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:
Diffstat (limited to 'release/scripts')
-rw-r--r--release/scripts/io/engine_render_pov.py63
-rw-r--r--release/scripts/io/export_3ds.py28
-rw-r--r--release/scripts/io/export_fbx.py210
-rw-r--r--release/scripts/io/export_mdd.py33
-rw-r--r--release/scripts/io/export_obj.py111
-rw-r--r--release/scripts/io/export_ply.py23
-rw-r--r--release/scripts/io/export_x3d.py53
-rw-r--r--release/scripts/io/import_anim_bvh.py67
-rw-r--r--release/scripts/io/import_scene_3ds.py42
-rw-r--r--release/scripts/io/import_scene_obj.py57
-rw-r--r--release/scripts/io/import_shape_mdd.py58
-rw-r--r--release/scripts/io/netrender/__init__.py1
-rw-r--r--release/scripts/io/netrender/client.py29
-rw-r--r--release/scripts/io/netrender/master.py74
-rw-r--r--release/scripts/io/netrender/master_html.py107
-rw-r--r--release/scripts/io/netrender/model.py14
-rw-r--r--release/scripts/io/netrender/netrender.css4
-rw-r--r--release/scripts/io/netrender/operators.py38
-rwxr-xr-xrelease/scripts/io/netrender/repath.py147
-rw-r--r--release/scripts/io/netrender/slave.py64
-rw-r--r--release/scripts/io/netrender/ui.py42
-rw-r--r--release/scripts/io/netrender/utils.py37
-rw-r--r--release/scripts/keyingsets/keyingsets_builtins.py225
-rw-r--r--release/scripts/keyingsets/keyingsets_utils.py163
-rw-r--r--release/scripts/modules/add_object_utils.py83
-rwxr-xr-xrelease/scripts/modules/blend_render_info.py100
-rw-r--r--release/scripts/modules/bpy/__init__.py11
-rw-r--r--release/scripts/modules/bpy/utils.py97
-rw-r--r--release/scripts/modules/bpy_types.py186
-rw-r--r--release/scripts/modules/console/complete_calltip.py2
-rw-r--r--release/scripts/modules/console/complete_import.py6
-rw-r--r--release/scripts/modules/graphviz_export.py31
-rw-r--r--release/scripts/modules/rigify/__init__.py27
-rw-r--r--release/scripts/modules/rigify/arm_biped.py8
-rw-r--r--release/scripts/modules/rigify/copy.py1
-rw-r--r--release/scripts/modules/rigify/eye_balls.py141
-rw-r--r--release/scripts/modules/rigify/eye_lid.py81
-rw-r--r--release/scripts/modules/rigify/finger_curl.py126
-rw-r--r--release/scripts/modules/rigify/leg_biped.py17
-rw-r--r--release/scripts/modules/rigify/leg_quadruped.py18
-rw-r--r--release/scripts/modules/rigify/mouth.py58
-rw-r--r--release/scripts/modules/rigify/neck.py344
-rw-r--r--release/scripts/modules/rigify/neck_flex.py17
-rw-r--r--release/scripts/modules/rigify/palm_curl.py6
-rw-r--r--release/scripts/modules/rigify/shape_key_control.py2
-rw-r--r--release/scripts/modules/rigify/shape_key_distance.py2
-rw-r--r--release/scripts/modules/rigify/shape_key_rotdiff.py2
-rw-r--r--release/scripts/modules/rigify/spine_pivot_flex.py20
-rw-r--r--release/scripts/modules/rigify/stretch.py16
-rw-r--r--release/scripts/modules/rigify/tail_control.py9
-rw-r--r--release/scripts/modules/rigify/tongue.py361
-rw-r--r--release/scripts/modules/rigify/track_dual.py12
-rw-r--r--release/scripts/modules/rigify/track_reverse.py1
-rw-r--r--release/scripts/modules/rigify_utils.py12
-rw-r--r--release/scripts/modules/rna_info.py200
-rw-r--r--release/scripts/modules/rna_prop_ui.py30
-rw-r--r--release/scripts/op/add_armature_human.py4
-rw-r--r--release/scripts/op/add_mesh_torus.py52
-rw-r--r--release/scripts/op/fcurve_euler_filter.py2
-rw-r--r--release/scripts/op/image.py172
-rw-r--r--release/scripts/op/mesh.py2
-rw-r--r--release/scripts/op/nla.py190
-rw-r--r--release/scripts/op/object.py81
-rw-r--r--release/scripts/op/object_align.py40
-rw-r--r--release/scripts/op/object_randomize_transform.py4
-rw-r--r--release/scripts/op/presets.py63
-rw-r--r--release/scripts/op/screen_play_rendered_anim.py62
-rw-r--r--release/scripts/op/sequencer.py90
-rw-r--r--release/scripts/op/uv.py31
-rw-r--r--release/scripts/op/uvcalc_follow_active.py8
-rw-r--r--release/scripts/op/uvcalc_smart_project.py29
-rw-r--r--release/scripts/op/vertexpaint_dirt.py21
-rw-r--r--release/scripts/op/wm.py207
-rw-r--r--release/scripts/presets/cloth/cotton.py1
-rw-r--r--release/scripts/presets/cloth/denim.py1
-rw-r--r--release/scripts/presets/cloth/leather.py1
-rw-r--r--release/scripts/presets/cloth/rubber.py1
-rw-r--r--release/scripts/presets/cloth/silk.py1
-rw-r--r--release/scripts/presets/ffmpeg/DV.py10
-rw-r--r--release/scripts/presets/ffmpeg/DVD.py19
-rw-r--r--release/scripts/presets/ffmpeg/SVCD.py19
-rw-r--r--release/scripts/presets/ffmpeg/VCD.py19
-rw-r--r--release/scripts/presets/ffmpeg/h264.py17
-rw-r--r--release/scripts/presets/ffmpeg/theora.py17
-rw-r--r--release/scripts/presets/ffmpeg/xvid.py17
-rw-r--r--release/scripts/presets/interaction/blender.py16
-rw-r--r--release/scripts/presets/interaction/maya.py386
-rw-r--r--release/scripts/presets/render/DVCPRO_HD_1080p.py8
-rw-r--r--release/scripts/presets/render/DVCPRO_HD_720p.py8
-rw-r--r--release/scripts/presets/render/HDTV_1080p.py1
-rw-r--r--release/scripts/presets/render/HDTV_720p.py1
-rw-r--r--release/scripts/presets/render/HDV_1080p.py8
-rw-r--r--release/scripts/presets/render/TV_NTSC_16_colon_9.py8
-rw-r--r--release/scripts/presets/render/TV_NTSC_4_colon_3.py (renamed from release/scripts/presets/render/TV_NTSC.py)3
-rw-r--r--release/scripts/presets/render/TV_PAL_16_colon_9.py5
-rw-r--r--release/scripts/presets/render/TV_PAL_4_colon_3.py (renamed from release/scripts/presets/render/TV_PAL.py)5
-rw-r--r--release/scripts/presets/sss/apple.py1
-rw-r--r--release/scripts/presets/sss/chicken.py1
-rw-r--r--release/scripts/presets/sss/cream.py1
-rw-r--r--release/scripts/presets/sss/ketchup.py1
-rw-r--r--release/scripts/presets/sss/marble.py1
-rw-r--r--release/scripts/presets/sss/potato.py1
-rw-r--r--release/scripts/presets/sss/skim_milk.py1
-rw-r--r--release/scripts/presets/sss/skin1.py1
-rw-r--r--release/scripts/presets/sss/skin2.py1
-rw-r--r--release/scripts/presets/sss/whole_milk.py1
-rw-r--r--release/scripts/presets/sunsky/classic.py1
-rw-r--r--release/scripts/presets/sunsky/desert.py1
-rw-r--r--release/scripts/presets/sunsky/mountain.py1
-rw-r--r--release/scripts/templates/gamelogic.py2
-rw-r--r--release/scripts/templates/operator.py11
-rw-r--r--release/scripts/templates/operator_modal.py1
-rw-r--r--release/scripts/templates/operator_modal_draw.py15
-rw-r--r--release/scripts/templates/operator_modal_view3d.py56
-rw-r--r--release/scripts/templates/operator_simple.py9
-rw-r--r--release/scripts/templates/operator_uv.py1
-rw-r--r--release/scripts/ui/properties_animviz.py23
-rw-r--r--release/scripts/ui/properties_data_armature.py37
-rw-r--r--release/scripts/ui/properties_data_armature_rigify.py54
-rw-r--r--release/scripts/ui/properties_data_bone.py5
-rw-r--r--release/scripts/ui/properties_data_camera.py9
-rw-r--r--release/scripts/ui/properties_data_curve.py47
-rw-r--r--release/scripts/ui/properties_data_empty.py2
-rw-r--r--release/scripts/ui/properties_data_lamp.py38
-rw-r--r--release/scripts/ui/properties_data_lattice.py6
-rw-r--r--release/scripts/ui/properties_data_mesh.py72
-rw-r--r--release/scripts/ui/properties_data_metaball.py2
-rw-r--r--release/scripts/ui/properties_data_modifier.py81
-rw-r--r--release/scripts/ui/properties_game.py26
-rw-r--r--release/scripts/ui/properties_material.py39
-rw-r--r--release/scripts/ui/properties_object.py43
-rw-r--r--release/scripts/ui/properties_object_constraint.py54
-rw-r--r--release/scripts/ui/properties_particle.py179
-rw-r--r--release/scripts/ui/properties_physics_cloth.py25
-rw-r--r--release/scripts/ui/properties_physics_common.py93
-rw-r--r--release/scripts/ui/properties_physics_field.py4
-rw-r--r--release/scripts/ui/properties_physics_fluid.py36
-rw-r--r--release/scripts/ui/properties_physics_smoke.py48
-rw-r--r--release/scripts/ui/properties_physics_softbody.py24
-rw-r--r--release/scripts/ui/properties_render.py119
-rw-r--r--release/scripts/ui/properties_scene.py34
-rw-r--r--release/scripts/ui/properties_texture.py229
-rw-r--r--release/scripts/ui/properties_world.py10
-rw-r--r--release/scripts/ui/space_buttons.py2
-rw-r--r--release/scripts/ui/space_dopesheet.py21
-rw-r--r--release/scripts/ui/space_graph.py15
-rw-r--r--release/scripts/ui/space_image.py105
-rw-r--r--release/scripts/ui/space_info.py192
-rw-r--r--release/scripts/ui/space_logic.py19
-rw-r--r--release/scripts/ui/space_nla.py2
-rw-r--r--release/scripts/ui/space_node.py18
-rw-r--r--release/scripts/ui/space_outliner.py18
-rw-r--r--release/scripts/ui/space_sequencer.py230
-rw-r--r--release/scripts/ui/space_text.py37
-rw-r--r--release/scripts/ui/space_time.py41
-rw-r--r--release/scripts/ui/space_userpref.py1425
-rw-r--r--release/scripts/ui/space_userpref_keymap.py812
-rw-r--r--release/scripts/ui/space_view3d.py240
-rw-r--r--release/scripts/ui/space_view3d_toolbar.py505
159 files changed, 7483 insertions, 2993 deletions
diff --git a/release/scripts/io/engine_render_pov.py b/release/scripts/io/engine_render_pov.py
index 338676968cd..9cda4375ecc 100644
--- a/release/scripts/io/engine_render_pov.py
+++ b/release/scripts/io/engine_render_pov.py
@@ -134,7 +134,7 @@ def write_pov(filename, scene=None, info_callback=None):
def exportCamera():
camera = scene.camera
- matrix = camera.matrix
+ matrix = camera.matrix_world
# compute resolution
Qsize = float(render.resolution_x) / float(render.resolution_y)
@@ -155,7 +155,7 @@ def write_pov(filename, scene=None, info_callback=None):
for ob in lamps:
lamp = ob.data
- matrix = ob.matrix
+ matrix = ob.matrix_world
color = tuple([c * lamp.energy for c in lamp.color]) # Colour is modified by energy
@@ -263,11 +263,11 @@ def write_pov(filename, scene=None, info_callback=None):
writeObjectMaterial(material)
- writeMatrix(ob.matrix)
+ writeMatrix(ob.matrix_world)
file.write('}\n')
- def exportMeshs(sel):
+ def exportMeshs(scene, sel):
ob_num = 0
@@ -280,7 +280,7 @@ def write_pov(filename, scene=None, info_callback=None):
me = ob.data
me_materials = me.materials
- me = ob.create_mesh(True, 'RENDER')
+ me = ob.create_mesh(scene, True, 'RENDER')
if not me:
continue
@@ -292,7 +292,7 @@ def write_pov(filename, scene=None, info_callback=None):
# continue
# me = ob.data
- matrix = ob.matrix
+ matrix = ob.matrix_world
try:
uv_layer = me.active_uv_texture.data
except:
@@ -545,7 +545,7 @@ def write_pov(filename, scene=None, info_callback=None):
mist = world.mist
- if mist.enabled:
+ if mist.use_mist:
file.write('fog {\n')
file.write('\tdistance %.6f\n' % mist.depth)
file.write('\tcolor rgbt<%.3g, %.3g, %.3g, %.3g>\n' % (tuple(world.horizon_color) + (1 - mist.intensity,)))
@@ -593,7 +593,7 @@ def write_pov(filename, scene=None, info_callback=None):
sel = scene.objects
exportLamps([l for l in sel if l.type == 'LAMP'])
exportMeta([l for l in sel if l.type == 'META'])
- exportMeshs(sel)
+ exportMeshs(scene, sel)
exportWorld(scene.world)
exportGlobalSettings(scene)
@@ -629,8 +629,8 @@ def write_pov_ini(filename_ini, filename_pov, filename_image):
file.write('Output_File_Type=T\n') # TGA, best progressive loading
file.write('Output_Alpha=1\n')
- if render.antialiasing:
- aa_mapping = {'OVERSAMPLE_5': 2, 'OVERSAMPLE_8': 3, 'OVERSAMPLE_11': 4, 'OVERSAMPLE_16': 5} # method 1 assumed
+ if render.render_antialiasing:
+ aa_mapping = {'5': 2, '8': 3, '11': 4, '16': 5} # method 1 assumed
file.write('Antialias=1\n')
file.write('Antialias_Depth=%d\n' % aa_mapping[render.antialiasing_samples])
else:
@@ -762,12 +762,22 @@ class PovrayRender(bpy.types.RenderEngine):
if 1:
# TODO, when povray isnt found this gives a cryptic error, would be nice to be able to detect if it exists
- self._process = subprocess.Popen([pov_binary, self._temp_file_ini]) # stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ try:
+ self._process = subprocess.Popen([pov_binary, self._temp_file_ini]) # stdout=subprocess.PIPE, stderr=subprocess.PIPE
+ except OSError:
+ # TODO, report api
+ print("POVRAY: could not execute '%s', possibly povray isn't installed" % pov_binary)
+ import traceback
+ traceback.print_exc()
+ print ("***-DONE-***")
+ return False
+
else:
# This works too but means we have to wait until its done
os.system('%s %s' % (pov_binary, self._temp_file_ini))
print ("***-DONE-***")
+ return True
def _cleanup(self):
for f in (self._temp_file_in, self._temp_file_ini, self._temp_file_out):
@@ -783,7 +793,10 @@ class PovrayRender(bpy.types.RenderEngine):
self.update_stats("", "POVRAY: Exporting data from Blender")
self._export(scene)
self.update_stats("", "POVRAY: Parsing File")
- self._render()
+
+ if not self._render():
+ self.update_stats("", "POVRAY: Not found")
+ return
r = scene.render
@@ -880,6 +893,30 @@ for member in dir(properties_material):
except:
pass
del properties_material
+import properties_data_mesh
+for member in dir(properties_data_mesh):
+ subclass = getattr(properties_data_mesh, member)
+ try:
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+ except:
+ pass
+del properties_data_mesh
+import properties_texture
+for member in dir(properties_texture):
+ subclass = getattr(properties_texture, member)
+ try:
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+ except:
+ pass
+del properties_texture
+import properties_data_camera
+for member in dir(properties_data_camera):
+ subclass = getattr(properties_data_camera, member)
+ try:
+ subclass.COMPAT_ENGINES.add('POVRAY_RENDER')
+ except:
+ pass
+del properties_data_camera
class RenderButtonsPanel(bpy.types.Panel):
@@ -954,6 +991,7 @@ def register():
for cls in classes:
register(cls)
+
def unregister():
unregister = bpy.types.unregister
for cls in classes:
@@ -961,4 +999,3 @@ def unregister():
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/io/export_3ds.py b/release/scripts/io/export_3ds.py
index b65332c931f..4fd889c75c6 100644
--- a/release/scripts/io/export_3ds.py
+++ b/release/scripts/io/export_3ds.py
@@ -74,15 +74,15 @@ import bpy
# also used by X3D exporter
# return a tuple (free, object list), free is True if memory should be freed later with free_derived_objects()
-def create_derived_objects(ob):
+def create_derived_objects(scene, ob):
if ob.parent and ob.parent.dupli_type != 'NONE':
return False, None
if ob.dupli_type != 'NONE':
- ob.create_dupli_list()
+ ob.create_dupli_list(scene)
return True, [(dob.object, dob.matrix) for dob in ob.dupli_list]
else:
- return False, [(ob, ob.matrix)]
+ return False, [(ob, ob.matrix_world)]
# also used by X3D exporter
def free_derived_objects(ob):
@@ -494,8 +494,7 @@ def make_material_texture_chunk(id, images):
mat_sub = _3ds_chunk(id)
def add_image(img):
- filename = os.path.basename(image.filename)
-# filename = image.filename.split('\\')[-1].split('/')[-1]
+ filename = os.path.basename(image.filepath)
mat_sub_file = _3ds_chunk(MATMAPFILE)
mat_sub_file.add_variable("mapfile", _3ds_string(sane_name(filename)))
mat_sub.add_subchunk(mat_sub_file)
@@ -942,6 +941,8 @@ def save_3ds(filename, context):
sce = context.scene
# sce= bpy.data.scenes.active
+ bpy.ops.object.mode_set(mode='OBJECT')
+
# Initialize the main chunk (primary):
primary = _3ds_chunk(PRIMARY)
# Add version chunk:
@@ -966,11 +967,12 @@ def save_3ds(filename, context):
# each material is added once):
materialDict = {}
mesh_objects = []
- for ob in [ob for ob in context.scene.objects if ob.is_visible()]:
+ scene = context.scene
+ for ob in [ob for ob in scene.objects if ob.is_visible(scene)]:
# for ob in sce.objects.context:
# get derived objects
- free, derived = create_derived_objects(ob)
+ free, derived = create_derived_objects(scene, ob)
if derived == None: continue
@@ -980,7 +982,7 @@ def save_3ds(filename, context):
if ob.type not in ('MESH', 'CURVE', 'SURFACE', 'TEXT', 'META'):
continue
- data = ob_derived.create_mesh(True, 'PREVIEW')
+ data = ob_derived.create_mesh(scene, True, 'PREVIEW')
# data = getMeshFromObject(ob_derived, None, True, False, sce)
if data:
data.transform(mat)
@@ -1120,12 +1122,11 @@ class Export3DS(bpy.types.Operator):
# to the class instance from the operator settings before calling.
- # filename = StringProperty(name="File Name", description="File name used for exporting the 3DS file", maxlen= 1024, default= ""),
- path = StringProperty(name="File Path", description="File path used for exporting the 3DS file", maxlen= 1024, default= "")
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the 3DS file", maxlen= 1024, default= "")
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
def execute(self, context):
- save_3ds(self.properties.path, context)
+ save_3ds(self.properties.filepath, context)
return {'FINISHED'}
def invoke(self, context, event):
@@ -1139,8 +1140,8 @@ class Export3DS(bpy.types.Operator):
# Add to a menu
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".3ds")
- self.layout.operator(Export3DS.bl_idname, text="3D Studio (.3ds)").path = default_path
+ default_path = os.path.splitext(bpy.data.filepath)[0] + ".3ds"
+ self.layout.operator(Export3DS.bl_idname, text="3D Studio (.3ds)").filepath = default_path
def register():
@@ -1153,4 +1154,3 @@ def unregister():
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/io/export_fbx.py b/release/scripts/io/export_fbx.py
index e1c7f68c557..4505b56b41c 100644
--- a/release/scripts/io/export_fbx.py
+++ b/release/scripts/io/export_fbx.py
@@ -54,50 +54,11 @@ import time
import math # math.pi
import shutil # for file copying
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-# import Blender
import bpy
-import Mathutils
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+from mathutils import Vector, Euler, Matrix, RotationMatrix
def copy_file(source, dest):
+ # XXX - remove, can use shutil
file = open(source, 'rb')
data = file.read()
file.close()
@@ -114,7 +75,7 @@ def copy_images(dest_dir, textures):
image_paths = set()
for tex in textures:
- image_paths.add(Blender.sys.expandpath(tex.filename))
+ image_paths.add(bpy.utils.expandpath(tex.filepath))
# Now copy images
copyCount = 0
@@ -135,7 +96,7 @@ def copy_images(dest_dir, textures):
# I guess FBX uses degrees instead of radians (Arystan).
# Call this function just before writing to FBX.
def eulerRadToDeg(eul):
- ret = Mathutils.Euler()
+ ret = Euler()
ret.x = 180 / math.pi * eul[0]
ret.y = 180 / math.pi * eul[1]
@@ -143,10 +104,10 @@ def eulerRadToDeg(eul):
return ret
-mtx4_identity = Mathutils.Matrix()
+mtx4_identity = Matrix()
# testing
-mtx_x90 = Mathutils.RotationMatrix( math.pi/2, 3, 'X') # used
+mtx_x90 = RotationMatrix( math.pi/2, 3, 'X') # used
#mtx_x90n = RotationMatrix(-90, 3, 'x')
#mtx_y90 = RotationMatrix( 90, 3, 'y')
#mtx_y90n = RotationMatrix(-90, 3, 'y')
@@ -154,11 +115,11 @@ mtx_x90 = Mathutils.RotationMatrix( math.pi/2, 3, 'X') # used
#mtx_z90n = RotationMatrix(-90, 3, 'z')
#mtx4_x90 = RotationMatrix( 90, 4, 'x')
-mtx4_x90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'X') # used
+mtx4_x90n = RotationMatrix(-math.pi/2, 4, 'X') # used
#mtx4_y90 = RotationMatrix( 90, 4, 'y')
-mtx4_y90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'Y') # used
-mtx4_z90 = Mathutils.RotationMatrix( math.pi/2, 4, 'Z') # used
-mtx4_z90n = Mathutils.RotationMatrix(-math.pi/2, 4, 'Z') # used
+mtx4_y90n = RotationMatrix(-math.pi/2, 4, 'Y') # used
+mtx4_z90 = RotationMatrix( math.pi/2, 4, 'Z') # used
+mtx4_z90n = RotationMatrix(-math.pi/2, 4, 'Z') # used
# def strip_path(p):
# return p.split('\\')[-1].split('/')[-1]
@@ -333,7 +294,7 @@ def write(filename, batch_objects = None, \
EXP_CAMERA = True,
EXP_EMPTY = True,
EXP_IMAGE_COPY = False,
- GLOBAL_MATRIX = Mathutils.Matrix(),
+ GLOBAL_MATRIX = Matrix(),
ANIM_ENABLE = True,
ANIM_OPTIMIZE = True,
ANIM_OPTIMIZE_PRECISSION = 6,
@@ -344,6 +305,8 @@ def write(filename, batch_objects = None, \
BATCH_OWN_DIR = False
):
+ bpy.ops.object.mode_set(mode='OBJECT')
+
# ----------------- Batch support!
if BATCH_ENABLE:
if os == None: BATCH_OWN_DIR = False
@@ -388,7 +351,6 @@ def write(filename, batch_objects = None, \
orig_sce = context.scene
# orig_sce = bpy.data.scenes.active
-
new_fbxpath = fbxpath # own dir option modifies, we need to keep an original
for data in data_seq: # scene or group
newname = BATCH_FILE_PREFIX + bpy.utils.clean_name(data.name)
@@ -545,10 +507,10 @@ def write(filename, batch_objects = None, \
#arm_mat = self.fbxArm.parRelMatrix()
if not self.parent:
#return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) # dont apply arm matrix anymore
- return mtx4_z90 * self.getPoseMatrix(frame)
+ return self.getPoseMatrix(frame) * mtx4_z90
else:
#return (mtx4_z90 * ((self.getPoseMatrix(frame) * arm_mat))) * (mtx4_z90 * (self.parent.getPoseMatrix(frame) * arm_mat)).invert()
- return (mtx4_z90 * (self.getPoseMatrix(frame))) * (mtx4_z90 * self.parent.getPoseMatrix(frame)).invert()
+ return (self.parent.getPoseMatrix(frame) * mtx4_z90).invert() * ((self.getPoseMatrix(frame)) * mtx4_z90)
# we need thes because cameras and lights modified rotations
def getAnimParRelMatrixRot(self, frame):
@@ -565,42 +527,41 @@ def write(filename, batch_objects = None, \
self.blenObject = ob
self.fbxGroupNames = []
self.fbxParent = None # set later on IF the parent is in the selection.
- if matrixWorld: self.matrixWorld = matrixWorld * GLOBAL_MATRIX
- else: self.matrixWorld = ob.matrix * GLOBAL_MATRIX
+ if matrixWorld: self.matrixWorld = GLOBAL_MATRIX * matrixWorld
+ else: self.matrixWorld = GLOBAL_MATRIX * ob.matrix_world
# else: self.matrixWorld = ob.matrixWorld * GLOBAL_MATRIX
self.__anim_poselist = {} # we should only access this
def parRelMatrix(self):
if self.fbxParent:
- return self.matrixWorld * self.fbxParent.matrixWorld.copy().invert()
+ return self.fbxParent.matrixWorld.copy().invert() * self.matrixWorld
else:
return self.matrixWorld
def setPoseFrame(self, f):
- self.__anim_poselist[f] = self.blenObject.matrix.copy()
-# self.__anim_poselist[f] = self.blenObject.matrixWorld.copy()
+ self.__anim_poselist[f] = self.blenObject.matrix_world.copy()
def getAnimParRelMatrix(self, frame):
if self.fbxParent:
#return (self.__anim_poselist[frame] * self.fbxParent.__anim_poselist[frame].copy().invert() ) * GLOBAL_MATRIX
- return (self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert()
+ return (GLOBAL_MATRIX * self.fbxParent.__anim_poselist[frame]).invert() * (GLOBAL_MATRIX * self.__anim_poselist[frame])
else:
- return self.__anim_poselist[frame] * GLOBAL_MATRIX
+ return GLOBAL_MATRIX * self.__anim_poselist[frame]
def getAnimParRelMatrixRot(self, frame):
type = self.blenObject.type
if self.fbxParent:
- matrix_rot = (((self.__anim_poselist[frame] * GLOBAL_MATRIX) * (self.fbxParent.__anim_poselist[frame] * GLOBAL_MATRIX).invert())).rotation_part()
+ matrix_rot = ((GLOBAL_MATRIX * self.fbxParent.__anim_poselist[frame]).invert() * (GLOBAL_MATRIX * self.__anim_poselist[frame])).rotation_part()
else:
- matrix_rot = (self.__anim_poselist[frame] * GLOBAL_MATRIX).rotation_part()
+ matrix_rot = (GLOBAL_MATRIX * self.__anim_poselist[frame]).rotation_part()
# Lamps need to be rotated
if type =='LAMP':
- matrix_rot = mtx_x90 * matrix_rot
+ matrix_rot = matrix_rot * mtx_x90
elif type =='CAMERA':
# elif ob and type =='Camera':
- y = Mathutils.Vector(0,1,0) * matrix_rot
- matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, y)
+ y = matrix_rot * Vector((0.0, 1.0, 0.0))
+ matrix_rot = RotationMatrix(math.pi/2, 3, y) * matrix_rot
return matrix_rot
@@ -651,7 +612,7 @@ def write(filename, batch_objects = None, \
}''' % (curtime))
file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime)
- file.write('\nCreator: "Blender3D version %s"' % bpy.app.version_string)
+ file.write('\nCreator: "Blender version %s"' % bpy.app.version_string)
pose_items = [] # list of (fbxName, matrix) to write pose data for, easier to collect allong the way
@@ -666,15 +627,15 @@ def write(filename, batch_objects = None, \
# we know we have a matrix
# matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod)
- matrix = mtx4_z90 * ob.matrix_local # dont apply armature matrix anymore
+ matrix = ob.matrix_local * mtx4_z90 # dont apply armature matrix anymore
# matrix = mtx4_z90 * ob.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
parent = ob.parent
if parent:
#par_matrix = mtx4_z90 * (parent.matrix['ARMATURESPACE'] * matrix_mod)
- par_matrix = mtx4_z90 * parent.matrix_local # dont apply armature matrix anymore
+ par_matrix = parent.matrix_local * mtx4_z90 # dont apply armature matrix anymore
# par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
- matrix = matrix * par_matrix.copy().invert()
+ matrix = par_matrix.copy().invert() * matrix
matrix_rot = matrix.rotation_part()
@@ -684,7 +645,7 @@ def write(filename, batch_objects = None, \
else:
# This is bad because we need the parent relative matrix from the fbx parent (if we have one), dont use anymore
- #if ob and not matrix: matrix = ob.matrixWorld * GLOBAL_MATRIX
+ #if ob and not matrix: matrix = ob.matrix_world * GLOBAL_MATRIX
if ob and not matrix: raise Exception("error: this should never happen!")
matrix_rot = matrix
@@ -698,11 +659,11 @@ def write(filename, batch_objects = None, \
matrix_rot = matrix.rotation_part()
# Lamps need to be rotated
if ob and ob.type =='Lamp':
- matrix_rot = mtx_x90 * matrix_rot
+ matrix_rot = matrix_rot * mtx_x90
rot = tuple(matrix_rot.to_euler())
elif ob and ob.type =='Camera':
- y = Mathutils.Vector(0,1,0) * matrix_rot
- matrix_rot = matrix_rot * Mathutils.RotationMatrix(math.pi/2, 3, y)
+ y = matrix_rot * Vector((0.0, 1.0, 0.0))
+ matrix_rot = RotationMatrix(math.pi/2, 3, y) * matrix_rot
rot = tuple(matrix_rot.to_euler())
else:
rot = tuple(matrix_rot.to_euler())
@@ -1087,8 +1048,8 @@ def write(filename, batch_objects = None, \
file.write('\n\t\tTypeFlags: "Camera"')
file.write('\n\t\tGeometryVersion: 124')
file.write('\n\t\tPosition: %.6f,%.6f,%.6f' % loc)
- file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(Mathutils.Vector(0,1,0) * matrix_rot) )
- file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(Mathutils.Vector(0,0,-1)*matrix_rot) )
+ file.write('\n\t\tUp: %.6f,%.6f,%.6f' % tuple(matrix_rot * Vector((0.0, 1.0, 0.0))))
+ file.write('\n\t\tLookAt: %.6f,%.6f,%.6f' % tuple(matrix_rot * Vector((0.0, 0.0, -1.0))))
#file.write('\n\t\tUp: 0,0,0' )
#file.write('\n\t\tLookAt: 0,0,0' )
@@ -1293,7 +1254,7 @@ def write(filename, batch_objects = None, \
file.write('\n\t}')
def copy_image(image):
- fn = bpy.utils.expandpath(image.filename)
+ fn = bpy.utils.expandpath(image.filepath)
fn_strip = os.path.basename(fn)
if EXP_IMAGE_COPY:
@@ -1320,7 +1281,7 @@ def write(filename, batch_objects = None, \
Property: "Height", "int", "",0''')
if tex:
fname_rel, fname_strip = copy_image(tex)
-# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
+# fname, fname_strip, fname_rel = derived_paths(tex.filepath, basepath, EXP_IMAGE_COPY)
else:
fname = fname_strip = fname_rel = ''
@@ -1385,7 +1346,7 @@ def write(filename, batch_objects = None, \
if tex:
fname_rel, fname_strip = copy_image(tex)
-# fname, fname_strip, fname_rel = derived_paths(tex.filename, basepath, EXP_IMAGE_COPY)
+# fname, fname_strip, fname_rel = derived_paths(tex.filepath, basepath, EXP_IMAGE_COPY)
else:
fname = fname_strip = fname_rel = ''
@@ -1485,10 +1446,10 @@ def write(filename, batch_objects = None, \
if my_mesh.fbxParent:
# TODO FIXME, this case is broken in some cases. skinned meshes just shouldnt have parents where possible!
- m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() )
+ m = (my_mesh.matrixWorld.copy().invert() * my_bone.fbxArm.matrixWorld.copy() * my_bone.restMatrix) * mtx4_z90
else:
# Yes! this is it... - but dosnt work when the mesh is a.
- m = mtx4_z90 * (my_bone.restMatrix * my_bone.fbxArm.matrixWorld.copy() * my_mesh.matrixWorld.copy().invert() )
+ m = (my_mesh.matrixWorld.copy().invert() * my_bone.fbxArm.matrixWorld.copy() * my_bone.restMatrix) * mtx4_z90
#m = mtx4_z90 * my_bone.restMatrix
matstr = mat4x4str(m)
@@ -1542,17 +1503,14 @@ def write(filename, batch_objects = None, \
file.write('\n\t\tPolygonVertexIndex: ')
i=-1
for f in me.faces:
- fi = f.verts
- # fi = [v_index for j, v_index in enumerate(f.verts) if v_index != 0 or j != 3]
-# fi = [v.index for v in f]
+ fi = f.verts[:]
- # flip the last index, odd but it looks like
- # this is how fbx tells one face from another
- fi[-1] = -(fi[-1]+1)
+ # last index XORd w. -1 indicates end of face
+ fi[-1] = fi[-1] ^ -1
fi = tuple(fi)
+
if i==-1:
if len(fi) == 3: file.write('%i,%i,%i' % fi )
-# if len(f) == 3: file.write('%i,%i,%i' % fi )
else: file.write('%i,%i,%i,%i' % fi )
i=0
else:
@@ -1560,10 +1518,26 @@ def write(filename, batch_objects = None, \
file.write('\n\t\t')
i=0
if len(fi) == 3: file.write(',%i,%i,%i' % fi )
-# if len(f) == 3: file.write(',%i,%i,%i' % fi )
else: file.write(',%i,%i,%i,%i' % fi )
i+=1
+ # write loose edges as faces.
+ for ed in me.edges:
+ if ed.loose:
+ ed_val = ed.verts[:]
+ ed_val = ed_val[0], ed_val[-1] ^ -1
+
+ if i==-1:
+ file.write('%i,%i' % ed_val)
+ i=0
+ else:
+ if i==13:
+ file.write('\n\t\t')
+ i=0
+ file.write(',%i,%i' % ed_val)
+ i+=1
+
+
file.write('\n\t\tEdges: ')
i=-1
for ed in me.edges:
@@ -2036,12 +2010,11 @@ def write(filename, batch_objects = None, \
if ob_arms_orig_rest:
for ob_base in bpy.data.objects:
- #if ob_base.type == 'Armature':
- ob_base.make_display_list()
-# ob_base.makeDisplayList()
+ if ob_base.type == 'ARMATURE':
+ ob_base.update(scene)
# This causes the makeDisplayList command to effect the mesh
- scene.set_frame(scene.current_frame)
+ scene.set_frame(scene.frame_current)
# Blender.Set('curframe', Blender.Get('curframe'))
@@ -2051,9 +2024,9 @@ def write(filename, batch_objects = None, \
if ob_base.parent and ob_base.parent.dupli_type != 'NONE':
continue
- obs = [(ob_base, ob_base.matrix)]
+ obs = [(ob_base, ob_base.matrix_world)]
if ob_base.dupli_type != 'NONE':
- ob_base.create_dupli_list()
+ ob_base.create_dupli_list(scene)
obs = [(dob.object, dob.matrix) for dob in ob_base.dupli_list]
for ob, mtx in obs:
@@ -2082,7 +2055,7 @@ def write(filename, batch_objects = None, \
if tmp_ob_type != 'MESH':
# if tmp_ob_type != 'Mesh':
# me = bpy.data.meshes.new()
- try: me = ob.create_mesh(True, 'PREVIEW')
+ try: me = ob.create_mesh(scene, True, 'PREVIEW')
# try: me.getFromObject(ob)
except: me = None
if me:
@@ -2093,7 +2066,7 @@ def write(filename, batch_objects = None, \
# Mesh Type!
if EXP_MESH_APPLY_MOD:
# me = bpy.data.meshes.new()
- me = ob.create_mesh(True, 'PREVIEW')
+ me = ob.create_mesh(scene, True, 'PREVIEW')
# me.getFromObject(ob)
# so we keep the vert groups
@@ -2212,11 +2185,9 @@ def write(filename, batch_objects = None, \
if ob_arms_orig_rest:
for ob_base in bpy.data.objects:
if ob_base.type == 'ARMATURE':
-# if ob_base.type == 'Armature':
- ob_base.make_display_list()
-# ob_base.makeDisplayList()
+ ob_base.update(scene)
# This causes the makeDisplayList command to effect the mesh
- scene.set_frame(scene.current_frame)
+ scene.set_frame(scene.frame_current)
# Blender.Set('curframe', Blender.Get('curframe'))
del tmp_ob_type, tmp_objects
@@ -2701,9 +2672,9 @@ Connections: {''')
return int(0.5 + ((t/fps) * 46186158000))
fps = float(render.fps)
- start = scene.start_frame
+ start = scene.frame_start
# start = render.sFrame
- end = scene.end_frame
+ end = scene.frame_end
# end = render.eFrame
if end < start: start, end = end, start
if start==end: ANIM_ENABLE = False
@@ -2713,7 +2684,7 @@ Connections: {''')
if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]:
- frame_orig = scene.current_frame
+ frame_orig = scene.frame_current
# frame_orig = Blender.Get('curframe')
if ANIM_OPTIMIZE:
@@ -2812,7 +2783,7 @@ Takes: {''')
# Set the action active
for my_bone in ob_arms:
if blenAction in my_bone.blenActionList:
- ob.action = blenAction
+ ob.animation_data.action = blenAction
# print '\t\tSetting Action!', blenAction
# scene.update(1)
@@ -2969,7 +2940,7 @@ Takes: {''')
# end action loop. set original actions
# do this after every loop incase actions effect eachother.
for my_bone in ob_arms:
- my_bone.blenObject.action = my_bone.blenAction
+ my_bone.blenObject.animation_data.action = my_bone.blenAction
file.write('\n}')
@@ -2998,8 +2969,7 @@ Takes: {''')
# --------------------------- Footer
if world:
m = world.mist
- has_mist = m.enabled
-# has_mist = world.mode & 1
+ has_mist = m.use_mist
mist_intense = m.intensity
mist_start = m.start
mist_end = m.depth
@@ -3150,9 +3120,9 @@ def fbx_ui_write(filename, context):
# Make the matrix
GLOBAL_MATRIX = mtx4_identity
GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = GLOBALS['_SCALE'].val
- if GLOBALS['_XROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n
- if GLOBALS['_YROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n
- if GLOBALS['_ZROT90'].val: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n
+ if GLOBALS['_XROT90'].val: GLOBAL_MATRIX = mtx4_x90n * GLOBAL_MATRIX
+ if GLOBALS['_YROT90'].val: GLOBAL_MATRIX = mtx4_y90n * GLOBAL_MATRIX
+ if GLOBALS['_ZROT90'].val: GLOBAL_MATRIX = mtx4_z90n * GLOBAL_MATRIX
ret = write(\
filename, None,\
@@ -3364,7 +3334,7 @@ class ExportFBX(bpy.types.Operator):
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for exporting the FBX file", maxlen= 1024, default="")
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the FBX file", maxlen= 1024, default="")
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
EXP_OBS_SELECTED = BoolProperty(name="Selected Objects", description="Export selected objects on visible layers", default=True)
@@ -3398,16 +3368,16 @@ class ExportFBX(bpy.types.Operator):
return context.active_object
def execute(self, context):
- if not self.properties.path:
- raise Exception("path not set")
+ if not self.properties.filepath:
+ raise Exception("filepath not set")
GLOBAL_MATRIX = mtx4_identity
GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self.properties.TX_SCALE
- if self.properties.TX_XROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_x90n
- if self.properties.TX_YROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_y90n
- if self.properties.TX_ZROT90: GLOBAL_MATRIX = GLOBAL_MATRIX * mtx4_z90n
+ if self.properties.TX_XROT90: GLOBAL_MATRIX = mtx4_x90n * GLOBAL_MATRIX
+ if self.properties.TX_YROT90: GLOBAL_MATRIX = mtx4_y90n * GLOBAL_MATRIX
+ if self.properties.TX_ZROT90: GLOBAL_MATRIX = mtx4_z90n * GLOBAL_MATRIX
- write(self.properties.path,
+ write(self.properties.filepath,
None, # XXX
context,
self.properties.EXP_OBS_SELECTED,
@@ -3440,7 +3410,7 @@ class ExportFBX(bpy.types.Operator):
# if __name__ == "__main__":
-# bpy.ops.EXPORT_OT_ply(filename="/tmp/test.ply")
+# bpy.ops.EXPORT_OT_ply(filepath="/tmp/test.ply")
# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts)
@@ -3467,8 +3437,8 @@ class ExportFBX(bpy.types.Operator):
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".fbx")
- self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX (.fbx)").path = default_path
+ default_path = os.path.splitext(bpy.data.filepath)[0] + ".fbx"
+ self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX (.fbx)").filepath = default_path
def register():
diff --git a/release/scripts/io/export_mdd.py b/release/scripts/io/export_mdd.py
index a4dca4db204..d2e53070910 100644
--- a/release/scripts/io/export_mdd.py
+++ b/release/scripts/io/export_mdd.py
@@ -48,7 +48,7 @@ Be sure not to use modifiers that change the number or order of verts in the mes
# ***** END GPL LICENCE BLOCK *****
import bpy
-import Mathutils
+import mathutils
from struct import pack
@@ -82,12 +82,12 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
bpy.ops.object.mode_set(mode='OBJECT')
- orig_frame = sce.current_frame
+ orig_frame = sce.frame_current
sce.set_frame(PREF_STARTFRAME)
- me = ob.create_mesh(True, 'PREVIEW')
+ me = ob.create_mesh(sce, True, 'PREVIEW')
#Flip y and z
- mat_flip = Mathutils.Matrix(\
+ mat_flip = mathutils.Matrix(\
[1.0, 0.0, 0.0, 0.0],\
[0.0, 0.0, 1.0, 0.0],\
[0.0, 1.0, 0.0, 0.0],\
@@ -113,7 +113,7 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
"""
check_vertcount(me, numverts)
- me.transform(mat_flip * ob.matrix)
+ me.transform(mat_flip * ob.matrix_world)
f.write(pack(">%df" % (numverts * 3), *[axis for v in me.verts for axis in v.co]))
for frame in range(PREF_STARTFRAME, PREF_ENDFRAME + 1):#in order to start at desired frame
@@ -123,9 +123,9 @@ def write(filename, sce, ob, PREF_STARTFRAME, PREF_ENDFRAME, PREF_FPS):
"""
sce.set_frame(frame)
- me = ob.create_mesh(True, 'PREVIEW')
+ me = ob.create_mesh(sce, True, 'PREVIEW')
check_vertcount(me, numverts)
- me.transform(mat_flip * ob.matrix)
+ me.transform(mat_flip * ob.matrix_world)
# Write the vertex data
f.write(pack(">%df" % (numverts * 3), *[axis for v in me.verts for axis in v.co]))
@@ -159,21 +159,21 @@ class ExportMDD(bpy.types.Operator):
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for exporting the MDD file", maxlen=1024)
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the MDD file", maxlen=1024)
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
- start_frame = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe, max=maxframe, default=1)
- end_frame = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default=250)
+ frame_start = IntProperty(name="Start Frame", description="Start frame for baking", min=minframe, max=maxframe, default=1)
+ frame_end = IntProperty(name="End Frame", description="End frame for baking", min=minframe, max=maxframe, default=250)
def poll(self, context):
ob = context.active_object
return (ob and ob.type == 'MESH')
def execute(self, context):
- if not self.properties.path:
+ if not self.properties.filepath:
raise Exception("filename not set")
- write(self.properties.path, context.scene, context.active_object,
- self.properties.start_frame, self.properties.end_frame, self.properties.fps)
+ write(self.properties.filepath, context.scene, context.active_object,
+ self.properties.frame_start, self.properties.frame_end, self.properties.fps)
return {'FINISHED'}
def invoke(self, context, event):
@@ -183,18 +183,19 @@ class ExportMDD(bpy.types.Operator):
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".mdd")
- self.layout.operator(ExportMDD.bl_idname, text="Lightwave Point Cache (.mdd)").path = default_path
+ import os
+ default_path = os.path.splitext(bpy.data.filepath)[0] + ".mdd"
+ self.layout.operator(ExportMDD.bl_idname, text="Lightwave Point Cache (.mdd)").filepath = default_path
def register():
bpy.types.register(ExportMDD)
bpy.types.INFO_MT_file_export.append(menu_func)
+
def unregister():
bpy.types.unregister(ExportMDD)
bpy.types.INFO_MT_file_export.remove(menu_func)
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/io/export_obj.py b/release/scripts/io/export_obj.py
index 046ae9ecf99..626b92c3591 100644
--- a/release/scripts/io/export_obj.py
+++ b/release/scripts/io/export_obj.py
@@ -47,7 +47,7 @@ import time
import shutil
import bpy
-import Mathutils
+import mathutils
# Returns a tuple - path,extension.
@@ -65,19 +65,15 @@ def fixName(name):
else:
return name.replace(' ', '_')
-# A Dict of Materials
-# (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
-MTL_DICT = {}
-
-def write_mtl(scene, filename, copy_images):
+def write_mtl(scene, filepath, copy_images, mtl_dict):
world = scene.world
worldAmb = world.ambient_color
- dest_dir = os.path.dirname(filename)
+ dest_dir = os.path.dirname(filepath)
def copy_image(image):
- fn = bpy.utils.expandpath(image.filename)
+ fn = bpy.utils.expandpath(image.filepath)
fn_strip = os.path.basename(fn)
if copy_images:
rel = fn_strip
@@ -90,12 +86,12 @@ def write_mtl(scene, filename, copy_images):
return rel
- file = open(filename, "w")
+ file = open(filepath, "w")
# XXX
-# file.write('# Blender3D MTL File: %s\n' % Blender.Get('filename').split('\\')[-1].split('/')[-1])
- file.write('# Material Count: %i\n' % len(MTL_DICT))
+# file.write('# Blender MTL File: %s\n' % Blender.Get('filepath').split('\\')[-1].split('/')[-1])
+ file.write('# Material Count: %i\n' % len(mtl_dict))
# Write material/image combinations we have used.
- for key, (mtl_mat_name, mat, img) in MTL_DICT.items():
+ for key, (mtl_mat_name, mat, img) in mtl_dict.items():
# Get the Blender data for the material and the image.
# Having an image named None will make a bug, dont do it :)
@@ -135,15 +131,15 @@ def write_mtl(scene, filename, copy_images):
# write relative image path
rel = copy_image(img)
file.write('map_Kd %s\n' % rel) # Diffuse mapping image
-# file.write('map_Kd %s\n' % img.filename.split('\\')[-1].split('/')[-1]) # Diffuse mapping image
+# file.write('map_Kd %s\n' % img.filepath.split('\\')[-1].split('/')[-1]) # Diffuse mapping image
elif mat: # No face image. if we havea material search for MTex image.
for mtex in mat.texture_slots:
if mtex and mtex.texture.type == 'IMAGE':
try:
- filename = copy_image(mtex.texture.image)
-# filename = mtex.texture.image.filename.split('\\')[-1].split('/')[-1]
- file.write('map_Kd %s\n' % filename) # Diffuse mapping image
+ filepath = copy_image(mtex.texture.image)
+# filepath = mtex.texture.image.filepath.split('\\')[-1].split('/')[-1]
+ file.write('map_Kd %s\n' % filepath) # Diffuse mapping image
break
except:
# Texture has no image though its an image type, best ignore.
@@ -173,7 +169,7 @@ def copy_images(dest_dir):
# Get unique image names
uniqueImages = {}
- for matname, mat, image in MTL_DICT.values(): # Only use image name
+ for matname, mat, image in mtl_dict.values(): # Only use image name
# Get Texface images
if image:
uniqueImages[image] = image # Should use sets here. wait until Python 2.4 is default.
@@ -193,7 +189,7 @@ def copy_images(dest_dir):
copyCount = 0
# for bImage in uniqueImages.values():
-# image_path = bpy.utils.expandpath(bImage.filename)
+# image_path = bpy.utils.expandpath(bImage.filepath)
# if bpy.sys.exists(image_path):
# # Make a name for the target path.
# dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
@@ -225,7 +221,7 @@ def write_nurb(file, ob, ob_mat):
cu = ob.data
# use negative indices
- Vector = Blender.Mathutils.Vector
+ Vector = Blender.mathutils.Vector
for nu in cu:
if nu.type==0: DEG_ORDER_U = 1
@@ -286,7 +282,7 @@ def write_nurb(file, ob, ob_mat):
return tot_verts
-def write(filename, objects, scene,
+def write(filepath, objects, scene,
EXPORT_TRI=False,
EXPORT_EDGES=False,
EXPORT_NORMALS=False,
@@ -355,26 +351,26 @@ def write(filename, objects, scene,
return ret
- print('OBJ Export path: "%s"' % filename)
+ print('OBJ Export path: "%s"' % filepath)
temp_mesh_name = '~tmp-mesh'
time1 = time.clock()
# time1 = sys.time()
# scn = Scene.GetCurrent()
- file = open(filename, "w")
+ file = open(filepath, "w")
# Write Header
- file.write('# Blender3D v%s OBJ File: %s\n' % (bpy.app.version_string, bpy.data.filename.split('/')[-1].split('\\')[-1] ))
- file.write('# www.blender3d.org\n')
+ file.write('# Blender v%s OBJ File: %s\n' % (bpy.app.version_string, bpy.data.filepath.split('/')[-1].split('\\')[-1] ))
+ file.write('# www.blender.org\n')
# Tell the obj file what material file to use.
if EXPORT_MTL:
- mtlfilename = '%s.mtl' % '.'.join(filename.split('.')[:-1])
- file.write('mtllib %s\n' % ( mtlfilename.split('\\')[-1].split('/')[-1] ))
+ mtlfilepath = '%s.mtl' % '.'.join(filepath.split('.')[:-1])
+ file.write('mtllib %s\n' % ( mtlfilepath.split('\\')[-1].split('/')[-1] ))
if EXPORT_ROTX90:
- mat_xrot90= Mathutils.RotationMatrix(-math.pi/2, 4, 'X')
+ mat_xrot90= mathutils.RotationMatrix(-math.pi/2, 4, 'X')
# Initialize totals, these are updated each object
totverts = totuvco = totno = 1
@@ -383,6 +379,10 @@ def write(filename, objects, scene,
globalNormals = {}
+ # A Dict of Materials
+ # (material.name, image.name):matname_imagename # matname_imagename has gaps removed.
+ mtl_dict = {}
+
# Get all meshes
for ob_main in objects:
@@ -396,14 +396,14 @@ def write(filename, objects, scene,
if ob_main.dupli_type != 'NONE':
# XXX
print('creating dupli_list on', ob_main.name)
- ob_main.create_dupli_list()
+ ob_main.create_dupli_list(scene)
obs = [(dob.object, dob.matrix) for dob in ob_main.dupli_list]
# XXX debug print
print(ob_main.name, 'has', len(obs), 'dupli children')
else:
- obs = [(ob_main, ob_main.matrix)]
+ obs = [(ob_main, ob_main.matrix_world)]
for ob, ob_mat in obs:
@@ -421,7 +421,7 @@ def write(filename, objects, scene,
if ob.type != 'MESH':
continue
- me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW')
+ me = ob.create_mesh(scene, EXPORT_APPLY_MODIFIERS, 'PREVIEW')
if EXPORT_ROTX90:
me.transform(mat_xrot90 * ob_mat)
@@ -691,7 +691,7 @@ def write(filename, objects, scene,
file.write('usemtl (null)\n') # mat, image
else:
- mat_data= MTL_DICT.get(key)
+ mat_data= mtl_dict.get(key)
if not mat_data:
# First add to global dict so we can export to mtl
# Then write mtl
@@ -701,9 +701,9 @@ def write(filename, objects, scene,
# If none image dont bother adding it to the name
if key[1] == None:
- mat_data = MTL_DICT[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image
+ mat_data = mtl_dict[key] = ('%s'%fixName(key[0])), materialItems[f_mat], f_image
else:
- mat_data = MTL_DICT[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image
+ mat_data = mtl_dict[key] = ('%s_%s' % (fixName(key[0]), fixName(key[1]))), materialItems[f_mat], f_image
if EXPORT_GROUP_BY_MAT:
file.write('g %s_%s_%s\n' % (fixName(ob.name), fixName(ob.data.name), mat_data[0]) ) # can be mat_image or (null)
@@ -782,22 +782,22 @@ def write(filename, objects, scene,
# Now we have all our materials, save them
if EXPORT_MTL:
- write_mtl(scene, mtlfilename, EXPORT_COPY_IMAGES)
+ write_mtl(scene, mtlfilepath, EXPORT_COPY_IMAGES, mtl_dict)
# if EXPORT_COPY_IMAGES:
-# dest_dir = os.path.basename(filename)
-# # dest_dir = filename
+# dest_dir = os.path.basename(filepath)
+# # dest_dir = filepath
# # # Remove chars until we are just the path.
# # while dest_dir and dest_dir[-1] not in '\\/':
# # dest_dir = dest_dir[:-1]
# if dest_dir:
-# copy_images(dest_dir)
+# copy_images(dest_dir, mtl_dict)
# else:
-# print('\tError: "%s" could not be used as a base for an image path.' % filename)
+# print('\tError: "%s" could not be used as a base for an image path.' % filepath)
print("OBJ Export time: %.2f" % (time.clock() - time1))
# print "OBJ Export time: %.2f" % (sys.time() - time1)
-def do_export(filename, context,
+def do_export(filepath, context,
EXPORT_APPLY_MODIFIERS = True, # not used
EXPORT_ROTX90 = True, # wrong
EXPORT_TRI = False, # ok
@@ -816,14 +816,15 @@ def do_export(filename, context,
EXPORT_KEEP_VERT_ORDER = False,
EXPORT_POLYGROUPS = False,
EXPORT_CURVE_AS_NURBS = True):
- # Window.EditMode(0)
- # Window.WaitCursor(1)
-
- base_name, ext = splitExt(filename)
+
+ base_name, ext = splitExt(filepath)
context_name = [base_name, '', '', ext] # Base name, scene name, frame number, extension
orig_scene = context.scene
+ # Exit edit mode before exporting, so current object states are exported properly.
+ bpy.ops.object.mode_set(mode='OBJECT')
+
# if EXPORT_ALL_SCENES:
# export_scenes = bpy.data.scenes
# else:
@@ -839,23 +840,23 @@ def do_export(filename, context,
for scn in export_scenes:
# scn.makeCurrent() # If already current, this is not slow.
# context = scn.getRenderingContext()
- orig_frame = scn.current_frame
+ orig_frame = scn.frame_current
if EXPORT_ALL_SCENES: # Add scene name into the context_name
context_name[1] = '_%s' % bpy.utils.clean_name(scn.name) # WARNING, its possible that this could cause a collision. we could fix if were feeling parranoied.
# Export an animation?
if EXPORT_ANIMATION:
- scene_frames = range(scn.start_frame, context.end_frame+1) # Up to and including the end frame.
+ scene_frames = range(scn.frame_start, context.frame_end + 1) # Up to and including the end frame.
else:
scene_frames = [orig_frame] # Dont export an animation.
# Loop through all frames in the scene and export.
for frame in scene_frames:
- if EXPORT_ANIMATION: # Add frame to the filename.
+ if EXPORT_ANIMATION: # Add frame to the filepath.
context_name[2] = '_%.6d' % frame
- scn.current_frame = frame
+ scn.frame_current = frame
if EXPORT_SEL_ONLY:
export_objects = context.selected_objects
else:
@@ -874,7 +875,7 @@ def do_export(filename, context,
EXPORT_POLYGROUPS, EXPORT_CURVE_AS_NURBS)
- scn.current_frame = orig_frame
+ scn.frame_current = orig_frame
# Restore old active scene.
# orig_scene.makeCurrent()
@@ -899,7 +900,7 @@ class ExportOBJ(bpy.types.Operator):
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for exporting the OBJ file", maxlen= 1024, default= "")
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the OBJ file", maxlen= 1024, default= "")
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
# context group
@@ -931,11 +932,11 @@ class ExportOBJ(bpy.types.Operator):
def execute(self, context):
- path = self.properties.path
- if not path.lower().endswith(".obj"):
- path += ".obj"
+ filepath = self.properties.filepath
+ if not filepath.lower().endswith(".obj"):
+ filepath += ".obj"
- do_export(path, context,
+ do_export(filepath, context,
EXPORT_TRI=self.properties.use_triangles,
EXPORT_EDGES=self.properties.use_edges,
EXPORT_NORMALS=self.properties.use_normals,
@@ -963,8 +964,8 @@ class ExportOBJ(bpy.types.Operator):
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".obj")
- self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)").path = default_path
+ default_path = os.path.splitext(bpy.data.filepath)[0] + ".obj"
+ self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)").filepath = default_path
def register():
diff --git a/release/scripts/io/export_ply.py b/release/scripts/io/export_ply.py
index 92d4f2ff914..0b936bdceb2 100644
--- a/release/scripts/io/export_ply.py
+++ b/release/scripts/io/export_ply.py
@@ -99,10 +99,11 @@ def write(filename, scene, ob, \
Window.WaitCursor(1)
"""
+ bpy.ops.object.mode_set(mode='OBJECT')
#mesh = BPyMesh.getMeshFromObject(ob, None, EXPORT_APPLY_MODIFIERS, False, scn) # XXX
if EXPORT_APPLY_MODIFIERS:
- mesh = ob.create_mesh(True, 'PREVIEW')
+ mesh = ob.create_mesh(scene, True, 'PREVIEW')
else:
mesh = ob.data
@@ -110,7 +111,7 @@ def write(filename, scene, ob, \
raise ("Error, could not get mesh data from active object")
return
- # mesh.transform(ob.matrixWorld) # XXX
+ # mesh.transform(ob.matrix_world) # XXX
faceUV = (len(mesh.uv_textures) > 0)
vertexUV = (len(mesh.sticky) > 0)
@@ -202,7 +203,7 @@ def write(filename, scene, ob, \
file.write('ply\n')
file.write('format ascii 1.0\n')
- file.write('comment Created by Blender3D %s - www.blender.org, source file: %s\n' % (bpy.app.version_string, bpy.data.filename.split('/')[-1].split('\\')[-1]))
+ file.write('comment Created by Blender %s - www.blender.org, source file: %s\n' % (bpy.app.version_string, bpy.data.filepath.split('/')[-1].split('\\')[-1]))
file.write('element vertex %d\n' % len(ply_verts))
@@ -210,13 +211,10 @@ def write(filename, scene, ob, \
file.write('property float y\n')
file.write('property float z\n')
- # XXX
- """
if EXPORT_NORMALS:
file.write('property float nx\n')
file.write('property float ny\n')
file.write('property float nz\n')
- """
if EXPORT_UV:
file.write('property float s\n')
file.write('property float t\n')
@@ -231,10 +229,8 @@ def write(filename, scene, ob, \
for i, v in enumerate(ply_verts):
file.write('%.6f %.6f %.6f ' % tuple(mesh_verts[v[0]].co)) # co
- """
if EXPORT_NORMALS:
file.write('%.6f %.6f %.6f ' % v[1]) # no
- """
if EXPORT_UV:
file.write('%.6f %.6f ' % v[2]) # uv
if EXPORT_COLORS:
@@ -271,7 +267,7 @@ class ExportPLY(bpy.types.Operator):
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for exporting the PLY file", maxlen=1024, default="")
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the PLY file", maxlen=1024, default="")
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply Modifiers to the exported mesh", default=True)
use_normals = BoolProperty(name="Normals", description="Export Normals for smooth and hard shaded faces", default=True)
@@ -284,10 +280,10 @@ class ExportPLY(bpy.types.Operator):
def execute(self, context):
# print("Selected: " + context.active_object.name)
- if not self.properties.path:
+ if not self.properties.filepath:
raise Exception("filename not set")
- write(self.properties.path, context.scene, context.active_object,\
+ write(self.properties.filepath, context.scene, context.active_object,\
EXPORT_APPLY_MODIFIERS=self.properties.use_modifiers,
EXPORT_NORMALS=self.properties.use_normals,
EXPORT_UV=self.properties.use_uvs,
@@ -314,8 +310,9 @@ class ExportPLY(bpy.types.Operator):
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".ply")
- self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)").path = default_path
+ import os
+ default_path = os.path.splitext(bpy.data.filepath)[0] + ".ply"
+ self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)").filepath = default_path
def register():
diff --git a/release/scripts/io/export_x3d.py b/release/scripts/io/export_x3d.py
index f1ab8cd3de7..1bad80f6d8e 100644
--- a/release/scripts/io/export_x3d.py
+++ b/release/scripts/io/export_x3d.py
@@ -69,7 +69,7 @@ import math
import os
import bpy
-import Mathutils
+import mathutils
from export_3ds import create_derived_objects, free_derived_objects
@@ -81,7 +81,7 @@ from export_3ds import create_derived_objects, free_derived_objects
#
DEG2RAD=0.017453292519943295
-MATWORLD= Mathutils.RotationMatrix(-90, 4, 'X')
+MATWORLD= mathutils.RotationMatrix(-90, 4, 'X')
####################################
# Global Variables
@@ -237,7 +237,7 @@ class x3d_class:
lens = min(lens, math.pi)
# get the camera location, subtract 90 degress from X to orient like X3D does
- # mat = ob.matrixWorld - mat is now passed!
+ # mat = ob.matrix_world - mat is now passed!
loc = self.rotatePointForVRML(mat.translation_part())
rot = mat.to_euler()
@@ -300,7 +300,7 @@ class x3d_class:
# note -dz seems to equal om[3][1]
# note dy seems to equal om[3][2]
- #location=(ob.matrixWorld*MATWORLD).translation_part() # now passed
+ #location=(ob.matrix_world*MATWORLD).translation_part() # now passed
location=(mtx*MATWORLD).translation_part()
radius = lamp.distance*math.cos(beamWidth)
@@ -346,7 +346,7 @@ class x3d_class:
ambi = 0
ambientIntensity = 0
- # location=(ob.matrixWorld*MATWORLD).translation_part() # now passed
+ # location=(ob.matrix_world*MATWORLD).translation_part() # now passed
location= (mtx*MATWORLD).translation_part()
self.file.write("<PointLight DEF=\"%s\" " % safeName)
@@ -364,7 +364,7 @@ class x3d_class:
return
else:
dx,dy,dz = self.computeDirection(mtx)
- # location=(ob.matrixWorld*MATWORLD).translation_part()
+ # location=(ob.matrix_world*MATWORLD).translation_part()
location=(mtx*MATWORLD).translation_part()
self.writeIndented("<%s\n" % obname,1)
self.writeIndented("direction=\"%s %s %s\"\n" % (round(dx,3),round(dy,3),round(dz,3)))
@@ -445,7 +445,7 @@ class x3d_class:
else:
bTwoSided=0
- # mtx = ob.matrixWorld * MATWORLD # mtx is now passed
+ # mtx = ob.matrix_world * MATWORLD # mtx is now passed
mtx = mtx * MATWORLD
loc= mtx.translation_part()
@@ -601,7 +601,7 @@ class x3d_class:
self.file.write("\">\n")
else:
#-- vertices
- # mesh.transform(ob.matrixWorld)
+ # mesh.transform(ob.matrix_world)
self.writeIndented("<Coordinate DEF=\"%s%s\" \n" % ("coord_",meshName), 1)
self.file.write("\t\t\t\tpoint=\"")
for v in mesh.verts:
@@ -717,7 +717,7 @@ class x3d_class:
def writeImageTexture(self, image):
name = image.name
- filename = image.filename.split('/')[-1].split('\\')[-1]
+ filename = image.filepath.split('/')[-1].split('\\')[-1]
if name in self.texNames:
self.writeIndented("<ImageTexture USE=\"%s\" />\n" % self.cleanStr(name))
self.texNames[name] += 1
@@ -794,28 +794,28 @@ class x3d_class:
pic = tex.image
# using .expandpath just in case, os.path may not expect //
- basename = os.path.basename(bpy.utils.expandpath(pic.filename))
+ basename = os.path.basename(bpy.utils.expandpath(pic.filepath))
pic = alltextures[i].image
# pic = alltextures[i].getImage()
if (namemat == "back") and (pic != None):
self.file.write("\n\tbackUrl=\"%s\" " % basename)
- # self.file.write("\n\tbackUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.file.write("\n\tbackUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
elif (namemat == "bottom") and (pic != None):
self.writeIndented("bottomUrl=\"%s\" " % basename)
- # self.writeIndented("bottomUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.writeIndented("bottomUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
elif (namemat == "front") and (pic != None):
self.writeIndented("frontUrl=\"%s\" " % basename)
- # self.writeIndented("frontUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.writeIndented("frontUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
elif (namemat == "left") and (pic != None):
self.writeIndented("leftUrl=\"%s\" " % basename)
- # self.writeIndented("leftUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.writeIndented("leftUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
elif (namemat == "right") and (pic != None):
self.writeIndented("rightUrl=\"%s\" " % basename)
- # self.writeIndented("rightUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.writeIndented("rightUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
elif (namemat == "top") and (pic != None):
self.writeIndented("topUrl=\"%s\" " % basename)
- # self.writeIndented("topUrl=\"%s\" " % pic.filename.split('/')[-1].split('\\')[-1])
+ # self.writeIndented("topUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
self.writeIndented("/>\n\n")
##########################################################
@@ -852,10 +852,10 @@ class x3d_class:
# --------------------------
- for ob_main in [o for o in scene.objects if o.is_visible()]:
+ for ob_main in [o for o in scene.objects if o.is_visible(scene)]:
# for ob_main in scene.objects.context:
- free, derived = create_derived_objects(ob_main)
+ free, derived = create_derived_objects(scene, ob_main)
if derived == None: continue
@@ -871,7 +871,7 @@ class x3d_class:
# elif objType in ("Mesh", "Curve", "Surf", "Text") :
if EXPORT_APPLY_MODIFIERS or objType != 'MESH':
# if EXPORT_APPLY_MODIFIERS or objType != 'Mesh':
- me = ob.create_mesh(EXPORT_APPLY_MODIFIERS, 'PREVIEW')
+ me = ob.create_mesh(scene, EXPORT_APPLY_MODIFIERS, 'PREVIEW')
# me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene)
else:
me = ob.data
@@ -1155,8 +1155,9 @@ def x3d_export(filename,
scene = context.scene
- # scene = Blender.Scene.GetCurrent()
world = scene.world
+
+ bpy.ops.object.mode_set(mode='OBJECT')
# XXX these are global textures while .Get() returned only scene's?
alltextures = bpy.data.textures
@@ -1214,9 +1215,6 @@ def x3d_export_ui(filename):
#########################################################
-# if __name__ == '__main__':
-# Blender.Window.FileSelector(x3d_export_ui,"Export X3D", Blender.Get('filename').replace('.blend', '.x3d'))
-
from bpy.props import *
class ExportX3D(bpy.types.Operator):
@@ -1226,7 +1224,7 @@ class ExportX3D(bpy.types.Operator):
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for exporting the X3D file", maxlen= 1024, default= "")
+ filepath = StringProperty(name="File Path", description="Filepath used for exporting the X3D file", maxlen= 1024, default= "")
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
apply_modifiers = BoolProperty(name="Apply Modifiers", description="Use transformed mesh data from each object", default=True)
@@ -1234,7 +1232,7 @@ class ExportX3D(bpy.types.Operator):
compress = BoolProperty(name="Compress", description="GZip the resulting file, requires a full python install", default=False)
def execute(self, context):
- x3d_export(self.properties.path, context, self.properties.apply_modifiers, self.properties.triangulate, self.properties.compress)
+ x3d_export(self.properties.filepath, context, self.properties.apply_modifiers, self.properties.triangulate, self.properties.compress)
return {'FINISHED'}
def invoke(self, context, event):
@@ -1244,8 +1242,8 @@ class ExportX3D(bpy.types.Operator):
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".x3d")
- self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)").path = default_path
+ default_path = os.path.splitext(bpy.data.filepath)[0] + ".x3d"
+ self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)").filepath = default_path
def register():
@@ -1261,4 +1259,3 @@ def unregister():
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/io/import_anim_bvh.py b/release/scripts/io/import_anim_bvh.py
index 364bd6e96ee..d497ac47065 100644
--- a/release/scripts/io/import_anim_bvh.py
+++ b/release/scripts/io/import_anim_bvh.py
@@ -22,8 +22,8 @@ import math
from math import radians
import bpy
-import Mathutils
-from Mathutils import Vector, Euler, Matrix, RotationMatrix, TranslationMatrix
+import mathutils
+from mathutils import Vector, Euler, Matrix, RotationMatrix, TranslationMatrix
class bvh_node_class(object):
@@ -83,7 +83,7 @@ def eulerRotate(x, y, z, rot_order):
# Should work but doesnt!
'''
- eul = Euler(x,y,z)
+ eul = Euler((x, y, z))
eul.order = "XYZ"[rot_order[0]] + "XYZ"[rot_order[1]] + "XYZ"[rot_order[2]]
return tuple(eul.to_matrix().to_euler())
'''
@@ -136,7 +136,7 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
#print '%snode: %s, parent: %s' % (len(bvh_nodes_serial) * ' ', name, bvh_nodes_serial[-1])
lineIdx += 2 # Incriment to the next line (Offset)
- rest_head_local = Vector(float(file_lines[lineIdx][1]), float(file_lines[lineIdx][2]), float(file_lines[lineIdx][3])) * GLOBAL_SCALE
+ rest_head_local = Vector((float(file_lines[lineIdx][1]), float(file_lines[lineIdx][2]), float(file_lines[lineIdx][3]))) * GLOBAL_SCALE
lineIdx += 1 # Incriment to the next line (Channels)
# newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation]
@@ -188,7 +188,7 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
# Account for an end node
if file_lines[lineIdx][0].lower() == 'end' and file_lines[lineIdx][1].lower() == 'site': # There is somtimes a name after 'End Site' but we will ignore it.
lineIdx += 2 # Incriment to the next line (Offset)
- rest_tail = Vector(float(file_lines[lineIdx][1]), float(file_lines[lineIdx][2]), float(file_lines[lineIdx][3])) * GLOBAL_SCALE
+ rest_tail = Vector((float(file_lines[lineIdx][1]), float(file_lines[lineIdx][2]), float(file_lines[lineIdx][3]))) * GLOBAL_SCALE
bvh_nodes_serial[-1].rest_tail_world = bvh_nodes_serial[-1].rest_head_world + rest_tail
bvh_nodes_serial[-1].rest_tail_local = bvh_nodes_serial[-1].rest_head_local + rest_tail
@@ -267,8 +267,8 @@ def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
# raise 'error, bvh node has no end and no children. bad file'
# Removed temp for now
- rest_tail_world = Vector(0.0, 0.0, 0.0)
- rest_tail_local = Vector(0.0, 0.0, 0.0)
+ rest_tail_world = Vector((0.0, 0.0, 0.0))
+ rest_tail_local = Vector((0.0, 0.0, 0.0))
for bvh_node_child in bvh_node.children:
rest_tail_world += bvh_node_child.rest_head_world
rest_tail_local += bvh_node_child.rest_head_local
@@ -321,14 +321,14 @@ def bvh_node_dict2objects(context, bvh_nodes, IMPORT_START_FRAME=1, IMPORT_LOOP=
# Animate the data, the last used bvh_node will do since they all have the same number of frames
- for current_frame in range(len(bvh_node.anim_data)):
- Blender.Set('curframe', current_frame + IMPORT_START_FRAME)
+ for frame_current in range(len(bvh_node.anim_data)):
+ Blender.Set('curframe', frame_current + IMPORT_START_FRAME)
for bvh_node in bvh_nodes.values():
- lx, ly, lz, rx, ry, rz = bvh_node.anim_data[current_frame]
+ lx, ly, lz, rx, ry, rz = bvh_node.anim_data[frame_current]
rest_head_local = bvh_node.rest_head_local
- bvh_node.temp.loc = rest_head_local + Vector(lx, ly, lz)
+ bvh_node.temp.loc = rest_head_local + Vector((lx, ly, lz))
bvh_node.temp.rot = rx, ry, rz
@@ -458,13 +458,11 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
pose_bone = pose_bones[bone_name]
pose_bone.rotation_mode = eul_order_lookup[tuple(bvh_node.rot_order)]
- elif ROT_MODE == 'XYZ':
- print(2)
+ elif ROT_MODE != 'QUATERNION':
for pose_bone in pose_bones:
- pose_bone.rotation_mode = 'XYZ'
+ pose_bone.rotation_mode = ROT_MODE
else:
# Quats default
- print(3)
pass
context.scene.update()
@@ -508,30 +506,30 @@ def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAM
prev_euler = [Euler() for i in range(len(bvh_nodes))]
# Animate the data, the last used bvh_node will do since they all have the same number of frames
- for current_frame in range(len(bvh_node.anim_data)-1): # skip the first frame (rest frame)
- # print current_frame
+ for frame_current in range(len(bvh_node.anim_data)-1): # skip the first frame (rest frame)
+ # print frame_current
- # if current_frame==40: # debugging
+ # if frame_current==40: # debugging
# break
# Dont neet to set the current frame
for i, bvh_node in enumerate(bvh_nodes.values()):
pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv = bvh_node.temp
- lx, ly, lz, rx, ry, rz = bvh_node.anim_data[current_frame + 1]
+ lx, ly, lz, rx, ry, rz = bvh_node.anim_data[frame_current + 1]
if bvh_node.has_rot:
- bone_rotation_matrix = Euler(rx, ry, rz).to_matrix().resize4x4()
+ bone_rotation_matrix = Euler((rx, ry, rz)).to_matrix().resize4x4()
bone_rotation_matrix = bone_rest_matrix_inv * bone_rotation_matrix * bone_rest_matrix
if ROT_MODE == 'QUATERNION':
pose_bone.rotation_quaternion = bone_rotation_matrix.to_quat()
else:
- euler = bone_rotation_matrix.to_euler('XYZ', prev_euler[i]) # pose_bone.rotation_mode # TODO, XYZ default for now
+ euler = bone_rotation_matrix.to_euler(pose_bone.rotation_mode, prev_euler[i])
pose_bone.rotation_euler = euler
prev_euler[i] = euler
if bvh_node.has_loc:
- pose_bone.location = (bone_rest_matrix_inv * TranslationMatrix(Vector(lx, ly, lz) - bvh_node.rest_head_local)).translation_part()
+ pose_bone.location = (bone_rest_matrix_inv * TranslationMatrix(Vector((lx, ly, lz)) - bvh_node.rest_head_local)).translation_part()
if bvh_node.has_loc:
pose_bone.keyframe_insert("location")
@@ -563,23 +561,23 @@ class BvhImporter(bpy.types.Operator):
bl_idname = "import_anim.bvh"
bl_label = "Import BVH"
- path = StringProperty(name="File Path", description="File path used for importing the OBJ file", maxlen=1024, default="")
+ filepath = StringProperty(name="File Path", description="Filepath used for importing the OBJ file", maxlen=1024, default="")
scale = FloatProperty(name="Scale", description="Scale the BVH by this value", min=0.0001, max=1000000.0, soft_min=0.001, soft_max=100.0, default=0.1)
- start_frame = IntProperty(name="Start Frame", description="Starting frame for the animation", default=1)
+ frame_start = IntProperty(name="Start Frame", description="Starting frame for the animation", default=1)
loop = BoolProperty(name="Loop", description="Loop the animation playback", default=False)
rotate_mode = EnumProperty(items=(
('QUATERNION', "Quaternion", "Convert rotations to quaternions"),
- # ('NATIVE', "Euler (Native)", "Use the rotation order defined in the BVH file"),
+ ('NATIVE', "Euler (Native)", "Use the rotation order defined in the BVH file"),
('XYZ', "Euler (XYZ)", "Convert rotations to euler XYZ"),
- # ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
- # ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
- # ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
- # ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
- # ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX")),
+ ('XZY', "Euler (XZY)", "Convert rotations to euler XZY"),
+ ('YXZ', "Euler (YXZ)", "Convert rotations to euler YXZ"),
+ ('YZX', "Euler (YZX)", "Convert rotations to euler YZX"),
+ ('ZXY', "Euler (ZXY)", "Convert rotations to euler ZXY"),
+ ('ZYX', "Euler (ZYX)", "Convert rotations to euler ZYX"),
),
name="Rotation",
description="Rotation conversion.",
- default='QUATERNION')
+ default='NATIVE')
def execute(self, context):
# print("Selected: " + context.active_object.name)
@@ -587,7 +585,7 @@ class BvhImporter(bpy.types.Operator):
t1 = time.time()
print('\tparsing bvh...', end="")
- bvh_nodes = read_bvh(context, self.properties.path,
+ bvh_nodes = read_bvh(context, self.properties.filepath,
ROT_MODE=self.properties.rotate_mode,
GLOBAL_SCALE=self.properties.scale)
@@ -597,7 +595,7 @@ class BvhImporter(bpy.types.Operator):
bvh_node_dict2armature(context, bvh_nodes,
ROT_MODE=self.properties.rotate_mode,
- IMPORT_START_FRAME=self.properties.start_frame,
+ IMPORT_START_FRAME=self.properties.frame_start,
IMPORT_LOOP=self.properties.loop)
print('Done in %.4f\n' % (time.time() - t1))
@@ -609,7 +607,8 @@ class BvhImporter(bpy.types.Operator):
return {'RUNNING_MODAL'}
-menu_func = lambda self, context: self.layout.operator(BvhImporter.bl_idname, text="Motion Capture (.bvh)")
+def menu_func(self, context):
+ self.layout.operator(BvhImporter.bl_idname, text="Motion Capture (.bvh)")
def register():
diff --git a/release/scripts/io/import_scene_3ds.py b/release/scripts/io/import_scene_3ds.py
index d1dbdc62563..7b3004d4f52 100644
--- a/release/scripts/io/import_scene_3ds.py
+++ b/release/scripts/io/import_scene_3ds.py
@@ -144,7 +144,7 @@ import struct
from import_scene_obj import unpack_face_list, load_image
import bpy
-import Mathutils
+import mathutils
BOUNDS_3DS = []
@@ -310,8 +310,8 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
contextObName = None
contextLamp = [None, None] # object, Data
contextMaterial = None
- contextMatrix_rot = None # Blender.Mathutils.Matrix(); contextMatrix.identity()
- #contextMatrix_tx = None # Blender.Mathutils.Matrix(); contextMatrix.identity()
+ contextMatrix_rot = None # Blender.mathutils.Matrix(); contextMatrix.identity()
+ #contextMatrix_tx = None # Blender.mathutils.Matrix(); contextMatrix.identity()
contextMesh_vertls = None
contextMesh_facels = None
contextMeshMaterials = {} # matname:[face_idxs]
@@ -360,7 +360,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
vertMappingIndex = 0
vertsToUse = [i for i in range(len(myContextMesh_vertls)) if faceVertUsers[i]]
- myVertMapping = dict( [ (ii, i) for i, ii in enumerate(vertsToUse) ] )
+ myVertMapping = {ii: i for i, ii in enumerate(vertsToUse)}
tempName= '%s_%s' % (contextObName, matName) # matName may be None.
bmesh = bpy.data.meshes.new(tempName)
@@ -427,9 +427,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
'''
if contextMatrix_rot:
- # ob.matrix = [x for row in contextMatrix_rot for x in row]
- ob.matrix = contextMatrix_rot
-# ob.setMatrix(contextMatrix_rot)
+ ob.matrix_world = contextMatrix_rot
importedObjects.append(ob)
bmesh.update()
@@ -722,7 +720,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
def getuv():
temp_data = file.read(STRUCT_SIZE_2FLOAT)
new_chunk.bytes_read += STRUCT_SIZE_2FLOAT #2 float x 4 bytes each
- return Mathutils.Vector( struct.unpack('<2f', temp_data) )
+ return mathutils.Vector( struct.unpack('<2f', temp_data) )
contextMeshUV = [ getuv() for i in range(num_uv) ]
@@ -732,7 +730,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
data = list( struct.unpack('<ffffffffffff', temp_data) )
new_chunk.bytes_read += STRUCT_SIZE_4x3MAT
- contextMatrix_rot = Mathutils.Matrix(\
+ contextMatrix_rot = mathutils.Matrix(\
data[:3] + [0],\
data[3:6] + [0],\
data[6:9] + [0],\
@@ -740,7 +738,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
'''
- contextMatrix_rot = Blender.Mathutils.Matrix(\
+ contextMatrix_rot = Blender.mathutils.Matrix(\
data[:3] + [0],\
data[3:6] + [0],\
data[6:9] + [0],\
@@ -748,14 +746,14 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
'''
'''
- contextMatrix_rot = Blender.Mathutils.Matrix(\
+ contextMatrix_rot = Blender.mathutils.Matrix(\
data[:3] ,\
data[3:6],\
data[6:9])
'''
'''
- contextMatrix_rot = Blender.Mathutils.Matrix()
+ contextMatrix_rot = Blender.mathutils.Matrix()
m = 0
for j in xrange(4):
for i in xrange(3):
@@ -773,7 +771,7 @@ def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
#print contextMatrix_rot
contextMatrix_rot.invert()
#print contextMatrix_rot
- #contextMatrix_tx = Blender.Mathutils.TranslationMatrix(0.5 * Blender.Mathutils.Vector(data[9:]))
+ #contextMatrix_tx = Blender.mathutils.TranslationMatrix(0.5 * Blender.mathutils.Vector(data[9:]))
#contextMatrix_tx.invert()
#tx.invert()
@@ -892,7 +890,7 @@ def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True,
# me = ob.getData(mesh=1)
# me.verts.delete([me.verts[0],])
# if not APPLY_MATRIX:
-# me.transform(ob.matrixWorld.copy().invert())
+# me.transform(ob.matrix_world.copy().invert())
# Done DUMMYVERT
"""
@@ -946,11 +944,11 @@ def load_3ds(filename, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True,
SCALE/=10
# SCALE Matrix
- SCALE_MAT = Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
-# SCALE_MAT = Blender.Mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
+ SCALE_MAT = mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
+# SCALE_MAT = Blender.mathutils.Matrix([SCALE,0,0,0],[0,SCALE,0,0],[0,0,SCALE,0],[0,0,0,1])
for ob in importedObjects:
- ob.setMatrix(ob.matrixWorld * SCALE_MAT)
+ ob.matrix_world = ob.matrix_world * SCALE_MAT
# Done constraining to bounds.
@@ -1012,16 +1010,14 @@ class IMPORT_OT_autodesk_3ds(bpy.types.Operator):
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for importing the 3DS file", maxlen= 1024, default= "")
- filename = StringProperty(name="File Name", description="Name of the file.")
- directory = StringProperty(name="Directory", description="Directory of the file.")
+ filepath = StringProperty(name="File Path", description="Filepath used for importing the 3DS file", maxlen= 1024, default= "")
# size_constraint = FloatProperty(name="Size Constraint", description="Scale the model by 10 until it reacehs the size constraint. Zero Disables.", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=10.0),
# search_images = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True),
# apply_matrix = BoolProperty(name="Transform Fix", description="Workaround for object transformations importing incorrectly", default=False),
def execute(self, context):
- load_3ds(self.properties.path, context, 0.0, False, False)
+ load_3ds(self.properties.filepath, context, 0.0, False, False)
return {'FINISHED'}
def invoke(self, context, event):
@@ -1030,8 +1026,8 @@ class IMPORT_OT_autodesk_3ds(bpy.types.Operator):
return {'RUNNING_MODAL'}
-menu_func = lambda self, context: self.layout.operator(IMPORT_OT_autodesk_3ds.bl_idname, text="3D Studio (.3ds)")
-
+def menu_func(self, context):
+ self.layout.operator(IMPORT_OT_autodesk_3ds.bl_idname, text="3D Studio (.3ds)")
def register():
bpy.types.register(IMPORT_OT_autodesk_3ds)
diff --git a/release/scripts/io/import_scene_obj.py b/release/scripts/io/import_scene_obj.py
index c5bd8339a15..afe82410557 100644
--- a/release/scripts/io/import_scene_obj.py
+++ b/release/scripts/io/import_scene_obj.py
@@ -54,8 +54,8 @@ Note, This loads mesh objects and materials only, nurbs and curves are not suppo
import os
import time
import bpy
-import Mathutils
-import Geometry
+import mathutils
+from geometry import PolyFill
# from Blender import Mesh, Draw, Window, Texture, Material, sys
# # import BPyMesh
@@ -65,19 +65,6 @@ import Geometry
# try: import os
# except: os= False
-# Generic path functions
-def stripFile(path):
- '''Return directory, where the file is'''
- lastSlash= max(path.rfind('\\'), path.rfind('/'))
- if lastSlash != -1:
- path= path[:lastSlash]
- return '%s%s' % (path, os.sep)
-# return '%s%s' % (path, sys.sep)
-
-def stripPath(path):
- '''Strips the slashes from the back of a string'''
- return path.split('/')[-1].split('\\')[-1]
-
def stripExt(name): # name is a string
'''Strips the prefix off the name before writing'''
index= name.rfind('.')
@@ -127,7 +114,7 @@ def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
if not set: # Need sets for this, otherwise do a normal fill.
PREF_FIX_LOOPS= False
- Vector= Mathutils.Vector
+ Vector= mathutils.Vector
if not indices:
return []
@@ -158,7 +145,7 @@ def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
if verts[i][1]==verts[i-1][0]:
verts.pop(i-1)
- fill= Geometry.PolyFill([verts])
+ fill= PolyFill([verts])
else:
'''
@@ -266,7 +253,7 @@ def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
vert_map[i+ii]= vert[2]
ii+=len(verts)
- fill= Geometry.PolyFill([ [v[0] for v in loop] for loop in loop_list ])
+ fill= PolyFill([ [v[0] for v in loop] for loop in loop_list ])
#draw_loops(loop_list)
#raise 'done loop'
# map to original indicies
@@ -316,13 +303,13 @@ def line_value(line_split):
def load_image(imagepath, dirname):
if os.path.exists(imagepath):
- return bpy.data.add_image(imagepath)
+ return bpy.data.images.load(imagepath)
variants = [os.path.join(dirname, imagepath), os.path.join(dirname, os.path.basename(imagepath))]
for path in variants:
if os.path.exists(path):
- return bpy.data.add_image(path)
+ return bpy.data.images.load(path)
else:
print(path, "doesn't exist")
@@ -360,7 +347,7 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
Create all the used materials in this obj,
assign colors and images to the materials from all referenced material libs
'''
- DIR= stripFile(filepath)
+ DIR= os.path.dirname(filepath)
#==================================================================================#
# This function sets textures defined in .mtl file #
@@ -431,7 +418,7 @@ def create_materials(filepath, material_libs, unique_materials, unique_material_
# Add an MTL with the same name as the obj if no MTLs are spesified.
- temp_mtl= stripExt(stripPath(filepath))+ '.mtl'
+ temp_mtl = os.path.splitext((os.path.basename(filepath)))[0] + '.mtl'
if os.path.exists(DIR + temp_mtl) and temp_mtl not in material_libs:
# if sys.exists(DIR + temp_mtl) and temp_mtl not in material_libs:
@@ -521,10 +508,9 @@ def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP,
'''
Takes vert_loc and faces, and seperates into multiple sets of
(verts_loc, faces, unique_materials, dataname)
- This is done so objects do not overload the 16 material limit.
'''
- filename = stripExt(stripPath(filepath))
+ filename = os.path.splitext((os.path.basename(filepath)))[0]
if not SPLIT_OB_OR_GROUP and not SPLIT_MATERIALS:
# use the filename for the object name since we arnt chopping up the mesh.
@@ -610,7 +596,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if unique_smooth_groups:
sharp_edges= {}
- smooth_group_users= dict([ (context_smooth_group, {}) for context_smooth_group in list(unique_smooth_groups.keys()) ])
+ smooth_group_users = {context_smooth_group: {} for context_smooth_group in list(unique_smooth_groups.keys())}
context_smooth_group_old= -1
# Split fgons into tri's
@@ -705,7 +691,7 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
# map the material names to an index
- material_mapping= dict([(name, i) for i, name in enumerate(unique_materials)]) # enumerate over unique_materials keys()
+ material_mapping = {name: i for i, name in enumerate(unique_materials)} # enumerate over unique_materials keys()
materials= [None] * len(unique_materials)
@@ -715,9 +701,8 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
me= bpy.data.meshes.new(dataname)
# make sure the list isnt too big
- for material in materials[0:16]:
+ for material in materials:
me.add_material(material)
-# me.materials= materials[0:16] # make sure the list isnt too big.
#me.verts.extend([(0,0,0)]) # dummy vert
me.add_geometry(len(verts_loc), 0, len(faces))
@@ -772,8 +757,6 @@ def create_mesh(scn, new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_l
if context_material:
if context_material_old is not context_material:
mat= material_mapping[context_material]
- if mat>15:
- mat= 15
context_material_old= context_material
blender_face.material_index= mat
@@ -1363,7 +1346,7 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
'Separate objects from obj...',\
('Object', SPLIT_OBJECTS, 'Import OBJ Objects into Blender Objects'),\
('Group', SPLIT_GROUPS, 'Import OBJ Groups into Blender Objects'),\
- ('Material', SPLIT_MATERIALS, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)'),\
+ ('Split Materials', SPLIT_MATERIALS, 'Import each material into a seperate mesh'),\
'Options...',\
('Keep Vert Order', KEEP_VERT_ORDER, 'Keep vert and face order, disables some other options.'),\
('Clamp Scale:', CLAMP_SIZE, 0.0, 1000.0, 'Clamp the size to this maximum (Zero to Disable)'),\
@@ -1449,7 +1432,7 @@ def load_obj_ui(filepath, BATCH_LOAD= False):
Draw.BeginAlign()
SPLIT_OBJECTS = Draw.Toggle('Object', EVENT_REDRAW, ui_x+9, ui_y+89, 55, 21, SPLIT_OBJECTS.val, 'Import OBJ Objects into Blender Objects', do_split)
SPLIT_GROUPS = Draw.Toggle('Group', EVENT_REDRAW, ui_x+64, ui_y+89, 55, 21, SPLIT_GROUPS.val, 'Import OBJ Groups into Blender Objects', do_split)
- SPLIT_MATERIALS = Draw.Toggle('Material', EVENT_REDRAW, ui_x+119, ui_y+89, 60, 21, SPLIT_MATERIALS.val, 'Import each material into a seperate mesh (Avoids > 16 per mesh error)', do_split)
+ SPLIT_MATERIALS = Draw.Toggle('Split Materials', EVENT_REDRAW, ui_x+119, ui_y+89, 60, 21, SPLIT_MATERIALS.val, 'Import each material into a seperate mesh', do_split)
Draw.EndAlign()
# Only used for user feedback
@@ -1580,14 +1563,14 @@ class IMPORT_OT_obj(bpy.types.Operator):
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for importing the OBJ file", maxlen= 1024, default= "")
+ filepath = StringProperty(name="File Path", description="Filepath used for importing the OBJ file", maxlen= 1024, default= "")
CREATE_SMOOTH_GROUPS = BoolProperty(name="Smooth Groups", description="Surround smooth groups by sharp edges", default= True)
CREATE_FGONS = BoolProperty(name="NGons as FGons", description="Import faces with more then 4 verts as fgons", default= True)
CREATE_EDGES = BoolProperty(name="Lines as Edges", description="Import lines and faces with 2 verts as edge", default= True)
SPLIT_OBJECTS = BoolProperty(name="Object", description="Import OBJ Objects into Blender Objects", default= True)
SPLIT_GROUPS = BoolProperty(name="Group", description="Import OBJ Groups into Blender Objects", default= True)
- SPLIT_MATERIALS = BoolProperty(name="Material", description="Import each material into a seperate mesh (Avoids > 16 per mesh error)", default= True)
+ SPLIT_MATERIALS = BoolProperty(name="Split Materials", description="Import each material into a seperate mesh", default= False)
# old comment: only used for user feedback
# disabled this option because in old code a handler for it disabled SPLIT* params, it's not passed to load_obj
# KEEP_VERT_ORDER = BoolProperty(name="Keep Vert Order", description="Keep vert and face order, disables split options, enable for morph targets", default= True)
@@ -1600,7 +1583,7 @@ class IMPORT_OT_obj(bpy.types.Operator):
def execute(self, context):
# print("Selected: " + context.active_object.name)
- load_obj(self.properties.path,
+ load_obj(self.properties.filepath,
context,
self.properties.CLAMP_SIZE,
self.properties.CREATE_FGONS,
@@ -1621,7 +1604,8 @@ class IMPORT_OT_obj(bpy.types.Operator):
return {'RUNNING_MODAL'}
-menu_func = lambda self, context: self.layout.operator(IMPORT_OT_obj.bl_idname, text="Wavefront (.obj)")
+def menu_func(self, context):
+ self.layout.operator(IMPORT_OT_obj.bl_idname, text="Wavefront (.obj)")
def register():
@@ -1648,4 +1632,3 @@ def unregister():
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/io/import_shape_mdd.py b/release/scripts/io/import_shape_mdd.py
index c64fbd15a5c..ec0e7696630 100644
--- a/release/scripts/io/import_shape_mdd.py
+++ b/release/scripts/io/import_shape_mdd.py
@@ -25,7 +25,7 @@
# origonal model the mdd was Baked out from their will be Strange
# behavior
#
-# vertex animation to ShapeKeys with ipo and gives the frame a value of 1.0
+# vertex animation to ShapeKeys with ipo and gives the frame a value of 1.0
# A modifier to read mdd files would be Ideal but thats for another day :)
#
# Please send any fixes,updates,bugs to Slow67_at_Gmail.com
@@ -36,77 +36,75 @@ from struct import unpack
def mdd_import(filepath, ob, scene, PREF_START_FRAME=0, PREF_JUMP=1):
-
+
print('\n\nimporting mdd "%s"' % filepath)
-
+
bpy.ops.object.mode_set(mode='OBJECT')
file = open(filepath, 'rb')
frames, points = unpack(">2i", file.read(8))
time = unpack((">%df" % frames), file.read(frames * 4))
-
- print('\tpoints:%d frames:%d' % (points,frames))
+
+ print('\tpoints:%d frames:%d' % (points, frames))
# If target object doesn't have Basis shape key, create it.
try:
- num_keys = len( ob.data.shape_keys.keys )
+ num_keys = len(ob.data.shape_keys.keys)
except:
basis = ob.add_shape_key()
basis.name = "Basis"
ob.data.update()
- scene.current_frame = PREF_START_FRAME
+ scene.frame_current = PREF_START_FRAME
def UpdateMesh(ob, fr):
-
+
# Insert new shape key
new_shapekey = ob.add_shape_key()
new_shapekey.name = ("frame_%.4d" % fr)
new_shapekey_name = new_shapekey.name
-
+
ob.active_shape_key_index = len(ob.data.shape_keys.keys)-1
index = len(ob.data.shape_keys.keys)-1
ob.shape_key_lock = True
-
- verts = ob.data.shape_keys.keys[ len(ob.data.shape_keys.keys)-1 ].data
-
-
- for v in verts:
- # 12 is the size of 3 floats
- x,y,z= unpack('>3f', file.read(12))
- v.co[:] = x,z,y
+
+ verts = ob.data.shape_keys.keys[len(ob.data.shape_keys.keys)-1].data
+
+
+ for v in verts: # 12 is the size of 3 floats
+ v.co[:] = unpack('>3f', file.read(12))
#me.update()
ob.shape_key_lock = False
-
+
# insert keyframes
shape_keys = ob.data.shape_keys
- scene.current_frame -= 1
+ scene.frame_current -= 1
ob.data.shape_keys.keys[index].value = 0.0
shape_keys.keys[len(ob.data.shape_keys.keys)-1].keyframe_insert("value")
- scene.current_frame += 1
+ scene.frame_current += 1
ob.data.shape_keys.keys[index].value = 1.0
shape_keys.keys[len(ob.data.shape_keys.keys)-1].keyframe_insert("value")
- scene.current_frame += 1
+ scene.frame_current += 1
ob.data.shape_keys.keys[index].value = 0.0
shape_keys.keys[len(ob.data.shape_keys.keys)-1].keyframe_insert("value")
- ob.data.update()
+ ob.data.update()
for i in range(frames):
UpdateMesh(ob, i)
-
+
from bpy.props import *
class importMDD(bpy.types.Operator):
'''Import MDD vertex keyframe file to shape keys'''
- bl_idname = "import.mdd"
+ bl_idname = "import_shape.mdd"
bl_label = "Import MDD"
# get first scene to get min and max properties for frames, fps
@@ -118,20 +116,19 @@ class importMDD(bpy.types.Operator):
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
- path = StringProperty(name="File Path", description="File path used for importing the MDD file", maxlen=1024)
+ filepath = StringProperty(name="File Path", description="Filepath used for importing the MDD file", maxlen=1024)
#fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
- start_frame = IntProperty(name="Start Frame", description="Start frame for inserting animation", min=minframe, max=maxframe, default=0)
-
+ frame_start = IntProperty(name="Start Frame", description="Start frame for inserting animation", min=minframe, max=maxframe, default=0)
def poll(self, context):
ob = context.active_object
return (ob and ob.type == 'MESH')
def execute(self, context):
- if not self.properties.path:
+ if not self.properties.filepath:
raise Exception("filename not set")
- mdd_import( self.properties.path, bpy.context.active_object, context.scene, self.properties.start_frame, 1)
+ mdd_import(self.properties.filepath, bpy.context.active_object, context.scene, self.properties.frame_start, 1)
return {'FINISHED'}
@@ -148,7 +145,8 @@ def menu_func(self, context):
def register():
bpy.types.register(importMDD)
bpy.types.INFO_MT_file_import.append(menu_func)
-
+
+
def unregister():
bpy.types.unregister(importMDD)
bpy.types.INFO_MT_file_import.remove(menu_func)
diff --git a/release/scripts/io/netrender/__init__.py b/release/scripts/io/netrender/__init__.py
index e06d061f173..f5f104d6d92 100644
--- a/release/scripts/io/netrender/__init__.py
+++ b/release/scripts/io/netrender/__init__.py
@@ -27,6 +27,7 @@ from netrender import master_html
from netrender import utils
from netrender import balancing
from netrender import ui
+from netrender import repath
jobs = []
slaves = []
diff --git a/release/scripts/io/netrender/client.py b/release/scripts/io/netrender/client.py
index aea9c37ff47..9f6d1a7639e 100644
--- a/release/scripts/io/netrender/client.py
+++ b/release/scripts/io/netrender/client.py
@@ -96,12 +96,12 @@ def clientSendJob(conn, scene, anim = False):
job = netrender.model.RenderJob()
if anim:
- for f in range(scene.start_frame, scene.end_frame + 1):
+ for f in range(scene.frame_start, scene.frame_end + 1):
job.addFrame(f)
else:
- job.addFrame(scene.current_frame)
+ job.addFrame(scene.frame_current)
- filename = bpy.data.filename
+ filename = bpy.data.filepath
job.addFile(filename)
job_name = netsettings.job_name
@@ -113,7 +113,7 @@ def clientSendJob(conn, scene, anim = False):
# LIBRARIES
###########################
for lib in bpy.data.libraries:
- file_path = bpy.utils.expandpath(lib.filename)
+ file_path = bpy.utils.expandpath(lib.filepath)
if os.path.exists(file_path):
job.addFile(file_path)
@@ -122,9 +122,13 @@ def clientSendJob(conn, scene, anim = False):
###########################
for image in bpy.data.images:
if image.source == "FILE" and not image.packed_file:
- file_path = bpy.utils.expandpath(image.filename)
+ file_path = bpy.utils.expandpath(image.filepath)
if os.path.exists(file_path):
job.addFile(file_path)
+
+ tex_path = os.path.splitext(file_path)[0] + ".tex"
+ if os.path.exists(tex_path):
+ job.addFile(tex_path)
###########################
# FLUID + POINT CACHE
@@ -144,6 +148,9 @@ def clientSendJob(conn, scene, anim = False):
addPointCache(job, object, modifier.domain_settings.point_cache_low, default_path)
if modifier.domain_settings.highres:
addPointCache(job, object, modifier.domain_settings.point_cache_high, default_path)
+ elif modifier.type == "MULTIRES" and modifier.external:
+ file_path = bpy.utils.expandpath(modifier.filepath)
+ job.addFile(file_path)
# particles modifier are stupid and don't contain data
# we have to go through the object property
@@ -186,6 +193,7 @@ def requestResult(conn, job_id, frame):
class NetworkRenderEngine(bpy.types.RenderEngine):
bl_idname = 'NET_RENDER'
bl_label = "Network Render"
+ bl_postprocess = False
def render(self, scene):
if scene.network_render.mode == "RENDER_CLIENT":
self.render_client(scene)
@@ -227,7 +235,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
self.update_stats("", "Network render waiting for results")
- requestResult(conn, job_id, scene.current_frame)
+ requestResult(conn, job_id, scene.frame_current)
response = conn.getresponse()
if response.status == http.client.NO_CONTENT:
@@ -235,12 +243,12 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
netsettings.job_id = clientSendJob(conn, scene)
job_id = netsettings.job_id
- requestResult(conn, job_id, scene.current_frame)
+ requestResult(conn, job_id, scene.frame_current)
response = conn.getresponse()
while response.status == http.client.ACCEPTED and not self.test_break():
time.sleep(1)
- requestResult(conn, job_id, scene.current_frame)
+ requestResult(conn, job_id, scene.frame_current)
response = conn.getresponse()
# cancel new jobs (animate on network) on break
@@ -268,7 +276,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
f.close()
result = self.begin_result(0, 0, x, y)
- result.load_from_file(netsettings.path + "output.exr", 0, 0)
+ result.load_from_file(netsettings.path + "output.exr")
self.end_result(result)
conn.close()
@@ -283,3 +291,6 @@ def compatible(module):
#compatible("properties_render")
compatible("properties_world")
compatible("properties_material")
+compatible("properties_data_mesh")
+compatible("properties_data_camera")
+compatible("properties_texture")
diff --git a/release/scripts/io/netrender/master.py b/release/scripts/io/netrender/master.py
index 019f33047d8..f227f61a536 100644
--- a/release/scripts/io/netrender/master.py
+++ b/release/scripts/io/netrender/master.py
@@ -19,6 +19,7 @@
import sys, os
import http, http.client, http.server, urllib, socket, socketserver, threading
import subprocess, shutil, time, hashlib
+import pickle
import select # for select.error
from netrender.utils import *
@@ -27,12 +28,16 @@ import netrender.balancing
import netrender.master_html
class MRenderFile(netrender.model.RenderFile):
- def __init__(self, filepath, index, start, end):
- super().__init__(filepath, index, start, end)
+ def __init__(self, filepath, index, start, end, signature):
+ super().__init__(filepath, index, start, end, signature)
self.found = False
def test(self):
self.found = os.path.exists(self.filepath)
+ if self.found:
+ found_signature = hashFile(self.filepath)
+ self.found = self.signature == found_signature
+
return self.found
@@ -74,7 +79,7 @@ class MRenderJob(netrender.model.RenderJob):
# special server properties
self.last_update = 0
self.save_path = ""
- self.files = [MRenderFile(rfile.filepath, rfile.index, rfile.start, rfile.end) for rfile in job_info.files]
+ self.files = [MRenderFile(rfile.filepath, rfile.index, rfile.start, rfile.end, rfile.signature) for rfile in job_info.files]
self.resolution = None
@@ -190,6 +195,11 @@ pause_pattern = re.compile("/pause_([a-zA-Z0-9]+)")
edit_pattern = re.compile("/edit_([a-zA-Z0-9]+)")
class RenderHandler(http.server.BaseHTTPRequestHandler):
+ def log_message(self, format, *args):
+ # override because the original calls self.address_string(), which
+ # is extremely slow due to some timeout..
+ sys.stderr.write("[%s] %s\n" % (self.log_date_time_string(), format%args))
+
def send_head(self, code = http.client.OK, headers = {}, content = "application/octet-stream"):
self.send_response(code)
self.send_header("Content-type", content)
@@ -711,7 +721,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
buf = self.rfile.read(length)
# add same temp file + renames as slave
-
+
f = open(file_path, "wb")
f.write(buf)
f.close()
@@ -861,16 +871,20 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.send_head(http.client.NO_CONTENT)
class RenderMasterServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
- def __init__(self, address, handler_class, path):
+ def __init__(self, address, handler_class, path, subdir=True):
super().__init__(address, handler_class)
self.jobs = []
self.jobs_map = {}
self.slaves = []
self.slaves_map = {}
self.job_id = 0
- self.path = path + "master_" + str(os.getpid()) + os.sep
- self.slave_timeout = 30 # 30 mins: need a parameter for that
+ if subdir:
+ self.path = path + "master_" + str(os.getpid()) + os.sep
+ else:
+ self.path = path
+
+ self.slave_timeout = 5 # 5 mins: need a parameter for that
self.balancer = netrender.balancing.Balancer()
self.balancer.addRule(netrender.balancing.RatingUsageByCategory(self.getJobs))
@@ -883,6 +897,22 @@ class RenderMasterServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
if not os.path.exists(self.path):
os.mkdir(self.path)
+ def restore(self, jobs, slaves, balancer = None):
+ self.jobs = jobs
+ self.jobs_map = {}
+
+ for job in self.jobs:
+ self.jobs_map[job.id] = job
+ self.job_id = max(self.job_id, int(job.id))
+
+ self.slaves = slaves
+ for slave in self.slaves:
+ self.slaves_map[slave.id] = slave
+
+ if balancer:
+ self.balancer = balancer
+
+
def nextJobID(self):
self.job_id += 1
return str(self.job_id)
@@ -1001,8 +1031,29 @@ class RenderMasterServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
def clearMaster(path):
shutil.rmtree(path)
+def createMaster(address, clear, path):
+ filepath = os.path.join(path, "blender_master.data")
+
+ if not clear and os.path.exists(filepath):
+ print("loading saved master:", filepath)
+ with open(filepath, 'rb') as f:
+ path, jobs, slaves = pickle.load(f)
+
+ httpd = RenderMasterServer(address, RenderHandler, path, subdir=False)
+ httpd.restore(jobs, slaves)
+
+ return httpd
+
+ return RenderMasterServer(address, RenderHandler, path)
+
+def saveMaster(path, httpd):
+ filepath = os.path.join(path, "blender_master.data")
+
+ with open(filepath, 'wb') as f:
+ pickle.dump((httpd.path, httpd.jobs, httpd.slaves), f, pickle.HIGHEST_PROTOCOL)
+
def runMaster(address, broadcast, clear, path, update_stats, test_break):
- httpd = RenderMasterServer(address, RenderHandler, path)
+ httpd = createMaster(address, clear, path)
httpd.timeout = 1
httpd.stats = update_stats
@@ -1010,7 +1061,7 @@ def runMaster(address, broadcast, clear, path, update_stats, test_break):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
- start_time = time.time()
+ start_time = time.time() - 2
while not test_break():
try:
@@ -1018,7 +1069,7 @@ def runMaster(address, broadcast, clear, path, update_stats, test_break):
except select.error:
pass
- if time.time() - start_time >= 10: # need constant here
+ if time.time() - start_time >= 2: # need constant here
httpd.timeoutSlaves()
httpd.updateUsage()
@@ -1031,3 +1082,6 @@ def runMaster(address, broadcast, clear, path, update_stats, test_break):
httpd.server_close()
if clear:
clearMaster(httpd.path)
+ else:
+ saveMaster(path, httpd)
+
diff --git a/release/scripts/io/netrender/master_html.py b/release/scripts/io/netrender/master_html.py
index e5feac86e12..c3695cd4f0f 100644
--- a/release/scripts/io/netrender/master_html.py
+++ b/release/scripts/io/netrender/master_html.py
@@ -29,6 +29,7 @@ def get(handler):
def head(title):
output("<html><head>")
+ output("<meta http-equiv='refresh' content=5>")
output("<script src='/html/netrender.js' type='text/javascript'></script>")
# output("<script src='/html/json2.js' type='text/javascript'></script>")
output("<title>")
@@ -105,53 +106,6 @@ def get(handler):
handler.send_head(content = "text/html")
head("NetRender")
- output("<h2>Master</h2>")
-
- output("""<button title="remove all jobs" onclick="clear_jobs();">CLEAR JOB LIST</button>""")
-
- startTable(caption = "Rules", class_style = "rules")
-
- headerTable("type", "enabled", "description", "limit")
-
- for rule in handler.server.balancer.rules:
- rowTable(
- "rating",
- checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
- rule,
- rule.str_limit() +
- """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
- )
-
- for rule in handler.server.balancer.priorities:
- rowTable(
- "priority",
- checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
- rule,
- rule.str_limit() +
- """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
- )
-
- for rule in handler.server.balancer.exceptions:
- rowTable(
- "exception",
- checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
- rule,
- rule.str_limit() +
- """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
- )
-
- endTable()
-
- output("<h2>Slaves</h2>")
-
- startTable()
- headerTable("name", "address", "last seen", "stats", "job")
-
- for slave in handler.server.slaves:
- rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None")
-
- endTable()
-
output("<h2>Jobs</h2>")
startTable()
@@ -203,6 +157,53 @@ def get(handler):
)
endTable()
+
+ output("<h2>Slaves</h2>")
+
+ startTable()
+ headerTable("name", "address", "last seen", "stats", "job")
+
+ for slave in handler.server.slaves:
+ rowTable(slave.name, slave.address[0], time.ctime(slave.last_seen), slave.stats, link(slave.job.name, "/html/job" + slave.job.id) if slave.job else "None")
+
+ endTable()
+
+ output("<h2>Configuration</h2>")
+
+ output("""<button title="remove all jobs" onclick="clear_jobs();">CLEAR JOB LIST</button>""")
+
+ startTable(caption = "Rules", class_style = "rules")
+
+ headerTable("type", "enabled", "description", "limit")
+
+ for rule in handler.server.balancer.rules:
+ rowTable(
+ "rating",
+ checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
+ rule,
+ rule.str_limit() +
+ """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
+ )
+
+ for rule in handler.server.balancer.priorities:
+ rowTable(
+ "priority",
+ checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
+ rule,
+ rule.str_limit() +
+ """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
+ )
+
+ for rule in handler.server.balancer.exceptions:
+ rowTable(
+ "exception",
+ checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
+ rule,
+ rule.str_limit() +
+ """<button title="edit limit" onclick="balance_edit('%i', '%s');">edit</button>""" % (id(rule), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
+ )
+
+ endTable()
output("</body></html>")
@@ -234,13 +235,17 @@ def get(handler):
tot_cache = 0
tot_fluid = 0
+ rowTable(job.files[0].filepath)
+ rowTable("Other Files", class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.other&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
+
for file in job.files:
if file.filepath.endswith(".bphys"):
tot_cache += 1
elif file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
tot_fluid += 1
else:
- rowTable(file.filepath)
+ if file != job.files[0]:
+ rowTable(file.filepath, class_style = "other")
if tot_cache > 0:
rowTable("%i physic cache files" % tot_cache, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.cache&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
@@ -256,9 +261,9 @@ def get(handler):
endTable()
- output("<h2>Blacklist</h2>")
-
if job.blacklist:
+ output("<h2>Blacklist</h2>")
+
startTable()
headerTable("name", "address")
@@ -267,8 +272,6 @@ def get(handler):
rowTable(slave.name, slave.address[0])
endTable()
- else:
- output("<i>Empty</i>")
output("<h2>Frames</h2>")
diff --git a/release/scripts/io/netrender/model.py b/release/scripts/io/netrender/model.py
index 8b0f50ba848..e7656f498b4 100644
--- a/release/scripts/io/netrender/model.py
+++ b/release/scripts/io/netrender/model.py
@@ -103,8 +103,10 @@ JOB_TYPES = {
}
class RenderFile:
- def __init__(self, filepath = "", index = 0, start = -1, end = -1):
+ def __init__(self, filepath = "", index = 0, start = -1, end = -1, signature=0):
self.filepath = filepath
+ self.original_path = filepath
+ self.signature = signature
self.index = index
self.start = start
self.end = end
@@ -112,9 +114,11 @@ class RenderFile:
def serialize(self):
return {
"filepath": self.filepath,
+ "original_path": self.original_path,
"index": self.index,
"start": self.start,
- "end": self.end
+ "end": self.end,
+ "signature": self.signature
}
@staticmethod
@@ -122,7 +126,8 @@ class RenderFile:
if not data:
return None
- rfile = RenderFile(data["filepath"], data["index"], data["start"], data["end"])
+ rfile = RenderFile(data["filepath"], data["index"], data["start"], data["end"], data["signature"])
+ rfile.original_path = data["original_path"]
return rfile
@@ -153,7 +158,8 @@ class RenderJob:
self.blacklist = job_info.blacklist
def addFile(self, file_path, start=-1, end=-1):
- self.files.append(RenderFile(file_path, len(self.files), start, end))
+ signature = hashFile(file_path)
+ self.files.append(RenderFile(file_path, len(self.files), start, end, signature))
def addFrame(self, frame_number, command = ""):
frame = RenderFrame(frame_number, command)
diff --git a/release/scripts/io/netrender/netrender.css b/release/scripts/io/netrender/netrender.css
index cc8a93bb9a7..0c54690e002 100644
--- a/release/scripts/io/netrender/netrender.css
+++ b/release/scripts/io/netrender/netrender.css
@@ -68,6 +68,10 @@ button {
display: none;
}
+.other {
+ display: none;
+}
+
.rules {
width: 60em;
text-align: left;
diff --git a/release/scripts/io/netrender/operators.py b/release/scripts/io/netrender/operators.py
index f667be68c84..858ec800dbc 100644
--- a/release/scripts/io/netrender/operators.py
+++ b/release/scripts/io/netrender/operators.py
@@ -39,7 +39,7 @@ class RENDER_OT_netslave_bake(bpy.types.Operator):
scene = context.scene
netsettings = scene.network_render
- filename = bpy.data.filename
+ filename = bpy.data.filepath
path, name = os.path.split(filename)
root, ext = os.path.splitext(name)
default_path = path + os.sep + "blendcache_" + root + os.sep # need an API call for that
@@ -77,7 +77,7 @@ class RENDER_OT_netslave_bake(bpy.types.Operator):
bpy.ops.ptcache.bake_all()
- #bpy.ops.wm.save_mainfile(path = path + os.sep + root + "_baked.blend")
+ #bpy.ops.wm.save_mainfile(filepath = path + os.sep + root + "_baked.blend")
return {'FINISHED'}
@@ -104,7 +104,7 @@ class RENDER_OT_netclientanim(bpy.types.Operator):
scene.network_render.job_id = client.clientSendJob(conn, scene, True)
conn.close()
- bpy.ops.screen.render('INVOKE_AREA', animation=True)
+ bpy.ops.render.render('INVOKE_AREA', animation=True)
return {'FINISHED'}
@@ -121,7 +121,7 @@ class RENDER_OT_netclientrun(bpy.types.Operator):
return True
def execute(self, context):
- bpy.ops.screen.render('INVOKE_AREA', animation=True)
+ bpy.ops.render.render('INVOKE_AREA', animation=True)
return {'FINISHED'}
@@ -159,6 +159,36 @@ class RENDER_OT_netclientsend(bpy.types.Operator):
return self.execute(context)
@rnaType
+class RENDER_OT_netclientsendframe(bpy.types.Operator):
+ '''Send Render Job with current frame to the Network'''
+ bl_idname = "render.netclientsendframe"
+ bl_label = "Send current frame job"
+
+ def poll(self, context):
+ return True
+
+ def execute(self, context):
+ scene = context.scene
+ netsettings = scene.network_render
+
+ try:
+ conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
+
+ if conn:
+ # Sending file
+ scene.network_render.job_id = client.clientSendJob(conn, scene, False)
+ conn.close()
+ self.report('INFO', "Job sent to master")
+ except Exception as err:
+ self.report('ERROR', str(err))
+
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ return self.execute(context)
+
+@rnaType
class RENDER_OT_netclientstatus(bpy.types.Operator):
'''Refresh the status of the current jobs'''
bl_idname = "render.netclientstatus"
diff --git a/release/scripts/io/netrender/repath.py b/release/scripts/io/netrender/repath.py
new file mode 100755
index 00000000000..7f9befd34fb
--- /dev/null
+++ b/release/scripts/io/netrender/repath.py
@@ -0,0 +1,147 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import sys, os
+import subprocess
+
+import bpy
+
+from netrender.utils import *
+import netrender.model
+
+BLENDER_PATH = sys.argv[0]
+
+def reset(job):
+ main_file = job.files[0]
+
+ job_full_path = main_file.filepath
+
+ if os.path.exists(job_full_path + ".bak"):
+ os.remove(job_full_path) # repathed file
+ os.renames(job_full_path + ".bak", job_full_path)
+
+def update(job):
+ paths = []
+
+ main_file = job.files[0]
+
+ job_full_path = main_file.filepath
+
+
+ path, ext = os.path.splitext(job_full_path)
+
+ new_path = path + ".remap" + ext
+
+ # Disable for now. Partial repath should work anyway
+ #all = main_file.filepath != main_file.original_path
+ all = False
+
+ for rfile in job.files[1:]:
+ if all or rfile.original_path != rfile.filepath:
+ paths.append(rfile.original_path)
+ paths.append(rfile.filepath)
+
+ # Only update if needed
+ if paths:
+ process = subprocess.Popen([BLENDER_PATH, "-b", "-noaudio", job_full_path, "-P", __file__, "--", new_path] + paths, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ process.wait()
+
+ os.renames(job_full_path, job_full_path + ".bak")
+ os.renames(new_path, job_full_path)
+
+def process(paths):
+ def processPointCache(point_cache):
+ point_cache.external = False
+
+ def processFluid(fluid):
+ new_path = path_map.get(fluid.path, None)
+ if new_path:
+ fluid.path = new_path
+
+ path_map = {}
+ for i in range(0, len(paths), 2):
+ # special case for point cache
+ if paths[i].endswith(".bphys"):
+ pass # Don't need them in the map, they all use the default external path
+ # NOTE: This is probably not correct all the time, need to be fixed.
+ # special case for fluids
+ elif paths[i].endswith(".bobj.gz"):
+ path_map[os.path.split(paths[i])[0]] = os.path.split(paths[i+1])[0]
+ else:
+ path_map[paths[i]] = paths[i+1]
+
+ ###########################
+ # LIBRARIES
+ ###########################
+ for lib in bpy.data.libraries:
+ file_path = bpy.utils.expandpath(lib.filepath)
+ new_path = path_map.get(file_path, None)
+ if new_path:
+ lib.filepath = new_path
+
+ ###########################
+ # IMAGES
+ ###########################
+ for image in bpy.data.images:
+ if image.source == "FILE" and not image.packed_file:
+ file_path = bpy.utils.expandpath(image.filepath)
+ new_path = path_map.get(file_path, None)
+ if new_path:
+ image.filepath = new_path
+
+
+ ###########################
+ # FLUID + POINT CACHE
+ ###########################
+ for object in bpy.data.objects:
+ for modifier in object.modifiers:
+ if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
+ processFluid(settings)
+ elif modifier.type == "CLOTH":
+ processPointCache(modifier.point_cache)
+ elif modifier.type == "SOFT_BODY":
+ processPointCache(modifier.point_cache)
+ elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
+ processPointCache(modifier.domain_settings.point_cache_low)
+ if modifier.domain_settings.highres:
+ processPointCache(modifier.domain_settings.point_cache_high)
+ elif modifier.type == "MULTIRES" and modifier.external:
+ file_path = bpy.utils.expandpath(modifier.filepath)
+ new_path = path_map.get(file_path, None)
+ if new_path:
+ modifier.filepath = new_path
+
+ # particles modifier are stupid and don't contain data
+ # we have to go through the object property
+ for psys in object.particle_systems:
+ processPointCache(psys.point_cache)
+
+
+if __name__ == "__main__":
+ try:
+ i = sys.argv.index("--")
+ except:
+ i = 0
+
+ if i:
+ new_path = sys.argv[i+1]
+ args = sys.argv[i+2:]
+
+ process(args)
+
+ bpy.ops.wm.save_as_mainfile(path=new_path, check_existing=False)
diff --git a/release/scripts/io/netrender/slave.py b/release/scripts/io/netrender/slave.py
index d24490385fb..9fd00152dc1 100644
--- a/release/scripts/io/netrender/slave.py
+++ b/release/scripts/io/netrender/slave.py
@@ -22,6 +22,7 @@ import subprocess, time
from netrender.utils import *
import netrender.model
+import netrender.repath
BLENDER_PATH = sys.argv[0]
@@ -64,12 +65,22 @@ def testCancel(conn, job_id, frame_number):
else:
return False
-def testFile(conn, job_id, slave_id, file_index, JOB_PREFIX, file_path, main_path = None):
- job_full_path = prefixPath(JOB_PREFIX, file_path, main_path)
-
- if not os.path.exists(job_full_path):
- temp_path = JOB_PREFIX + "slave.temp.blend"
- conn.request("GET", fileURL(job_id, file_index), headers={"slave-id":slave_id})
+def testFile(conn, job_id, slave_id, rfile, JOB_PREFIX, main_path = None):
+ job_full_path = prefixPath(JOB_PREFIX, rfile.filepath, main_path)
+
+ found = os.path.exists(job_full_path)
+
+ if found:
+ found_signature = hashFile(job_full_path)
+ found = found_signature == rfile.signature
+
+ if not found:
+ print("Found file %s at %s but signature mismatch!" % (rfile.filepath, job_full_path))
+ job_full_path = prefixPath(JOB_PREFIX, rfile.filepath, main_path, force = True)
+
+ if not found:
+ temp_path = JOB_PREFIX + "slave.temp"
+ conn.request("GET", fileURL(job_id, rfile.index), headers={"slave-id":slave_id})
response = conn.getresponse()
if response.status != http.client.OK:
@@ -85,6 +96,8 @@ def testFile(conn, job_id, slave_id, file_index, JOB_PREFIX, file_path, main_pat
f.close()
os.renames(temp_path, job_full_path)
+
+ rfile.filepath = job_full_path
return job_full_path
@@ -105,6 +118,8 @@ def render_slave(engine, netsettings, threads):
if not os.path.exists(NODE_PREFIX):
os.mkdir(NODE_PREFIX)
+ engine.update_stats("", "Network render connected to master, waiting for jobs")
+
while not engine.test_break():
conn.request("GET", "/job", headers={"slave-id":slave_id})
response = conn.getresponse()
@@ -113,6 +128,7 @@ def render_slave(engine, netsettings, threads):
timeout = 1 # reset timeout on new job
job = netrender.model.RenderJob.materialize(eval(str(response.read(), encoding='utf8')))
+ engine.update_stats("", "Network render processing job from master")
JOB_PREFIX = NODE_PREFIX + "job_" + job.id + os.sep
if not os.path.exists(JOB_PREFIX):
@@ -123,14 +139,17 @@ def render_slave(engine, netsettings, threads):
job_path = job.files[0].filepath # path of main file
main_path, main_file = os.path.split(job_path)
- job_full_path = testFile(conn, job.id, slave_id, 0, JOB_PREFIX, job_path)
+ job_full_path = testFile(conn, job.id, slave_id, job.files[0], JOB_PREFIX)
print("Fullpath", job_full_path)
print("File:", main_file, "and %i other files" % (len(job.files) - 1,))
- engine.update_stats("", "Render File "+ main_file+ " for job "+ job.id)
for rfile in job.files[1:]:
+ testFile(conn, job.id, slave_id, rfile, JOB_PREFIX, main_path)
print("\t", rfile.filepath)
- testFile(conn, job.id, slave_id, rfile.index, JOB_PREFIX, rfile.filepath, main_path)
+
+ netrender.repath.update(job)
+
+ engine.update_stats("", "Render File "+ main_file+ " for job "+ job.id)
# announce log to master
logfile = netrender.model.LogFile(job.id, slave_id, [frame.number for frame in job.frames])
@@ -175,6 +194,10 @@ def render_slave(engine, netsettings, threads):
# (only need to update on one frame, they are linked
conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
response = conn.getresponse()
+
+ # Also output on console
+ if netsettings.slave_thumb:
+ print(str(stdout, encoding='utf8'), end="")
stdout = bytes()
@@ -182,6 +205,9 @@ def render_slave(engine, netsettings, threads):
if testCancel(conn, job.id, first_frame):
cancelled = True
+ if job.type == netrender.model.JOB_BLENDER:
+ netrender.repath.reset(job)
+
# read leftovers if needed
stdout += process.stdout.read()
@@ -191,6 +217,17 @@ def render_slave(engine, netsettings, threads):
process.terminate()
continue # to next frame
+ # flush the rest of the logs
+ if stdout:
+ # Also output on console
+ if netsettings.slave_thumb:
+ print(str(stdout, encoding='utf8'), end="")
+
+ # (only need to update on one frame, they are linked
+ conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
+ if conn.getresponse().status == http.client.NO_CONTENT:
+ continue
+
total_t = time.time() - start_t
avg_t = total_t / len(job.frames)
@@ -199,13 +236,6 @@ def render_slave(engine, netsettings, threads):
print("status", status)
- # flush the rest of the logs
- if stdout:
- # (only need to update on one frame, they are linked
- conn.request("PUT", logURL(job.id, first_frame), stdout, headers=headers)
- if conn.getresponse().status == http.client.NO_CONTENT:
- continue
-
headers = {"job-id":job.id, "slave-id":slave_id, "job-time":str(avg_t)}
@@ -245,6 +275,8 @@ def render_slave(engine, netsettings, threads):
conn.request("PUT", "/render", headers=headers)
if conn.getresponse().status == http.client.NO_CONTENT:
continue
+
+ engine.update_stats("", "Network render connected to master, waiting for jobs")
else:
if timeout < MAX_TIMEOUT:
timeout += INCREMENT_TIMEOUT
diff --git a/release/scripts/io/netrender/ui.py b/release/scripts/io/netrender/ui.py
index ba14d7e4f42..c60b10c484a 100644
--- a/release/scripts/io/netrender/ui.py
+++ b/release/scripts/io/netrender/ui.py
@@ -37,8 +37,8 @@ DONE = 2
ERROR = 3
def init_file():
- if netrender.init_file != bpy.data.filename:
- netrender.init_file = bpy.data.filename
+ if netrender.init_file != bpy.data.filepath:
+ netrender.init_file = bpy.data.filepath
netrender.init_data = True
netrender.init_address = True
@@ -76,7 +76,7 @@ def verify_address(netsettings):
else:
netsettings.server_address = "[default]"
-class RenderButtonsPanel(bpy.types.Panel):
+class RenderButtonsPanel():
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
@@ -88,7 +88,7 @@ class RenderButtonsPanel(bpy.types.Panel):
# Setting panel, use in the scene for now.
@rnaType
-class RENDER_PT_network_settings(RenderButtonsPanel):
+class RENDER_PT_network_settings(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Network Settings"
COMPAT_ENGINES = {'NET_RENDER'}
@@ -123,7 +123,7 @@ class RENDER_PT_network_settings(RenderButtonsPanel):
layout.operator("render.netclientweb", icon='QUESTION')
@rnaType
-class RENDER_PT_network_slave_settings(RenderButtonsPanel):
+class RENDER_PT_network_slave_settings(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Slave Settings"
COMPAT_ENGINES = {'NET_RENDER'}
@@ -141,13 +141,14 @@ class RENDER_PT_network_slave_settings(RenderButtonsPanel):
layout.prop(netsettings, "slave_clear")
layout.prop(netsettings, "slave_thumb")
+ layout.prop(netsettings, "slave_outputlog")
layout.label(text="Threads:")
layout.prop(rd, "threads_mode", expand=True)
sub = layout.column()
- sub.enabled = rd.threads_mode == 'THREADS_FIXED'
+ sub.enabled = rd.threads_mode == 'FIXED'
sub.prop(rd, "threads")
@rnaType
-class RENDER_PT_network_master_settings(RenderButtonsPanel):
+class RENDER_PT_network_master_settings(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Master Settings"
COMPAT_ENGINES = {'NET_RENDER'}
@@ -166,7 +167,7 @@ class RENDER_PT_network_master_settings(RenderButtonsPanel):
layout.prop(netsettings, "master_clear")
@rnaType
-class RENDER_PT_network_job(RenderButtonsPanel):
+class RENDER_PT_network_job(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Job Settings"
COMPAT_ENGINES = {'NET_RENDER'}
@@ -186,10 +187,11 @@ class RENDER_PT_network_job(RenderButtonsPanel):
if netsettings.server_address != "[default]":
layout.operator("render.netclientanim", icon='RENDER_ANIMATION')
layout.operator("render.netclientsend", icon='FILE_BLEND')
+ layout.operator("render.netclientsendframe", icon='RENDER_STILL')
if netsettings.job_id:
row = layout.row()
- row.operator("screen.render", text="Get Image", icon='RENDER_STILL')
- row.operator("screen.render", text="Get Animation", icon='RENDER_ANIMATION').animation = True
+ row.operator("render.render", text="Get Image", icon='RENDER_STILL')
+ row.operator("render.render", text="Get Animation", icon='RENDER_ANIMATION').animation = True
split = layout.split(percentage=0.3)
@@ -206,16 +208,17 @@ class RENDER_PT_network_job(RenderButtonsPanel):
row.prop(netsettings, "chunks")
@rnaType
-class RENDER_PT_network_slaves(RenderButtonsPanel):
+class RENDER_PT_network_slaves(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Slaves Status"
COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
netsettings = scene.network_render
+ if netsettings.mode != "RENDER_CLIENT":
+ return False
verify_address(netsettings)
return (super().poll(context)
- and netsettings.mode == "RENDER_CLIENT"
and netsettings.server_address != "[default]")
def draw(self, context):
@@ -244,16 +247,17 @@ class RENDER_PT_network_slaves(RenderButtonsPanel):
layout.label(text="Stats: " + slave.stats)
@rnaType
-class RENDER_PT_network_slaves_blacklist(RenderButtonsPanel):
+class RENDER_PT_network_slaves_blacklist(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Slaves Blacklist"
COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
netsettings = scene.network_render
+ if netsettings.mode != "RENDER_CLIENT":
+ return False
verify_address(netsettings)
return (super().poll(context)
- and netsettings.mode == "RENDER_CLIENT"
and netsettings.server_address != "[default]")
def draw(self, context):
@@ -281,16 +285,17 @@ class RENDER_PT_network_slaves_blacklist(RenderButtonsPanel):
layout.label(text="Stats: " + slave.stats)
@rnaType
-class RENDER_PT_network_jobs(RenderButtonsPanel):
+class RENDER_PT_network_jobs(bpy.types.Panel, RenderButtonsPanel):
bl_label = "Jobs"
COMPAT_ENGINES = {'NET_RENDER'}
def poll(self, context):
scene = context.scene
netsettings = scene.network_render
+ if netsettings.mode != "RENDER_CLIENT":
+ return False
verify_address(netsettings)
return (super().poll(context)
- and netsettings.mode == "RENDER_CLIENT"
and netsettings.server_address != "[default]")
def draw(self, context):
@@ -362,6 +367,11 @@ NetRenderSettings.BoolProperty( attr="slave_thumb",
description="Generate thumbnails on slaves instead of master",
default = False)
+NetRenderSettings.BoolProperty( attr="slave_outputlog",
+ name="Output render log on console",
+ description="Output render text log to console as well as sending it to the master",
+ default = True)
+
NetRenderSettings.BoolProperty( attr="master_clear",
name="Clear on exit",
description="delete saved files on exit",
diff --git a/release/scripts/io/netrender/utils.py b/release/scripts/io/netrender/utils.py
index 1d35ea00c99..6288b9747c0 100644
--- a/release/scripts/io/netrender/utils.py
+++ b/release/scripts/io/netrender/utils.py
@@ -19,7 +19,7 @@
import sys, os
import re
import http, http.client, http.server, urllib, socket
-import subprocess, shutil, time, hashlib
+import subprocess, shutil, time, hashlib, zlib
import netrender.model
@@ -28,7 +28,7 @@ try:
except:
bpy = None
-VERSION = bytes("0.8", encoding='utf8')
+VERSION = bytes("0.9", encoding='utf8')
# Jobs status
JOB_WAITING = 0 # before all data has been entered
@@ -110,7 +110,7 @@ def clientConnection(address, port, report = None, scan = True):
return None
try:
- conn = http.client.HTTPConnection(address, port)
+ conn = http.client.HTTPConnection(address, port, timeout = 5)
if conn:
if clientVerifyVersion(conn):
@@ -154,18 +154,33 @@ def renderURL(job_id, frame_number):
def cancelURL(job_id):
return "/cancel_%s" % (job_id)
-def prefixPath(prefix_directory, file_path, prefix_path):
+def hashFile(path):
+ f = open(path, "rb")
+ value = hashData(f.read())
+ f.close()
+ return value
+
+def hashData(data):
+ m = hashlib.md5()
+ m.update(data)
+ return m.hexdigest()
+
+
+def prefixPath(prefix_directory, file_path, prefix_path, force = False):
if os.path.isabs(file_path):
# if an absolute path, make sure path exists, if it doesn't, use relative local path
full_path = file_path
- if not os.path.exists(full_path):
+ if force or not os.path.exists(full_path):
p, n = os.path.split(full_path)
if prefix_path and p.startswith(prefix_path):
- directory = prefix_directory + p[len(prefix_path):]
- full_path = directory + os.sep + n
- if not os.path.exists(directory):
- os.mkdir(directory)
+ if len(prefix_path) < len(p):
+ directory = prefix_directory + p[len(prefix_path)+1:] + os.sep # +1 to remove separator
+ if not os.path.exists(directory):
+ os.mkdir(directory)
+ else:
+ directory = prefix_directory
+ full_path = directory + n
else:
full_path = prefix_directory + n
else:
@@ -199,8 +214,8 @@ def thumbnail(filename):
if bpy:
scene = bpy.data.scenes[0] # FIXME, this is dodgy!
scene.render.file_format = "JPEG"
- scene.render.quality = 90
- bpy.ops.image.open(path = filename)
+ scene.render.file_quality = 90
+ bpy.ops.image.open(filepath=filename)
img = bpy.data.images[imagename]
img.save_render(thumbname, scene=scene)
diff --git a/release/scripts/keyingsets/keyingsets_builtins.py b/release/scripts/keyingsets/keyingsets_builtins.py
new file mode 100644
index 00000000000..bf5c66ad01d
--- /dev/null
+++ b/release/scripts/keyingsets/keyingsets_builtins.py
@@ -0,0 +1,225 @@
+# Built-In Keying Sets
+# None of these Keying Sets should be removed, as these
+# are needed by various parts of Blender in order for them
+# to work correctly.
+
+import bpy
+from keyingsets_utils import *
+
+###############################
+# Built-In KeyingSets
+
+# Location
+class BUILTIN_KSI_Location(bpy.types.KeyingSetInfo):
+ bl_label = "Location"
+
+ # poll - use predefined callback for selected bones/objects
+ poll = RKS_POLL_selected_items
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ generate = RKS_GEN_location
+
+# Rotation
+class BUILTIN_KSI_Rotation(bpy.types.KeyingSetInfo):
+ bl_label = "Rotation"
+
+ # poll - use predefined callback for selected bones/objects
+ poll = RKS_POLL_selected_items
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ generate = RKS_GEN_rotation
+
+# Scale
+class BUILTIN_KSI_Scaling(bpy.types.KeyingSetInfo):
+ bl_label = "Scaling"
+
+ # poll - use predefined callback for selected bones/objects
+ poll = RKS_POLL_selected_items
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ generate = RKS_GEN_scaling
+
+# ------------
+
+# LocRot
+class BUILTIN_KSI_LocRot(bpy.types.KeyingSetInfo):
+ bl_label = "LocRot"
+
+ # poll - use predefined callback for selected bones/objects
+ poll = RKS_POLL_selected_items
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ def generate(self, context, ks, data):
+ # location
+ RKS_GEN_location(self, context, ks, data)
+ # rotation
+ RKS_GEN_rotation(self, context, ks, data)
+
+# LocScale
+class BUILTIN_KSI_LocScale(bpy.types.KeyingSetInfo):
+ bl_label = "LocScale"
+
+ # poll - use predefined callback for selected bones/objects
+ poll = RKS_POLL_selected_items
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ def generate(self, context, ks, data):
+ # location
+ RKS_GEN_location(self, context, ks, data)
+ # scale
+ RKS_GEN_scaling(self, context, ks, data)
+
+# LocRotScale
+class BUILTIN_KSI_LocRotScale(bpy.types.KeyingSetInfo):
+ bl_label = "LocRotScale"
+
+ # poll - use predefined callback for selected bones/objects
+ poll = RKS_POLL_selected_items
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ def generate(self, context, ks, data):
+ # location
+ RKS_GEN_location(self, context, ks, data)
+ # rotation
+ RKS_GEN_rotation(self, context, ks, data)
+ # scale
+ RKS_GEN_scaling(self, context, ks, data)
+
+# RotScale
+class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo):
+ bl_label = "RotScale"
+
+ # poll - use predefined callback for selected bones/objects
+ poll = RKS_POLL_selected_items
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ def generate(self, context, ks, data):
+ # rotation
+ RKS_GEN_rotation(self, context, ks, data)
+ # scaling
+ RKS_GEN_scaling(self, context, ks, data)
+
+# ------------
+
+# Location
+class BUILTIN_KSI_VisualLoc(bpy.types.KeyingSetInfo):
+ bl_label = "Visual Location"
+
+ insertkey_visual = True
+
+ # poll - use predefined callback for selected bones/objects
+ poll = RKS_POLL_selected_items
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ generate = RKS_GEN_location
+
+# Rotation
+class BUILTIN_KSI_VisualRot(bpy.types.KeyingSetInfo):
+ bl_label = "Visual Rotation"
+
+ insertkey_visual = True
+
+ # poll - use predefined callback for selected bones/objects
+ poll = RKS_POLL_selected_items
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ generate = RKS_GEN_rotation
+
+# VisualLocRot
+class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo):
+ bl_label = "Visual LocRot"
+
+ insertkey_visual = True
+
+ # poll - use predefined callback for selected bones/objects
+ poll = RKS_POLL_selected_items
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ def generate(self, context, ks, data):
+ # location
+ RKS_GEN_location(self, context, ks, data)
+ # rotation
+ RKS_GEN_rotation(self, context, ks, data)
+
+# ------------
+
+# Available
+class BUILTIN_KSI_Available(bpy.types.KeyingSetInfo):
+ bl_label = "Available"
+
+ # poll - use predefined callback for selected objects
+ # TODO: this should really check whether the selected object (or datablock)
+ # has any animation data defined yet
+ poll = RKS_POLL_selected_objects
+
+ # iterator - use callback for selected bones/objects
+ iterator = RKS_ITER_selected_item
+
+ # generator - use callback for location
+ generate = RKS_GEN_available
+
+###############################
+
+classes = [
+ BUILTIN_KSI_Location,
+ BUILTIN_KSI_Rotation,
+ BUILTIN_KSI_Scaling,
+
+ BUILTIN_KSI_LocRot,
+ BUILTIN_KSI_LocScale,
+ BUILTIN_KSI_LocRotScale,
+ BUILTIN_KSI_RotScale,
+
+ BUILTIN_KSI_VisualLoc,
+ BUILTIN_KSI_VisualRot,
+ BUILTIN_KSI_VisualLocRot,
+
+ BUILTIN_KSI_Available,
+]
+
+
+def register():
+ register = bpy.types.register
+ for cls in classes:
+ register(cls)
+
+
+def unregister():
+ unregister = bpy.types.unregister
+ for cls in classes:
+ unregister(cls)
+
+if __name__ == "__main__":
+ register()
+
+###############################
diff --git a/release/scripts/keyingsets/keyingsets_utils.py b/release/scripts/keyingsets/keyingsets_utils.py
new file mode 100644
index 00000000000..77b0f3ebacd
--- /dev/null
+++ b/release/scripts/keyingsets/keyingsets_utils.py
@@ -0,0 +1,163 @@
+# This file defines a set of methods that are useful for various
+# Relative Keying Set (RKS) related operations, such as: callbacks
+# for polling, iterator callbacks, and also generate callbacks.
+# All of these can be used in conjunction with the others.
+
+import bpy
+
+###########################
+# General Utilities
+
+# Append the specified property name on the the existing path
+def path_add_property(path, prop):
+ if len(path):
+ return path + "." + prop;
+ else:
+ return prop;
+
+###########################
+# Poll Callbacks
+
+# selected objects
+def RKS_POLL_selected_objects(ksi, context):
+ return context.active_object or len(context.selected_objects);
+
+# selected bones
+def RKS_POLL_selected_bones(ksi, context):
+ # we must be in Pose Mode, and there must be some bones selected
+ if (context.active_object) and (context.active_object.mode == 'POSE'):
+ if context.active_pose_bone or len(context.selected_pose_bones):
+ return True;
+
+ # nothing selected
+ return False;
+
+
+# selected bones or objects
+def RKS_POLL_selected_items(ksi, context):
+ return RKS_POLL_selected_bones(ksi, context) or RKS_POLL_selected_objects(ksi, context);
+
+###########################
+# Iterator Callbacks
+
+# all selected objects or pose bones, depending on which we've got
+def RKS_ITER_selected_item(ksi, context, ks):
+ if (context.active_object) and (context.active_object.mode == 'POSE'):
+ for bone in context.selected_pose_bones:
+ ksi.generate(context, ks, bone)
+ else:
+ for ob in context.selected_objects:
+ ksi.generate(context, ks, ob)
+
+###########################
+# Generate Callbacks
+
+# 'Available' F-Curves
+def RKS_GEN_available(ksi, context, ks, data):
+ # try to get the animation data associated with the closest
+ # ID-block to the data (neither of which may exist/be easy to find)
+ id_block = data.id_data
+ adt = getattr(id_block, "animation_data", None)
+
+ # there must also be an active action...
+ if adt is None or adt.action is None:
+ return;
+
+ # for each F-Curve, include an path to key it
+ # NOTE: we don't need to set the group settings here
+ for fcu in adt.action.fcurves:
+ ks.paths.add(id_block, fcu.data_path, index=fcu.array_index)
+
+# ------
+
+# get ID block and based ID path for transform generators
+def get_transform_generators_base_info(data):
+ # ID-block for the data
+ id_block = data.id_data
+
+ # get base path and grouping method/name
+ if isinstance(data, bpy.types.ID):
+ # no path in this case
+ path = ""
+
+ # data on ID-blocks directly should get grouped by the KeyingSet
+ grouping = None
+ else:
+ # get the path to the ID-block
+ path = data.path_from_id()
+
+ # try to use the name of the data element to group the F-Curve
+ # else fallback on the KeyingSet name
+ grouping = getattr(data, "name", None)
+
+ # return the ID-block and the path
+ return id_block, path, grouping
+
+# Location
+def RKS_GEN_location(ksi, context, ks, data):
+ # get id-block and path info
+ id_block, base_path, grouping= get_transform_generators_base_info(data)
+
+ # add the property name to the base path
+ path = path_add_property(base_path, "location")
+
+ # add Keying Set entry for this...
+ if grouping:
+ ks.paths.add(id_block, path, grouping_method='NAMED', group_name=grouping)
+ else:
+ ks.paths.add(id_block, path)
+
+# Rotation
+def RKS_GEN_rotation(ksi, context, ks, data):
+ # get id-block and path info
+ id_block, base_path, grouping= get_transform_generators_base_info(data)
+
+ # add the property name to the base path
+ # rotation mode affects the property used
+ if data.rotation_mode == 'QUATERNION':
+ path = path_add_property(base_path, "rotation_quaternion")
+ elif data.rotation_mode == 'AXISANGLE':
+ path = path_add_property(base_path, "rotation_axis_angle")
+ else:
+ path = path_add_property(base_path, "rotation_euler")
+
+ # add Keying Set entry for this...
+ if grouping:
+ ks.paths.add(id_block, path, grouping_method='NAMED', group_name=grouping)
+ else:
+ ks.paths.add(id_block, path)
+
+# Scaling
+def RKS_GEN_scaling(ksi, context, ks, data):
+ # get id-block and path info
+ id_block, base_path, grouping= get_transform_generators_base_info(data)
+
+ # add the property name to the base path
+ path = path_add_property(base_path, "scale")
+
+ # add Keying Set entry for this...
+ if grouping:
+ ks.paths.add(id_block, path, grouping_method='NAMED', group_name=grouping)
+ else:
+ ks.paths.add(id_block, path)
+
+###########################
+# Un-needed stuff which is here to just shut up the warnings...
+
+classes = []
+
+def register():
+ register = bpy.types.register
+ for cls in classes:
+ register(cls)
+
+
+def unregister():
+ unregister = bpy.types.unregister
+ for cls in classes:
+ unregister(cls)
+
+if __name__ == "__main__":
+ register()
+
+###########################
diff --git a/release/scripts/modules/add_object_utils.py b/release/scripts/modules/add_object_utils.py
new file mode 100644
index 00000000000..cef368c529d
--- /dev/null
+++ b/release/scripts/modules/add_object_utils.py
@@ -0,0 +1,83 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+import mathutils
+
+
+def add_object_align_init(context, operator):
+
+ if operator and operator.properties.is_property_set("location") and operator.properties.is_property_set("rotation"):
+ location = mathutils.TranslationMatrix(mathutils.Vector(operator.properties.location))
+ rotation = mathutils.Euler(operator.properties.rotation).to_matrix().resize4x4()
+ else:
+ # TODO, local view cursor!
+ location = mathutils.TranslationMatrix(context.scene.cursor_location)
+
+ if context.user_preferences.edit.object_align == 'VIEW' and context.space_data.type == 'VIEW_3D':
+ rotation = context.space_data.region_3d.view_matrix.rotation_part().invert().resize4x4()
+ else:
+ rotation = mathutils.Matrix()
+
+ # set the operator properties
+ if operator:
+ operator.properties.location = location.translation_part()
+ operator.properties.rotation = rotation.to_euler()
+
+ return location * rotation
+
+
+def add_object_data(context, obdata, operator=None):
+
+ scene = context.scene
+
+ # ugh, could be made nicer
+ for ob in scene.objects:
+ ob.selected = False
+
+ obj_new = bpy.data.objects.new(obdata.name, obdata)
+
+ base = scene.objects.link(obj_new)
+ base.selected = True
+
+ if context.space_data and context.space_data.type == 'VIEW_3D':
+ base.layers_from_view(context.space_data)
+
+
+ obj_new.matrix_world = add_object_align_init(context, operator)
+
+ obj_act = scene.objects.active
+
+ if obj_act and obj_act.mode == 'EDIT' and obj_act.type == obj_new.type:
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ obj_act.selected = True
+ scene.update() # apply location
+ #scene.objects.active = obj_new
+
+ bpy.ops.object.join() # join into the active.
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ else:
+ scene.objects.active = obj_new
+ if context.user_preferences.edit.enter_edit_mode:
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ return base
diff --git a/release/scripts/modules/blend_render_info.py b/release/scripts/modules/blend_render_info.py
new file mode 100755
index 00000000000..dcd1f9cbee3
--- /dev/null
+++ b/release/scripts/modules/blend_render_info.py
@@ -0,0 +1,100 @@
+#!/usr/bin/python
+
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+# This module can get render info without running from inside blender.
+#
+# This struct wont change according to Ton.
+# Note that the size differs on 32/64bit
+#
+# typedef struct BHead {
+# int code, len;
+# void *old;
+# int SDNAnr, nr;
+# } BHead;
+
+
+def read_blend_rend_chunk(path):
+
+ import struct
+
+ blendfile = open(path, 'rb')
+
+ head = blendfile.read(7)
+
+ if head[0:2] == b'\x1f\x8b': # gzip magic
+ import gzip
+ blendfile.close()
+ blendfile = gzip.open(path, 'rb')
+ head = blendfile.read(7)
+
+ if head != b'BLENDER':
+ print("not a blend file:", path)
+ blendfile.close()
+ return []
+
+ is_64_bit = (blendfile.read(1) == b'-')
+
+ # true for PPC, false for X86
+ is_big_endian = (blendfile.read(1) == b'V')
+
+ # Now read the bhead chunk!!!
+ blendfile.read(3) # skip the version
+
+ scenes = []
+
+ sizeof_bhead = 24 if is_64_bit else 20
+
+ while blendfile.read(4) == b'REND':
+ sizeof_bhead_left = sizeof_bhead - 4
+
+ struct.unpack('>i' if is_big_endian else '<i', blendfile.read(4))[0]
+ sizeof_bhead_left -= 4
+
+ # We dont care about the rest of the bhead struct
+ blendfile.read(sizeof_bhead_left)
+
+ # Now we want the scene name, start and end frame. this is 32bites long
+ start_frame, end_frame = struct.unpack('>2i' if is_big_endian else '<2i', blendfile.read(8))
+
+ scene_name = blendfile.read(24)
+
+ scene_name = scene_name[:scene_name.index(b'\0')]
+
+ try:
+ scene_name = str(scene_name, 'utf8')
+ except TypeError:
+ pass
+
+ scenes.append((start_frame, end_frame, scene_name))
+
+ return scenes
+
+
+def main():
+ import sys
+ for arg in sys.argv[1:]:
+ if arg.lower().endswith('.blend'):
+ for value in read_blend_rend_chunk(arg):
+ print("%d %d %s" % value)
+
+if __name__ == '__main__':
+ main()
diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py
index 12f8e19cef4..1e6db441599 100644
--- a/release/scripts/modules/bpy/__init__.py
+++ b/release/scripts/modules/bpy/__init__.py
@@ -43,10 +43,13 @@ def _main():
## people need to explain how this is even a fix.
# _sys.path[:] = filter(None, _sys.path)
- # a bit nasty but this prevents help() and input() from locking blender
- # Ideally we could have some way for the console to replace sys.stdin but
- # python would lock blender while waiting for a return value, not easy :|
- _sys.stdin = None
+ # because of how the console works. we need our own help() pager func.
+ # replace the bold function because it adds crazy chars
+ import pydoc
+ pydoc.getpager = lambda: pydoc.plainpager
+ pydoc.Helper.getline = lambda self, prompt: None
+ pydoc.TextDoc.bold = lambda self, text: text
+
# if "-d" in sys.argv: # Enable this to measure startup speed
if 0:
diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py
index 7787d9ee5fe..5cde7091257 100644
--- a/release/scripts/modules/bpy/utils.py
+++ b/release/scripts/modules/bpy/utils.py
@@ -27,7 +27,7 @@ import bpy as _bpy
import os as _os
import sys as _sys
-from _bpy import home_paths
+from _bpy import home_paths, blend_paths
def _test_import(module_name, loaded_modules):
@@ -144,6 +144,9 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
_loaded.append(mod)
if reload_scripts:
+
+ # TODO, this is broken but should work, needs looking into
+ '''
# reload modules that may not be directly included
for type_class_name in dir(_bpy.types):
type_class = getattr(_bpy.types, type_class_name)
@@ -156,6 +159,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
for module_name in sorted(loaded_modules):
print("Reloading:", module_name)
test_reload(_sys.modules[module_name])
+ '''
# loop over and unload all scripts
_loaded.reverse()
@@ -166,23 +170,26 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
unregister()
except:
traceback.print_exc()
+
+ for mod in _loaded:
+ reload(mod)
+
_loaded[:] = []
- for base_path in script_paths(user=False):
- for path_subdir in ("ui", "op", "io", "cfg"):
+ user_path = user_script_path()
+
+ for base_path in script_paths():
+ for path_subdir in ("", "ui", "op", "io", "cfg", "keyingsets", "modules"):
path = _os.path.join(base_path, path_subdir)
if _os.path.isdir(path):
sys_path_ensure(path)
- for mod in modules_from_path(path, loaded_modules):
- test_register(mod)
+ # only add this to sys.modules, dont run
+ if path_subdir == "modules":
+ continue
- user_path = user_script_path()
- if user_path:
- for path_subdir in ("", "ui", "op", "io", "cfg"):
- path = _os.path.join(user_path, path_subdir)
- if _os.path.isdir(path):
- sys_path_ensure(path)
+ if user_path != base_path and path_subdir == "":
+ continue # avoid loading 2.4x scripts
for mod in modules_from_path(path, loaded_modules):
test_register(mod)
@@ -206,8 +213,26 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
def expandpath(path):
+ """
+ Returns the absolute path relative to the current blend file using the "//" prefix.
+ """
if path.startswith("//"):
- return _os.path.join(_os.path.dirname(_bpy.data.filename), path[2:])
+ return _os.path.join(_os.path.dirname(_bpy.data.filepath), path[2:])
+
+ return path
+
+
+def relpath(path, start=None):
+ """
+ Returns the path relative to the current blend file using the "//" prefix.
+
+ :arg start: Relative to this path, when not set the current filename is used.
+ :type start: string
+ """
+ if not path.startswith("//"):
+ if start is None:
+ start = _os.path.dirname(_bpy.data.filepath)
+ return "//" + _os.path.relpath(path, start)
return path
@@ -315,3 +340,51 @@ def preset_paths(subdir):
'''
return (_os.path.join(_presets, subdir), )
+
+
+def smpte_from_seconds(time, fps=None):
+ '''
+ Returns an SMPTE formatted string from the time in seconds: "HH:MM:SS:FF".
+
+ If the fps is not given the current scene is used.
+ '''
+ import math
+
+ if fps is None:
+ fps = _bpy.context.scene.render.fps
+
+ hours = minutes = seconds = frames = 0
+
+ if time < 0:
+ time = - time
+ neg = "-"
+ else:
+ neg = ""
+
+ if time >= 3600.0: # hours
+ hours = int(time / 3600.0)
+ time = time % 3600.0
+ if time >= 60.0: # mins
+ minutes = int(time / 60.0)
+ time = time % 60.0
+
+ seconds = int(time)
+ frames = int(round(math.floor(((time - seconds) * fps))))
+
+ return "%s%02d:%02d:%02d:%02d" % (neg, hours, minutes, seconds, frames)
+
+
+def smpte_from_frame(frame, fps=None, fps_base=None):
+ '''
+ Returns an SMPTE formatted string from the frame: "HH:MM:SS:FF".
+
+ If the fps and fps_base are not given the current scene is used.
+ '''
+
+ if fps is None:
+ fps = _bpy.context.scene.render.fps
+
+ if fps_base is None:
+ fps_base = _bpy.context.scene.render.fps_base
+
+ return smpte_from_seconds((frame * fps_base) / fps, fps)
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index 060de711637..9d6f5ce7b2f 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
from _bpy import types as bpy_types
-from Mathutils import Vector
+from mathutils import Vector
StructRNA = bpy_types.Struct.__bases__[0]
# StructRNA = bpy_types.Struct
@@ -29,15 +29,62 @@ class Context(StructRNA):
__slots__ = ()
def copy(self):
+ from types import BuiltinMethodType
new_context = {}
- generic_keys = StructRNA.__dict__.keys()
- for item in dir(self):
- if item not in generic_keys:
- new_context[item] = getattr(self, item)
+ generic_attrs = list(StructRNA.__dict__.keys()) + ["bl_rna", "rna_type", "copy"]
+ for attr in dir(self):
+ if not (attr.startswith("_") or attr in generic_attrs):
+ value = getattr(self, attr)
+ if type(value) != BuiltinMethodType:
+ new_context[attr] = value
return new_context
+class Library(bpy_types.ID):
+ __slots__ = ()
+
+ @property
+ def users_id(self):
+ """ID datablocks which use this library"""
+ import bpy
+
+ # See: readblenentry.c, IDTYPE_FLAGS_ISLINKABLE, we could make this an attribute in rna.
+ attr_links = "actions", "armatures", "brushes", "cameras", \
+ "curves", "gpencil", "groups", "images", \
+ "lamps", "lattices", "materials", "metaballs", \
+ "meshes", "node_groups", "objects", "scenes", \
+ "sounds", "textures", "texts", "fonts", "worlds"
+
+ return tuple(id_block for attr in attr_links for id_block in getattr(bpy.data, attr) if id_block.library == self)
+
+
+class Texture(bpy_types.ID):
+ __slots__ = ()
+
+ @property
+ def users_material(self):
+ """Materials that use this texture"""
+ import bpy
+ return tuple(mat for mat in bpy.data.materials if self in [slot.texture for slot in mat.texture_slots if slot])
+
+ @property
+ def users_object_modifier(self):
+ """Object modifiers that use this texture"""
+ import bpy
+ return tuple(obj for obj in bpy.data.objects if self in [mod.texture for mod in obj.modifiers if mod.type == 'DISPLACE'])
+
+
+class Group(bpy_types.ID):
+ __slots__ = ()
+
+ @property
+ def users_dupli_group(self):
+ """The dupli group this group is used in"""
+ import bpy
+ return tuple(obj for obj in bpy.data.objects if self == obj.dupli_group)
+
+
class Object(bpy_types.ID):
__slots__ = ()
@@ -45,21 +92,19 @@ class Object(bpy_types.ID):
def children(self):
"""All the children of this object"""
import bpy
- return [child for child in bpy.data.objects if child.parent == self]
+ return tuple(child for child in bpy.data.objects if child.parent == self)
@property
- def group_users(self):
+ def users_group(self):
"""The groups this object is in"""
import bpy
- name = self.name
- return [group for group in bpy.data.groups if name in group.objects]
+ return tuple(group for group in bpy.data.groups if self in group.objects[:])
@property
- def scene_users(self):
+ def users_scene(self):
"""The scenes this object is in"""
import bpy
- name = self.name
- return [scene for scene in bpy.data.scenes if name in scene.objects]
+ return tuple(scene for scene in bpy.data.scenes if self in scene.objects[:])
class _GenericBone:
@@ -95,19 +140,19 @@ class _GenericBone:
def x_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
- return self.matrix.rotation_part() * Vector(1.0, 0.0, 0.0)
+ return self.matrix.rotation_part() * Vector((1.0, 0.0, 0.0))
@property
def y_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
- return self.matrix.rotation_part() * Vector(0.0, 1.0, 0.0)
+ return self.matrix.rotation_part() * Vector((0.0, 1.0, 0.0))
@property
def z_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
- return self.matrix.rotation_part() * Vector(0.0, 0.0, 1.0)
+ return self.matrix.rotation_part() * Vector((0.0, 0.0, 1.0))
@property
def basename(self):
@@ -236,8 +281,8 @@ class EditBone(StructRNA, _GenericBone):
Transform the the bones head, tail, roll and envalope (when the matrix has a scale component).
Expects a 4x4 or 3x3 matrix.
"""
- from Mathutils import Vector
- z_vec = self.matrix.rotation_part() * Vector(0.0, 0.0, 1.0)
+ from mathutils import Vector
+ z_vec = self.matrix.rotation_part() * Vector((0.0, 0.0, 1.0))
self.tail = matrix * self.tail
self.head = matrix * self.head
scalar = matrix.median_scale
@@ -303,7 +348,7 @@ class Mesh(bpy_types.ID):
edge_face_count_dict = self.edge_face_count_dict
return [edge_face_count_dict.get(ed.key, 0) for ed in self.edges]
- def edge_loops(self, faces=None, seams=()):
+ def edge_loops_from_faces(self, faces=None, seams=()):
"""
Edge loops defined by faces
@@ -314,7 +359,7 @@ class Mesh(bpy_types.ID):
return a list of edge key lists
[ [(0,1), (4, 8), (3,8)], ...]
- optionaly, seams are edge keys that will be removed
+ return a list of edge vertex index lists
"""
OTHER_INDEX = 2, 3, 0, 1 # opposite face index
@@ -379,6 +424,70 @@ class Mesh(bpy_types.ID):
return edge_loops
+ def edge_loops_from_edges(self, edges=None):
+ """
+ Edge loops defined by edges
+
+ Takes me.edges or a list of edges and returns the edge loops
+
+ return a list of vertex indices.
+ [ [1, 6, 7, 2], ...]
+
+ closed loops have matching start and end values.
+ """
+ line_polys = []
+
+ # Get edges not used by a face
+ if edges is None:
+ edges = self.edges
+
+ if not hasattr(edges, "pop"):
+ edges = edges[:]
+
+ edge_dict = {ed.key: ed for ed in self.edges if ed.selected}
+
+ while edges:
+ current_edge = edges.pop()
+ vert_end, vert_start = current_edge.verts[:]
+ line_poly = [vert_start, vert_end]
+
+ ok = True
+ while ok:
+ ok = False
+ #for i, ed in enumerate(edges):
+ i = len(edges)
+ while i:
+ i -= 1
+ ed = edges[i]
+ v1, v2 = ed.verts
+ if v1 == vert_end:
+ line_poly.append(v2)
+ vert_end = line_poly[-1]
+ ok = 1
+ del edges[i]
+ # break
+ elif v2 == vert_end:
+ line_poly.append(v1)
+ vert_end = line_poly[-1]
+ ok = 1
+ del edges[i]
+ #break
+ elif v1 == vert_start:
+ line_poly.insert(0, v2)
+ vert_start = line_poly[0]
+ ok = 1
+ del edges[i]
+ # break
+ elif v2 == vert_start:
+ line_poly.insert(0, v1)
+ vert_start = line_poly[0]
+ ok = 1
+ del edges[i]
+ #break
+ line_polys.append(line_poly)
+
+ return line_polys
+
class MeshEdge(StructRNA):
__slots__ = ()
@@ -410,6 +519,24 @@ class MeshFace(StructRNA):
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])
+class Text(bpy_types.ID):
+ __slots__ = ()
+
+ def as_string(self):
+ """Return the text as a string."""
+ return "\n".join(line.line for line in self.lines)
+
+ def from_string(self, string):
+ """Replace text with this string."""
+ self.clear()
+ self.write(string)
+
+ @property
+ def users_logic(self):
+ """Logic bricks that use this text"""
+ import bpy
+ return tuple(obj for obj in bpy.data.objects if self in [cont.text for cont in obj.game.controllers if cont.type == 'PYTHON'])
+
import collections
@@ -490,9 +617,9 @@ class Header(StructRNA, _GenericUI):
class Menu(StructRNA, _GenericUI):
__slots__ = ()
- def path_menu(self, searchpaths, operator):
+ def path_menu(self, searchpaths, operator, props_default={}):
layout = self.layout
- # hard coded to set the operators 'path' to the filename.
+ # hard coded to set the operators 'filepath' to the filename.
import os
import bpy.utils
@@ -501,17 +628,26 @@ class Menu(StructRNA, _GenericUI):
# collect paths
files = []
- for path in searchpaths:
- files.extend([(f, os.path.join(path, f)) for f in os.listdir(path)])
+ for directory in searchpaths:
+ files.extend([(f, os.path.join(directory, f)) for f in os.listdir(directory)])
files.sort()
- for f, path in files:
+ for f, filepath in files:
if f.startswith("."):
continue
- layout.operator(operator, text=bpy.utils.display_name(f)).path = path
+ preset_name = bpy.utils.display_name(f)
+ props = layout.operator(operator, text=preset_name)
+
+ for attr, value in props_default.items():
+ setattr(props, attr, value)
+
+ props.filepath = filepath
+ if operator == "script.execute_preset":
+ props.menu_idname = self.bl_idname
+ props.preset_name = preset_name
def draw_preset(self, context):
"""Define these on the subclass
diff --git a/release/scripts/modules/console/complete_calltip.py b/release/scripts/modules/console/complete_calltip.py
index c4687b4f10b..87fac9f4c07 100644
--- a/release/scripts/modules/console/complete_calltip.py
+++ b/release/scripts/modules/console/complete_calltip.py
@@ -124,7 +124,7 @@ def get_argspec(func, strip_self=True, doc=None, source=None):
if source is None:
try:
source = inspect.getsource(func)
- except TypeError:
+ except (TypeError, IOError):
source = ''
if source:
match = re.search(DEF_SOURCE % func_name, source, RE_FLAG)
diff --git a/release/scripts/modules/console/complete_import.py b/release/scripts/modules/console/complete_import.py
index 875c557f497..4b50cf6deb8 100644
--- a/release/scripts/modules/console/complete_import.py
+++ b/release/scripts/modules/console/complete_import.py
@@ -32,6 +32,7 @@ changes have been made:
- limit list of modules to prefix in case of "from w"
- sorted modules
- added sphinx documentation
+- complete() returns a blank list of the module isnt found
"""
@@ -183,3 +184,8 @@ def complete(line):
if len(words) >= 3 and words[0] == 'from':
mod = words[1]
return filter_prefix(try_import(mod), words[-1])
+
+ # get here if the import is not found
+ # import invalidmodule
+ # ^, in this case return nothing
+ return []
diff --git a/release/scripts/modules/graphviz_export.py b/release/scripts/modules/graphviz_export.py
index 1e7c7adfb7f..900d69670d5 100644
--- a/release/scripts/modules/graphviz_export.py
+++ b/release/scripts/modules/graphviz_export.py
@@ -51,13 +51,13 @@ def compat_str(text, line_length=0):
return text
-def graph_armature(obj, path, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True, XTRA_INFO=True):
+def graph_armature(obj, filepath, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True, XTRA_INFO=True):
CONSTRAINTS = DRIVERS = True
- fileobject = open(path, "w")
+ fileobject = open(filepath, "w")
fw = fileobject.write
fw(header)
- fw('label = "%s::%s" ;' % (bpy.data.filename.split("/")[-1].split("\\")[-1], obj.name))
+ fw('label = "%s::%s" ;' % (bpy.data.filepath.split("/")[-1].split("\\")[-1], obj.name))
arm = obj.data
@@ -157,17 +157,18 @@ def graph_armature(obj, path, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True,
pbone = rna_path_as_pbone(rna_path)
if pbone:
- for target in fcurve_driver.driver.targets:
- pbone_target = rna_path_as_pbone(target.data_path)
- rna_path_target = target.data_path
- if pbone_target:
- opts = ['dir=forward', "weight=1", "arrowhead=normal", "arrowtail=none", "constraint=false", 'color="blue"', "labelfontsize=4"] # ,
- display_source = rna_path.replace("pose.bones", "")
- display_target = rna_path_target.replace("pose.bones", "")
- if XTRA_INFO:
- label = "%s\\n%s" % (display_source, display_target)
- opts.append('label="%s"' % compat_str(label))
- fw('"%s" -> "%s" [%s] ;\n' % (pbone_target.name, pbone.name, ','.join(opts)))
+ for var in fcurve_driver.driver.variables:
+ for target in var.targets:
+ pbone_target = rna_path_as_pbone(target.data_path)
+ rna_path_target = target.data_path
+ if pbone_target:
+ opts = ['dir=forward', "weight=1", "arrowhead=normal", "arrowtail=none", "constraint=false", 'color="blue"', "labelfontsize=4"] # ,
+ display_source = rna_path.replace("pose.bones", "")
+ display_target = rna_path_target.replace("pose.bones", "")
+ if XTRA_INFO:
+ label = "%s\\n%s" % (display_source, display_target)
+ opts.append('label="%s"' % compat_str(label))
+ fw('"%s" -> "%s" [%s] ;\n' % (pbone_target.name, pbone.name, ','.join(opts)))
fw(footer)
fileobject.close()
@@ -177,7 +178,7 @@ def graph_armature(obj, path, FAKE_PARENT=True, CONSTRAINTS=True, DRIVERS=True,
import sys
sys.stdout.flush()
'''
- print("\nSaved:", path)
+ print("\nSaved:", filepath)
return True
if __name__ == "__main__":
diff --git a/release/scripts/modules/rigify/__init__.py b/release/scripts/modules/rigify/__init__.py
index 895afd20d59..ef8f62ad058 100644
--- a/release/scripts/modules/rigify/__init__.py
+++ b/release/scripts/modules/rigify/__init__.py
@@ -19,17 +19,17 @@
# <pep8 compliant>
import bpy
-from Mathutils import Vector
+from mathutils import Vector
# TODO, have these in a more general module
from rna_prop_ui import rna_idprop_ui_prop_get
SPECIAL_TYPES = "root",
LAYER_TYPES = "main", "extra", "ik", "fk"
-ORG_LAYERS = [n==31 for n in range(0,32)]
-MCH_LAYERS = [n==30 for n in range(0,32)]
-DEF_LAYERS = [n==29 for n in range(0,32)]
-ROOT_LAYERS = [n==28 for n in range(0,32)]
+ORG_LAYERS = [n == 31 for n in range(0, 32)]
+MCH_LAYERS = [n == 30 for n in range(0, 32)]
+DEF_LAYERS = [n == 29 for n in range(0, 32)]
+ROOT_LAYERS = [n == 28 for n in range(0, 32)]
ORG_PREFIX = "ORG-"
MCH_PREFIX = "MCH-"
@@ -38,7 +38,6 @@ DEF_PREFIX = "DEF-"
WGT_PREFIX = "WGT-"
-
class RigifyError(Exception):
"""Exception raised for errors in the metarig.
"""
@@ -235,12 +234,12 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True):
bone_gen = obj.pose.bones[bone.name]
# Rotation mode and transform locks
- bone_gen.rotation_mode = bone.rotation_mode
- bone_gen.lock_rotation = tuple(bone.lock_rotation)
- bone_gen.lock_rotation_w = bone.lock_rotation_w
+ bone_gen.rotation_mode = bone.rotation_mode
+ bone_gen.lock_rotation = tuple(bone.lock_rotation)
+ bone_gen.lock_rotation_w = bone.lock_rotation_w
bone_gen.lock_rotations_4d = bone.lock_rotations_4d
- bone_gen.lock_location = tuple(bone.lock_location)
- bone_gen.lock_scale = tuple(bone.lock_scale)
+ bone_gen.lock_location = tuple(bone.lock_location)
+ bone_gen.lock_scale = tuple(bone.lock_scale)
# Custom properties
for prop in bone.keys():
@@ -456,12 +455,12 @@ def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True):
bone.deform = True
else:
# Assign bone appearance if there is a widget for it
- obj.pose.bones[bone_name].custom_shape = context.scene.objects.get(WGT_PREFIX+bone_name)
+ obj.pose.bones[bone_name].custom_shape = context.scene.objects.get(WGT_PREFIX + bone_name)
layer_tot[:] = [max(lay) for lay in zip(layer_tot, bone.layer)]
# Only for demo'ing
- layer_show = [a and not (b or c or d) for a,b,c,d in zip(layer_tot, ORG_LAYERS, MCH_LAYERS, DEF_LAYERS)]
+ layer_show = [a and not (b or c or d) for a, b, c, d in zip(layer_tot, ORG_LAYERS, MCH_LAYERS, DEF_LAYERS)]
arm.layer = layer_show
@@ -535,7 +534,7 @@ def generate_test_all(context, GRAPH=False):
new_objects = rigify.generate_test(context)
if GRAPH:
- base_name = os.path.splitext(bpy.data.filename)[0]
+ base_name = os.path.splitext(bpy.data.filepath)[0]
for obj, obj_new in new_objects:
for obj in (obj, obj_new):
fn = base_name + "-" + bpy.utils.clean_name(obj.name)
diff --git a/release/scripts/modules/rigify/arm_biped.py b/release/scripts/modules/rigify/arm_biped.py
index 7aa6a37304a..7a99eb5d80a 100644
--- a/release/scripts/modules/rigify/arm_biped.py
+++ b/release/scripts/modules/rigify/arm_biped.py
@@ -23,7 +23,7 @@ from math import radians, pi
from rigify import RigifyError, ORG_PREFIX
from rigify_utils import bone_class_instance, copy_bone_simple, add_pole_target_bone, add_stretch_to, blend_bone_list, get_side_name, get_base_name
from rna_prop_ui import rna_idprop_ui_prop_get
-from Mathutils import Vector
+from mathutils import Vector
METARIG_NAMES = "shoulder", "arm", "forearm", "hand"
@@ -192,7 +192,7 @@ def fk(obj, definitions, base_names, options):
# shoulder is used as a hinge
fk_chain.rename("shoulder", "MCH-%s_hinge" % base_names[mt.arm])
- fk_chain.shoulder_e.translate(Vector(0.0, fk_chain.shoulder_e.length / 2, 0.0))
+ fk_chain.shoulder_e.translate(Vector((0.0, fk_chain.shoulder_e.length / 2, 0.0)))
# upper arm constrains to this.
ex.socket_e = copy_bone_simple(arm, mt.arm, "MCH-%s_socket" % base_names[mt.arm])
@@ -240,11 +240,11 @@ def fk(obj, definitions, base_names, options):
con.name = "hinge"
con.target = obj
con.subtarget = mt.shoulder
- driver_fcurve = con.driver_add("influence", 0)
+ driver_fcurve = con.driver_add("influence")
driver = driver_fcurve.driver
- controller_path = fk_chain.arm_p.path_to_id()
+ controller_path = fk_chain.arm_p.path_from_id()
# add custom prop
fk_chain.arm_p["hinge"] = 0.0
prop = rna_idprop_ui_prop_get(fk_chain.arm_p, "hinge", create=True)
diff --git a/release/scripts/modules/rigify/copy.py b/release/scripts/modules/rigify/copy.py
index 907435da2b4..e0bff555a9b 100644
--- a/release/scripts/modules/rigify/copy.py
+++ b/release/scripts/modules/rigify/copy.py
@@ -110,4 +110,3 @@ def main(obj, bone_definition, base_names, options):
deform(obj, bone_definition, base_names, options)
return (cpy,)
-
diff --git a/release/scripts/modules/rigify/eye_balls.py b/release/scripts/modules/rigify/eye_balls.py
index 9cb3c8229b0..48f0448dfb3 100644
--- a/release/scripts/modules/rigify/eye_balls.py
+++ b/release/scripts/modules/rigify/eye_balls.py
@@ -20,13 +20,92 @@
import bpy
from rna_prop_ui import rna_idprop_ui_prop_get
-from Mathutils import Vector
+from mathutils import Vector
from rigify import RigifyError
from rigify_utils import copy_bone_simple
#METARIG_NAMES = ("cpy",)
RIG_TYPE = "eye_balls"
+def addget_shape_key(obj, name="Key"):
+ """ Fetches a shape key, or creates it if it doesn't exist
+ """
+ # Create a shapekey set if it doesn't already exist
+ if obj.data.shape_keys is None:
+ shape = obj.add_shape_key(name="Basis", from_mix=False)
+ obj.active_shape_key_index = 0
+
+ # Get the shapekey, or create it if it doesn't already exist
+ if name in obj.data.shape_keys.keys:
+ shape_key = obj.data.shape_keys.keys[name]
+ else:
+ shape_key = obj.add_shape_key(name=name, from_mix=False)
+
+ return shape_key
+
+
+def addget_shape_key_driver(obj, name="Key"):
+ """ Fetches the driver for the shape key, or creates it if it doesn't
+ already exist.
+ """
+ driver_path = 'keys["' + name + '"].value'
+ fcurve = None
+ driver = None
+ new = False
+ if obj.data.shape_keys.animation_data is not None:
+ for driver_s in obj.data.shape_keys.animation_data.drivers:
+ if driver_s.data_path == driver_path:
+ fcurve = driver_s
+ if fcurve == None:
+ fcurve = obj.data.shape_keys.keys[name].driver_add("value")
+ fcurve.driver.type = 'AVERAGE'
+ new = True
+
+ return fcurve, new
+
+
+def create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression):
+ """ Creates/gets a shape key and sets up a driver for it.
+
+ obj = armature object
+ bone = driving bone name
+ meshes = list of meshes to create the shapekey/driver on
+ shape_name = name of the shape key
+ var_name = name of the driving variable
+ var_path = path to the property on the bone to drive with
+ expression = python expression for the driver
+ """
+ pb = obj.pose.bones
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ for mesh_name in meshes:
+ mesh_obj = bpy.data.objects[mesh_name]
+
+ # Add/get the shape key
+ shape = addget_shape_key(mesh_obj, name=shape_name)
+
+ # Add/get the shape key driver
+ fcurve, a = addget_shape_key_driver(mesh_obj, name=shape_name)
+
+ # Set up the driver
+ driver = fcurve.driver
+ driver.type = 'SCRIPTED'
+ driver.expression = expression
+
+ # Get the variable, or create it if it doesn't already exist
+ if var_name in driver.variables:
+ var = driver.variables[var_name]
+ else:
+ var = driver.variables.new()
+ var.name = var_name
+
+ # Set up the variable
+ var.type = "SINGLE_PROP"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = 'pose.bones["' + bone + '"]' + var_path
+
+
def mark_actions():
for action in bpy.data.actions:
action.tag = True
@@ -120,6 +199,12 @@ def control(obj, definitions, base_names, options):
head = definitions[0]
eye_target = definitions[1]
+ # Get list of pupil mesh objects
+ if "mesh" in options:
+ pupil_meshes = options["mesh"].replace(" ", "").split(",")
+ else:
+ pupil_meshes = []
+
# Get list of eyes
if "eyes" in options:
eye_base_names = options["eyes"].replace(" ", "").split(",")
@@ -132,7 +217,7 @@ def control(obj, definitions, base_names, options):
eyes += ["ORG-"+name]
# Get the average position of the eyes
- center = Vector(0,0,0)
+ center = Vector((0, 0, 0))
for eye in eyes:
center += eb[eye].head
if len(eyes) != 0:
@@ -197,7 +282,7 @@ def control(obj, definitions, base_names, options):
prop["min"] = 0.0
prop["max"] = 1.0
- free_driver_path = pb[target_ctrl].path_to_id() + '["free"]'
+ free_driver_path = pb[target_ctrl].path_from_id() + '["free"]'
# Constraints
# Mind's eye tracks eye target control
@@ -210,7 +295,7 @@ def control(obj, definitions, base_names, options):
con.target = obj
con.subtarget = head
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
mod = fcurve.modifiers[0]
@@ -241,11 +326,55 @@ def control(obj, definitions, base_names, options):
con.subtarget = target_ctrl
con.action = spread_action
con.transform_channel = 'SCALE_X'
- con.start_frame = -20
- con.end_frame = 20
+ con.frame_start = -20
+ con.frame_end = 20
con.minimum = 0.0
con.maximum = 2.0
con.target_space = 'LOCAL'
+
+
+ # Get/create the shape keys and drivers for pupil dilation
+ shape_names = ["PUPILS-dilate_wide", "PUPILS-dilate_narrow"]
+ slider_name = "pupil_dilate"
+
+ # Set up the custom property on the bone
+ prop = rna_idprop_ui_prop_get(pb[target_ctrl], slider_name, create=True)
+ pb[target_ctrl][slider_name] = 0.0
+ prop["min"] = 0.0
+ prop["max"] = 1.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+ if len(shape_names) > 1:
+ prop["min"] = -1.0
+ prop["soft_min"] = -1.0
+
+ # Add the shape drivers
+ # Positive
+ if shape_names[0] != "":
+ # Set up the variables for creating the shape key driver
+ shape_name = shape_names[0]
+ var_name = slider_name.replace(".", "_").replace("-", "_")
+ var_path = '["' + slider_name + '"]'
+ if slider_name + "_fac" in options:
+ fac = options[slider_name + "_fac"]
+ else:
+ fac = 1.0
+ expression = var_name + " * " + str(fac)
+ # Create the shape key driver
+ create_shape_and_driver(obj, target_ctrl, pupil_meshes, shape_name, var_name, var_path, expression)
+ # Negative
+ if shape_names[0] != "" and len(shape_names) > 1:
+ # Set up the variables for creating the shape key driver
+ shape_name = shape_names[1]
+ var_name = slider_name.replace(".", "_").replace("-", "_")
+ var_path = '["' + slider_name + '"]'
+ if slider_name + "_fac" in options:
+ fac = options[slider_name + "_fac"]
+ else:
+ fac = 1.0
+ expression = var_name + " * " + str(fac) + " * -1"
+ # Create the shape key driver
+ create_shape_and_driver(obj, target_ctrl, pupil_meshes, shape_name, var_name, var_path, expression)
diff --git a/release/scripts/modules/rigify/eye_lid.py b/release/scripts/modules/rigify/eye_lid.py
index 39804e6b704..bb9749011c2 100644
--- a/release/scripts/modules/rigify/eye_lid.py
+++ b/release/scripts/modules/rigify/eye_lid.py
@@ -21,7 +21,7 @@
import bpy
from rna_prop_ui import rna_idprop_ui_prop_get
from math import acos
-from Mathutils import Vector
+from mathutils import Vector
from rigify import RigifyError
from rigify_utils import copy_bone_simple
@@ -299,14 +299,15 @@ def control(obj, definitions, base_names, options):
lid8 = copy_bone_simple(obj.data, definitions[9], base_names[definitions[9]]).name
size = eb[lid1].length
- eb[lid1].tail = eb[lid1].head + Vector(0,size,0)
- eb[lid2].tail = eb[lid2].head + Vector(0,size,0)
- eb[lid3].tail = eb[lid3].head + Vector(0,size,0)
- eb[lid4].tail = eb[lid4].head + Vector(0,size,0)
- eb[lid5].tail = eb[lid5].head + Vector(0,size,0)
- eb[lid6].tail = eb[lid6].head + Vector(0,size,0)
- eb[lid7].tail = eb[lid7].head + Vector(0,size,0)
- eb[lid8].tail = eb[lid8].head + Vector(0,size,0)
+ size_y = Vector(0.0, size, 0.0)
+ eb[lid1].tail = eb[lid1].head + size_y
+ eb[lid2].tail = eb[lid2].head + size_y
+ eb[lid3].tail = eb[lid3].head + size_y
+ eb[lid4].tail = eb[lid4].head + size_y
+ eb[lid5].tail = eb[lid5].head + size_y
+ eb[lid6].tail = eb[lid6].head + size_y
+ eb[lid7].tail = eb[lid7].head + size_y
+ eb[lid8].tail = eb[lid8].head + size_y
eb[lid1].roll = 0
eb[lid2].roll = 0
@@ -355,7 +356,7 @@ def control(obj, definitions, base_names, options):
prop["min"] = 0.0
prop["max"] = 1.0
- close_driver_path = pb[upper_lid_ctrl].path_to_id() + '["close_action"]'
+ close_driver_path = pb[upper_lid_ctrl].path_from_id() + '["close_action"]'
# Constraints
@@ -433,12 +434,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = upper_lid_ctrl
con.action = close_action
con.transform_channel = 'LOCATION_Y'
- con.start_frame = -30
- con.end_frame = 30
+ con.frame_start = -30
+ con.frame_end = 30
con.minimum = -distance*2
con.maximum = distance
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -452,12 +453,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = upper_lid_ctrl
con.action = close_action
con.transform_channel = 'LOCATION_Y'
- con.start_frame = -30
- con.end_frame = 30
+ con.frame_start = -30
+ con.frame_end = 30
con.minimum = -distance*2
con.maximum = distance
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -470,12 +471,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = upper_lid_ctrl
con.action = close_action
con.transform_channel = 'LOCATION_Y'
- con.start_frame = -30
- con.end_frame = 30
+ con.frame_start = -30
+ con.frame_end = 30
con.minimum = -distance*2
con.maximum = distance
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -488,12 +489,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = upper_lid_ctrl
con.action = close_action
con.transform_channel = 'LOCATION_Y'
- con.start_frame = -30
- con.end_frame = 30
+ con.frame_start = -30
+ con.frame_end = 30
con.minimum = -distance*2
con.maximum = distance
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -506,12 +507,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = upper_lid_ctrl
con.action = close_action
con.transform_channel = 'LOCATION_Y'
- con.start_frame = -30
- con.end_frame = 30
+ con.frame_start = -30
+ con.frame_end = 30
con.minimum = -distance*2
con.maximum = distance
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -525,12 +526,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = lower_lid_ctrl
con.action = close_action
con.transform_channel = 'LOCATION_Y'
- con.start_frame = -30
- con.end_frame = 30
+ con.frame_start = -30
+ con.frame_end = 30
con.minimum = -distance
con.maximum = distance*2
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -543,12 +544,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = lower_lid_ctrl
con.action = close_action
con.transform_channel = 'LOCATION_Y'
- con.start_frame = -30
- con.end_frame = 30
+ con.frame_start = -30
+ con.frame_end = 30
con.minimum = -distance
con.maximum = distance*2
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -561,12 +562,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = lower_lid_ctrl
con.action = close_action
con.transform_channel = 'LOCATION_Y'
- con.start_frame = -30
- con.end_frame = 30
+ con.frame_start = -30
+ con.frame_end = 30
con.minimum = -distance
con.maximum = distance*2
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -579,12 +580,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = lower_lid_ctrl
con.action = close_action
con.transform_channel = 'LOCATION_Y'
- con.start_frame = -30
- con.end_frame = 30
+ con.frame_start = -30
+ con.frame_end = 30
con.minimum = -distance
con.maximum = distance*2
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -597,12 +598,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = lower_lid_ctrl
con.action = close_action
con.transform_channel = 'LOCATION_Y'
- con.start_frame = -30
- con.end_frame = 30
+ con.frame_start = -30
+ con.frame_end = 30
con.minimum = -distance
con.maximum = distance*2
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
diff --git a/release/scripts/modules/rigify/finger_curl.py b/release/scripts/modules/rigify/finger_curl.py
index f6574fc75bb..63f1816012b 100644
--- a/release/scripts/modules/rigify/finger_curl.py
+++ b/release/scripts/modules/rigify/finger_curl.py
@@ -57,31 +57,20 @@ def metarig_template():
def metarig_definition(obj, orig_bone_name):
'''
The bone given is the first in a chain
- Expects a chain of at least 2 children.
+ Expects a chain with at least 1 child of the same base name.
eg.
- finger -> finger_01 -> finger_02
+ finger_01 -> finger_02
'''
- bone_definition = []
-
orig_bone = obj.data.bones[orig_bone_name]
- bone_definition.append(orig_bone.name)
-
- bone = orig_bone
- chain = 0
- while chain < 2: # first 2 bones only have 1 child
- children = bone.children
-
- if len(children) != 1:
- raise RigifyError("expected the chain to have 2 children from bone '%s' without a fork" % orig_bone_name)
- bone = children[0]
- bone_definition.append(bone.name) # finger_02, finger_03
- chain += 1
-
- if len(bone_definition) != len(METARIG_NAMES):
- raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
-
+ bone_definition = [orig_bone.name]
+
+ bone_definition.extend([child.name for child in orig_bone.children_recursive_basename])
+
+ if len(bone_definition) < 2:
+ raise RigifyError("expected the chain to have at least 1 child from bone '%s' without the same base name" % orig_bone_name)
+
return bone_definition
@@ -90,6 +79,8 @@ def deform(obj, definitions, base_names, options):
"""
bpy.ops.object.mode_set(mode='EDIT')
+ three_digits = True if len(definitions) > 2 else False
+
# Create base digit bones: two bones, each half of the base digit.
f1a = copy_bone_simple(obj.data, definitions[0], "DEF-%s.01" % base_names[definitions[0]], parent=True)
f1b = copy_bone_simple(obj.data, definitions[0], "DEF-%s.02" % base_names[definitions[0]], parent=True)
@@ -102,13 +93,15 @@ def deform(obj, definitions, base_names, options):
# Create the other deform bones.
f2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s" % base_names[definitions[1]], parent=True)
- f3 = copy_bone_simple(obj.data, definitions[2], "DEF-%s" % base_names[definitions[2]], parent=True)
+ if three_digits:
+ f3 = copy_bone_simple(obj.data, definitions[2], "DEF-%s" % base_names[definitions[2]], parent=True)
# Store names before leaving edit mode
f1a_name = f1a.name
f1b_name = f1b.name
f2_name = f2.name
- f3_name = f3.name
+ if three_digits:
+ f3_name = f3.name
# Leave edit mode
bpy.ops.object.mode_set(mode='OBJECT')
@@ -117,7 +110,8 @@ def deform(obj, definitions, base_names, options):
f1a = obj.pose.bones[f1a_name]
f1b = obj.pose.bones[f1b_name]
f2 = obj.pose.bones[f2_name]
- f3 = obj.pose.bones[f3_name]
+ if three_digits:
+ f3 = obj.pose.bones[f3_name]
# Constrain the base digit's bones
con = f1a.constraints.new('DAMPED_TRACK')
@@ -141,15 +135,18 @@ def deform(obj, definitions, base_names, options):
con.target = obj
con.subtarget = definitions[1]
- con = f3.constraints.new('COPY_TRANSFORMS')
- con.name = "copy_transforms"
- con.target = obj
- con.subtarget = definitions[2]
+ if three_digits:
+ con = f3.constraints.new('COPY_TRANSFORMS')
+ con.name = "copy_transforms"
+ con.target = obj
+ con.subtarget = definitions[2]
def main(obj, bone_definition, base_names, options):
# *** EDITMODE
bpy.ops.object.mode_set(mode='EDIT')
+
+ three_digits = True if len(bone_definition) > 2 else False
# get assosiated data
arm = obj.data
@@ -159,7 +156,8 @@ def main(obj, bone_definition, base_names, options):
org_f1 = bone_definition[0] # Original finger bone 01
org_f2 = bone_definition[1] # Original finger bone 02
- org_f3 = bone_definition[2] # Original finger bone 03
+ if three_digits:
+ org_f3 = bone_definition[2] # Original finger bone 03
# Check options
if "bend_ratio" in options:
@@ -179,7 +177,10 @@ def main(obj, bone_definition, base_names, options):
# Create the control bone
base_name = base_names[bone_definition[0]].split(".", 1)[0]
- tot_len = eb[org_f1].length + eb[org_f2].length + eb[org_f3].length
+ if three_digits:
+ tot_len = eb[org_f1].length + eb[org_f2].length + eb[org_f3].length
+ else:
+ tot_len = eb[org_f1].length + eb[org_f2].length
control = copy_bone_simple(arm, bone_definition[0], base_name + get_side_name(base_names[bone_definition[0]]), parent=True).name
eb[control].connected = eb[org_f1].connected
eb[control].parent = eb[org_f1].parent
@@ -188,26 +189,30 @@ def main(obj, bone_definition, base_names, options):
# Create secondary control bones
f1 = copy_bone_simple(arm, bone_definition[0], base_names[bone_definition[0]]).name
f2 = copy_bone_simple(arm, bone_definition[1], base_names[bone_definition[1]]).name
- f3 = copy_bone_simple(arm, bone_definition[2], base_names[bone_definition[2]]).name
+ if three_digits:
+ f3 = copy_bone_simple(arm, bone_definition[2], base_names[bone_definition[2]]).name
# Create driver bones
df1 = copy_bone_simple(arm, bone_definition[0], "MCH-" + base_names[bone_definition[0]]).name
eb[df1].length /= 2
df2 = copy_bone_simple(arm, bone_definition[1], "MCH-" + base_names[bone_definition[1]]).name
eb[df2].length /= 2
- df3 = copy_bone_simple(arm, bone_definition[2], "MCH-" + base_names[bone_definition[2]]).name
- eb[df3].length /= 2
+ if three_digits:
+ df3 = copy_bone_simple(arm, bone_definition[2], "MCH-" + base_names[bone_definition[2]]).name
+ eb[df3].length /= 2
# Set parents of the bones, interleaving the driver bones with the secondary control bones
- eb[f3].connected = False
- eb[df3].connected = False
+ if three_digits:
+ eb[f3].connected = False
+ eb[df3].connected = False
eb[f2].connected = False
eb[df2].connected = False
eb[f1].connected = False
eb[df1].connected = eb[org_f1].connected
- eb[f3].parent = eb[df3]
- eb[df3].parent = eb[f2]
+ if three_digits:
+ eb[f3].parent = eb[df3]
+ eb[df3].parent = eb[f2]
eb[f2].parent = eb[df2]
eb[df2].parent = eb[f1]
eb[f1].parent = eb[df1]
@@ -234,12 +239,15 @@ def main(obj, bone_definition, base_names, options):
pb[control].lock_scale = True, False, True
pb[f1].rotation_mode = 'YZX'
pb[f2].rotation_mode = 'YZX'
- pb[f3].rotation_mode = 'YZX'
+ if three_digits:
+ pb[f3].rotation_mode = 'YZX'
pb[f1].lock_location = True, True, True
pb[f2].lock_location = True, True, True
- pb[f3].lock_location = True, True, True
+ if three_digits:
+ pb[f3].lock_location = True, True, True
pb[df2].rotation_mode = 'YZX'
- pb[df3].rotation_mode = 'YZX'
+ if three_digits:
+ pb[df3].rotation_mode = 'YZX'
# Add the bend_ratio property to the control bone
pb[control]["bend_ratio"] = bend_ratio
@@ -271,18 +279,19 @@ def main(obj, bone_definition, base_names, options):
con.target = obj
con.subtarget = f2
- con = pb[org_f3].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = f3
+ if three_digits:
+ con = pb[org_f3].constraints.new('COPY_TRANSFORMS')
+ con.target = obj
+ con.subtarget = f3
if make_hinge:
con = pb[hinge].constraints.new('COPY_TRANSFORMS')
con.target = obj
con.subtarget = bb[org_f1].parent.name
- hinge_driver_path = pb[control].path_to_id() + '["hinge"]'
+ hinge_driver_path = pb[control].path_from_id() + '["hinge"]'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
var = driver.variables.new()
driver.type = 'AVERAGE'
@@ -301,10 +310,15 @@ def main(obj, bone_definition, base_names, options):
con.subtarget = socket
# Create the drivers for the driver bones (control bone scale rotates driver bones)
- controller_path = pb[control].path_to_id() # 'pose.bones["%s"]' % control_bone_name
+ controller_path = pb[control].path_from_id() # 'pose.bones["%s"]' % control_bone_name
+
+ if three_digits:
+ finger_digits = [df2, df3]
+ else:
+ finger_digits = [df2]
i = 0
- for bone in [df2, df3]:
+ for bone in finger_digits:
# XXX - todo, any number
if i == 2:
@@ -334,10 +348,13 @@ def main(obj, bone_definition, base_names, options):
var.targets[0].data_path = controller_path + '["bend_ratio"]'
# XXX - todo, any number
- if i == 0:
- driver.expression = '(-scale+1.0)*pi*2.0*(1.0-br)'
- elif i == 1:
- driver.expression = '(-scale+1.0)*pi*2.0*br'
+ if three_digits:
+ if i == 0:
+ driver.expression = '(-scale+1.0)*pi*2.0*(1.0-br)'
+ elif i == 1:
+ driver.expression = '(-scale+1.0)*pi*2.0*br'
+ else:
+ driver.expression = driver.expression = '(-scale+1.0)*pi*2.0'
i += 1
@@ -346,11 +363,16 @@ def main(obj, bone_definition, base_names, options):
layer = [n==options["ex_layer"] for n in range(0,32)]
else:
layer = list(arm.bones[bone_definition[0]].layer)
- for bone_name in [f1, f2, f3]:
- arm.bones[bone_name].layer = layer
+ #for bone_name in [f1, f2, f3]:
+ # arm.bones[bone_name].layer = layer
+ arm.bones[f1].layer = layer
+ arm.bones[f2].layer = layer
+ if three_digits:
+ arm.bones[f3].layer = layer
layer = list(arm.bones[bone_definition[0]].layer)
bb[control].layer = layer
# no blending the result of this
return None
+
diff --git a/release/scripts/modules/rigify/leg_biped.py b/release/scripts/modules/rigify/leg_biped.py
index 40d2ea0c4f2..53028986873 100644
--- a/release/scripts/modules/rigify/leg_biped.py
+++ b/release/scripts/modules/rigify/leg_biped.py
@@ -201,7 +201,7 @@ def ik(obj, bone_definition, base_names, options):
ik.knee_target_e.local_location = False
# roll the bone to point up... could also point in the same direction as ik.foot_roll
- # ik.foot_roll_02_e.matrix * Vector(0.0, 0.0, 1.0) # ACK!, no rest matrix in editmode
+ # ik.foot_roll_02_e.matrix * Vector((0.0, 0.0, 1.0)) # ACK!, no rest matrix in editmode
ik.foot_roll_01_e.align_roll((0.0, 0.0, -1.0))
bpy.ops.object.mode_set(mode='OBJECT')
@@ -227,7 +227,7 @@ def ik(obj, bone_definition, base_names, options):
con = ik_chain.shin_p.constraints.new('IK')
con.chain_length = 2
con.iterations = 500
- con.pole_angle = -pi/2
+ con.pole_angle = -pi / 2.0
con.use_tail = True
con.use_stretch = True
con.use_target = True
@@ -265,7 +265,7 @@ def ik(obj, bone_definition, base_names, options):
# last step setup layers
if "ik_layer" in options:
- layer = [n==options["ik_layer"] for n in range(0,32)]
+ layer = [n == options["ik_layer"] for n in range(0, 32)]
else:
layer = list(mt_chain.thigh_b.layer)
for attr in ik_chain.attr_names:
@@ -279,7 +279,7 @@ def ik(obj, bone_definition, base_names, options):
def fk(obj, bone_definition, base_names, options):
- from Mathutils import Vector
+ from mathutils import Vector
arm = obj.data
# these account for all bones in METARIG_NAMES
@@ -298,7 +298,7 @@ def fk(obj, bone_definition, base_names, options):
ex.thigh_socket_e = copy_bone_simple(arm, mt_chain.thigh, "MCH-%s_socket" % base_names[mt_chain.thigh], parent=True)
ex.thigh_socket = ex.thigh_socket_e.name
- ex.thigh_socket_e.tail = ex.thigh_socket_e.head + Vector(0.0, 0.0, ex.thigh_socket_e.length / 4.0)
+ ex.thigh_socket_e.tail = ex.thigh_socket_e.head + Vector((0.0, 0.0, ex.thigh_socket_e.length / 4.0))
ex.thigh_hinge_e = copy_bone_simple(arm, mt.hips, "MCH-%s_hinge" % base_names[mt_chain.thigh], parent=False)
ex.thigh_hinge = ex.thigh_hinge_e.name
@@ -349,9 +349,9 @@ def fk(obj, bone_definition, base_names, options):
con.subtarget = mt.hips
# add driver
- hinge_driver_path = fk_chain.thigh_p.path_to_id() + '["hinge"]'
+ hinge_driver_path = fk_chain.thigh_p.path_from_id() + '["hinge"]'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
var = driver.variables.new()
driver.type = 'AVERAGE'
@@ -368,7 +368,7 @@ def fk(obj, bone_definition, base_names, options):
# last step setup layers
if "fk_layer" in options:
- layer = [n==options["fk_layer"] for n in range(0,32)]
+ layer = [n == options["fk_layer"] for n in range(0, 32)]
else:
layer = list(mt_chain.thigh_b.layer)
for attr in fk_chain.attr_names:
@@ -499,4 +499,3 @@ def main(obj, bone_definition, base_names, options):
bpy.ops.object.mode_set(mode='OBJECT')
blend_bone_list(obj, bone_definition + [None], bones_fk, bones_ik, target_bone=bones_ik[6], target_prop="ik", blend_default=1.0)
-
diff --git a/release/scripts/modules/rigify/leg_quadruped.py b/release/scripts/modules/rigify/leg_quadruped.py
index c21680740bd..688387bbd53 100644
--- a/release/scripts/modules/rigify/leg_quadruped.py
+++ b/release/scripts/modules/rigify/leg_quadruped.py
@@ -23,7 +23,7 @@ from rna_prop_ui import rna_idprop_ui_prop_get
from math import pi
from rigify import RigifyError
from rigify_utils import bone_class_instance, copy_bone_simple, get_side_name, get_base_name
-from Mathutils import Vector
+from mathutils import Vector
METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe"
@@ -160,7 +160,7 @@ def ik(obj, bone_definition, base_names, options):
ik.foot_roll_e.parent = ik_chain.foot_e
ik.foot_roll_e.head -= mt_chain.toe_e.vector.normalize() * mt_chain.foot_e.length
ik.foot_roll_e.tail = ik.foot_roll_e.head - (mt_chain.foot_e.vector.normalize() * mt_chain.toe_e.length)
- ik.foot_roll_e.align_roll(mt_chain.foot_e.matrix.rotation_part() * Vector(0.0, 0.0, -1.0))
+ ik.foot_roll_e.align_roll(mt_chain.foot_e.matrix.rotation_part() * Vector((0.0, 0.0, -1.0)))
# MCH-foot
ik.foot_roll_01_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + base_names[mt_chain.foot])
@@ -207,13 +207,13 @@ def ik(obj, bone_definition, base_names, options):
prop["min"] = 0.0
prop["max"] = 1.0
- ik_driver_path = pb[ik_chain.foot].path_to_id() + '["ik"]'
+ ik_driver_path = pb[ik_chain.foot].path_from_id() + '["ik"]'
# simple constraining of orig bones
con = mt_chain.thigh_p.constraints.new('COPY_TRANSFORMS')
con.target = obj
con.subtarget = ik_chain.thigh
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
var = driver.variables.new()
driver.type = 'AVERAGE'
@@ -225,7 +225,7 @@ def ik(obj, bone_definition, base_names, options):
con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS')
con.target = obj
con.subtarget = ik_chain.shin
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
var = driver.variables.new()
driver.type = 'AVERAGE'
@@ -237,7 +237,7 @@ def ik(obj, bone_definition, base_names, options):
con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS')
con.target = obj
con.subtarget = ik.foot_roll_02
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
var = driver.variables.new()
driver.type = 'AVERAGE'
@@ -249,7 +249,7 @@ def ik(obj, bone_definition, base_names, options):
con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS')
con.target = obj
con.subtarget = ik_chain.toe
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
var = driver.variables.new()
driver.type = 'AVERAGE'
@@ -369,9 +369,9 @@ def fk(obj, bone_definition, base_names, options):
prop["min"] = 0.0
prop["max"] = 1.0
- hinge_driver_path = pb[fk_chain.thigh].path_to_id() + '["hinge"]'
+ hinge_driver_path = pb[fk_chain.thigh].path_from_id() + '["hinge"]'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
var = driver.variables.new()
driver.type = 'AVERAGE'
diff --git a/release/scripts/modules/rigify/mouth.py b/release/scripts/modules/rigify/mouth.py
index 31d7c5a1ce9..d516a48ec95 100644
--- a/release/scripts/modules/rigify/mouth.py
+++ b/release/scripts/modules/rigify/mouth.py
@@ -21,7 +21,7 @@
import bpy
from rna_prop_ui import rna_idprop_ui_prop_get
from math import acos, pi
-from Mathutils import Vector
+from mathutils import Vector
from rigify import RigifyError
from rigify_utils import copy_bone_simple
@@ -77,7 +77,7 @@ def addget_shape_key_driver(obj, name="Key"):
if driver_s.data_path == driver_path:
fcurve = driver_s
if fcurve == None:
- fcurve = obj.data.shape_keys.keys[name].driver_add("value", 0)
+ fcurve = obj.data.shape_keys.keys[name].driver_add("value")
fcurve.driver.type = 'AVERAGE'
new = True
@@ -173,7 +173,7 @@ def deform(obj, definitions, base_names, options):
jopen1 = copy_bone_simple(obj.data, jaw, "MCH-"+base_names[jaw]+".track1", parent=True).name
eb[jopen1].connected = False
eb[jopen1].head = eb[jaw].tail
- eb[jopen1].tail = eb[jopen1].head + Vector(0, 0, eb[jaw].length/4)
+ eb[jopen1].tail = eb[jopen1].head + Vector((0, 0, eb[jaw].length/4))
jopen2 = copy_bone_simple(obj.data, jopen1, "MCH-"+base_names[jaw]+".track2").name
eb[jopen2].parent = eb[jaw]
@@ -427,7 +427,7 @@ def control(obj, definitions, base_names, options):
# Jaw open tracker
jopent = copy_bone_simple(obj.data, jaw_e.name, "MCH-"+base_names[jaw_e.name]+".track", parent=True).name
eb[jopent].connected = False
- eb[jopent].tail = jaw_e.tail + Vector(0,0,jaw_e.length)
+ eb[jopent].tail = jaw_e.tail + Vector((0.0, 0.0, jaw_e.length))
eb[jopent].head = jaw_e.tail
bpy.ops.object.mode_set(mode='OBJECT')
@@ -448,7 +448,7 @@ def control(obj, definitions, base_names, options):
prop["min"] = 0.0
prop["max"] = 1.0
- open_driver_path = pb[lip1].path_to_id() + '["open_action"]'
+ open_driver_path = pb[lip1].path_from_id() + '["open_action"]'
# Constraints
@@ -543,12 +543,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = jopent
con.action = open_action
con.transform_channel = 'SCALE_Y'
- con.start_frame = 0
- con.end_frame = 60
+ con.frame_start = 0
+ con.frame_end = 60
con.minimum = 0.0
con.maximum = 1.0
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -561,12 +561,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = jopent
con.action = open_action
con.transform_channel = 'SCALE_Y'
- con.start_frame = 0
- con.end_frame = 60
+ con.frame_start = 0
+ con.frame_end = 60
con.minimum = 0.0
con.maximum = 1.0
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -579,12 +579,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = jopent
con.action = open_action
con.transform_channel = 'SCALE_Y'
- con.start_frame = 0
- con.end_frame = 60
+ con.frame_start = 0
+ con.frame_end = 60
con.minimum = 0.0
con.maximum = 1.0
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -597,12 +597,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = jopent
con.action = open_action
con.transform_channel = 'SCALE_Y'
- con.start_frame = 0
- con.end_frame = 60
+ con.frame_start = 0
+ con.frame_end = 60
con.minimum = 0.0
con.maximum = 1.0
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -615,12 +615,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = jopent
con.action = open_action
con.transform_channel = 'SCALE_Y'
- con.start_frame = 0
- con.end_frame = 60
+ con.frame_start = 0
+ con.frame_end = 60
con.minimum = 0.0
con.maximum = 1.0
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -633,12 +633,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = jopent
con.action = open_action
con.transform_channel = 'SCALE_Y'
- con.start_frame = 0
- con.end_frame = 60
+ con.frame_start = 0
+ con.frame_end = 60
con.minimum = 0.0
con.maximum = 1.0
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -651,12 +651,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = jopent
con.action = open_action
con.transform_channel = 'SCALE_Y'
- con.start_frame = 0
- con.end_frame = 60
+ con.frame_start = 0
+ con.frame_end = 60
con.minimum = 0.0
con.maximum = 1.0
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -669,12 +669,12 @@ def control(obj, definitions, base_names, options):
con.subtarget = jopent
con.action = open_action
con.transform_channel = 'SCALE_Y'
- con.start_frame = 0
- con.end_frame = 60
+ con.frame_start = 0
+ con.frame_end = 60
con.minimum = 0.0
con.maximum = 1.0
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
diff --git a/release/scripts/modules/rigify/neck.py b/release/scripts/modules/rigify/neck.py
new file mode 100644
index 00000000000..0d2ab25bcc9
--- /dev/null
+++ b/release/scripts/modules/rigify/neck.py
@@ -0,0 +1,344 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from rigify import RigifyError
+from rigify_utils import bone_class_instance, copy_bone_simple
+from rna_prop_ui import rna_idprop_ui_prop_get
+
+
+
+def metarig_template():
+ # TODO:
+ ## generated by rigify.write_meta_rig
+ #bpy.ops.object.mode_set(mode='EDIT')
+ #obj = bpy.context.active_object
+ #arm = obj.data
+ #bone = arm.edit_bones.new('body')
+ #bone.head[:] = 0.0000, -0.0276, -0.1328
+ #bone.tail[:] = 0.0000, -0.0170, -0.0197
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #bone = arm.edit_bones.new('head')
+ #bone.head[:] = 0.0000, -0.0170, -0.0197
+ #bone.tail[:] = 0.0000, 0.0726, 0.1354
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['body']
+ #bone = arm.edit_bones.new('neck.01')
+ #bone.head[:] = 0.0000, -0.0170, -0.0197
+ #bone.tail[:] = 0.0000, -0.0099, 0.0146
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #bone.parent = arm.edit_bones['head']
+ #bone = arm.edit_bones.new('neck.02')
+ #bone.head[:] = 0.0000, -0.0099, 0.0146
+ #bone.tail[:] = 0.0000, -0.0242, 0.0514
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.01']
+ #bone = arm.edit_bones.new('neck.03')
+ #bone.head[:] = 0.0000, -0.0242, 0.0514
+ #bone.tail[:] = 0.0000, -0.0417, 0.0868
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.02']
+ #bone = arm.edit_bones.new('neck.04')
+ #bone.head[:] = 0.0000, -0.0417, 0.0868
+ #bone.tail[:] = 0.0000, -0.0509, 0.1190
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.03']
+ #bone = arm.edit_bones.new('neck.05')
+ #bone.head[:] = 0.0000, -0.0509, 0.1190
+ #bone.tail[:] = 0.0000, -0.0537, 0.1600
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.04']
+ #
+ #bpy.ops.object.mode_set(mode='OBJECT')
+ #pbone = obj.pose.bones['head']
+ #pbone['type'] = 'neck_flex'
+ pass
+
+
+def metarig_definition(obj, orig_bone_name):
+ '''
+ The bone given is neck_01, its parent is the body
+ eg.
+ body -> neck_01 -> neck_02 -> neck_03.... etc
+ '''
+ arm = obj.data
+ neck = arm.bones[orig_bone_name]
+ body = neck.parent
+
+ bone_definition = [body.name, neck.name]
+ bone_definition.extend([child.name for child in neck.children_recursive_basename])
+ return bone_definition
+
+
+def deform(obj, definitions, base_names, options):
+ for org_bone_name in definitions[1:]:
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ # Create deform bone.
+ bone = copy_bone_simple(obj.data, org_bone_name, "DEF-%s" % base_names[org_bone_name], parent=True)
+
+ # Store name before leaving edit mode
+ bone_name = bone.name
+
+ # Leave edit mode
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Get the pose bone
+ bone = obj.pose.bones[bone_name]
+
+ # Constrain to the original bone
+ # XXX. Todo, is this needed if the bone is connected to its parent?
+ con = bone.constraints.new('COPY_TRANSFORMS')
+ con.name = "copy_loc"
+ con.target = obj
+ con.subtarget = org_bone_name
+
+
+def main(obj, bone_definition, base_names, options):
+ from mathutils import Vector
+
+ arm = obj.data
+ eb = obj.data.edit_bones
+ bb = obj.data.bones
+ pb = obj.pose.bones
+
+ body = bone_definition[0]
+
+ # Create the neck and head control bones
+ if "head_name" in options:
+ head_name = options["head_name"]
+ else:
+ head_name = "head"
+
+ neck_name = base_names[bone_definition[1]].split(".")[0]
+
+ neck_ctrl = copy_bone_simple(arm, bone_definition[1], neck_name).name
+ head_ctrl = copy_bone_simple(arm, bone_definition[len(bone_definition)-1], head_name).name
+ eb[head_ctrl].tail += eb[neck_ctrl].head - eb[head_ctrl].head
+ eb[head_ctrl].head = eb[neck_ctrl].head
+
+ # Create hinge and socket bones
+ neck_hinge = copy_bone_simple(arm, bone_definition[0], "MCH-" + neck_name + "_hinge").name
+ head_hinge = copy_bone_simple(arm, neck_ctrl, "MCH-" + head_name + "_hinge").name
+ eb[neck_hinge].tail += eb[neck_ctrl].head - eb[neck_hinge].head
+ eb[neck_hinge].head = eb[neck_ctrl].head
+ eb[head_hinge].tail += eb[neck_ctrl].head - eb[head_hinge].head
+ eb[head_hinge].head = eb[neck_ctrl].head
+
+ neck_socket = copy_bone_simple(arm, bone_definition[1], "MCH-" + neck_name + "_socket").name
+ head_socket = copy_bone_simple(arm, bone_definition[1], "MCH-" + head_name + "_socket").name
+
+ # Parent-child relationships between the body, hinges, controls, and sockets
+ eb[neck_ctrl].parent = eb[neck_hinge]
+ eb[head_ctrl].parent = eb[head_hinge]
+
+ eb[neck_socket].parent = eb[body]
+ eb[head_socket].parent = eb[body]
+
+ # Create neck bones
+ neck = [] # neck bones
+ neck_neck = [] # bones constrained to neck control
+ neck_head = [] # bones constrained to head control
+ for i in range(1, len(bone_definition)):
+ # Create bones
+ neck_bone = copy_bone_simple(arm, bone_definition[i], base_names[bone_definition[i]]).name
+ neck_neck_bone = copy_bone_simple(arm, neck_ctrl, "MCH-" + base_names[bone_definition[i]] + ".neck").name
+ neck_head_bone = copy_bone_simple(arm, head_ctrl, "MCH-" + base_names[bone_definition[i]] + ".head").name
+
+ # Move them all to the same place
+ eb[neck_neck_bone].tail += eb[neck_bone].head - eb[neck_neck_bone].head
+ eb[neck_head_bone].tail += eb[neck_bone].head - eb[neck_neck_bone].head
+ eb[neck_neck_bone].head = eb[neck_bone].head
+ eb[neck_head_bone].head = eb[neck_bone].head
+
+ # Parent/child relationships
+ eb[neck_bone].parent = eb[neck_head_bone]
+ eb[neck_head_bone].parent = eb[neck_neck_bone]
+
+ if i > 1:
+ eb[neck_neck_bone].parent = eb[neck[i-2]]
+ else:
+ eb[neck_neck_bone].parent = eb[body]
+
+ # Add them to the lists
+ neck += [neck_bone]
+ neck_neck += [neck_neck_bone]
+ neck_head += [neck_head_bone]
+
+ # Create deformation rig
+ deform(obj, bone_definition, base_names, options)
+
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Axis locks
+ pb[neck_ctrl].lock_location = True, True, True
+ pb[head_ctrl].lock_location = True, True, True
+
+ for bone in neck:
+ pb[bone].lock_location = True, True, True
+
+ # Neck hinge
+ prop = rna_idprop_ui_prop_get(pb[neck_ctrl], "hinge", create=True)
+ pb[neck_ctrl]["hinge"] = 0.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+ prop["hard_min"] = 0.0
+ prop["hard_max"] = 1.0
+
+ con = pb[neck_hinge].constraints.new('COPY_LOCATION')
+ con.name = "socket"
+ con.target = obj
+ con.subtarget = neck_socket
+
+ con = pb[neck_hinge].constraints.new('COPY_ROTATION')
+ con.name = "hinge"
+ con.target = obj
+ con.subtarget = body
+
+ hinge_driver_path = pb[neck_ctrl].path_from_id() + '["hinge"]'
+
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = hinge_driver_path
+
+ mod = fcurve.modifiers[0]
+ mod.poly_order = 1
+ mod.coefficients[0] = 1.0
+ mod.coefficients[1] = -1.0
+
+ # Head hinge
+ prop = rna_idprop_ui_prop_get(pb[head_ctrl], "hinge", create=True)
+ pb[head_ctrl]["hinge"] = 0.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+ prop["hard_min"] = 0.0
+ prop["hard_max"] = 1.0
+
+ con = pb[head_hinge].constraints.new('COPY_LOCATION')
+ con.name = "socket"
+ con.target = obj
+ con.subtarget = head_socket
+
+ con = pb[head_hinge].constraints.new('COPY_ROTATION')
+ con.name = "hinge"
+ con.target = obj
+ con.subtarget = neck_ctrl
+
+ hinge_driver_path = pb[head_ctrl].path_from_id() + '["hinge"]'
+
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = hinge_driver_path
+
+ mod = fcurve.modifiers[0]
+ mod.poly_order = 1
+ mod.coefficients[0] = 1.0
+ mod.coefficients[1] = -1.0
+
+ # Neck rotation constraints
+ for i in range(0, len(neck_neck)):
+ con = pb[neck_neck[i]].constraints.new('COPY_ROTATION')
+ con.name = "neck rotation"
+ con.target = obj
+ con.subtarget = neck_ctrl
+ con.influence = (i+1) / len(neck_neck)
+
+
+ # Head rotation constraints/drivers
+ prop = rna_idprop_ui_prop_get(pb[head_ctrl], "extent", create=True)
+ if "extent" in options:
+ pb[head_ctrl]["extent"] = options["extent"]
+ else:
+ pb[head_ctrl]["extent"] = 0.5
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+ prop["hard_min"] = 0.0
+ prop["hard_max"] = 1.0
+
+ extent_prop_path = pb[head_ctrl].path_from_id() + '["extent"]'
+
+ for i in range(0, len(neck_head)):
+ con = pb[neck_head[i]].constraints.new('COPY_ROTATION')
+ con.name = "head rotation"
+ con.target = obj
+ con.subtarget = head_ctrl
+
+ if i < (len(neck_head)-1):
+ inf = (i+1) / len(neck_head)
+
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ var.name = "ext"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = extent_prop_path
+
+ driver.expression = "0 if ext == 0 else (((%s-1)/ext)+1)" % inf
+ else:
+ con.influence = 1.0
+
+ # Constrain original bones to the neck bones
+ for i in range(0, len(neck)):
+ con = pb[bone_definition[i+1]].constraints.new('COPY_TRANSFORMS')
+ con.name = "copy_transform"
+ con.target = obj
+ con.subtarget = neck[i]
+
+
+ # Set the controls' custom shapes to use other bones for transforms
+ pb[neck_ctrl].custom_shape_transform = pb[bone_definition[len(bone_definition)//2]]
+ pb[head_ctrl].custom_shape_transform = pb[bone_definition[len(bone_definition)-1]]
+
+
+ # last step setup layers
+ if "ex_layer" in options:
+ layer = [n==options["ex_layer"] for n in range(0,32)]
+ else:
+ layer = list(arm.bones[bone_definition[1]].layer)
+ for bone in neck:
+ bb[bone].layer = layer
+
+ layer = list(arm.bones[bone_definition[1]].layer)
+ bb[neck_ctrl].layer = layer
+ bb[head_ctrl].layer = layer
+
+
+ # no blending the result of this
+ return None
+
diff --git a/release/scripts/modules/rigify/neck_flex.py b/release/scripts/modules/rigify/neck_flex.py
index b3628ef4c2c..08f963434d1 100644
--- a/release/scripts/modules/rigify/neck_flex.py
+++ b/release/scripts/modules/rigify/neck_flex.py
@@ -125,7 +125,7 @@ def deform(obj, definitions, base_names, options):
def main(obj, bone_definition, base_names, options):
- from Mathutils import Vector
+ from mathutils import Vector
arm = obj.data
@@ -176,7 +176,7 @@ def main(obj, bone_definition, base_names, options):
ex.neck_socket_e.connected = False
ex.neck_socket_e.parent = mt.body_e
ex.neck_socket_e.head = mt.head_e.head
- ex.neck_socket_e.tail = mt.head_e.head - Vector(0.0, neck_chain_segment_length / 2.0, 0.0)
+ ex.neck_socket_e.tail = mt.head_e.head - Vector((0.0, neck_chain_segment_length / 2.0, 0.0))
ex.neck_socket_e.roll = 0.0
@@ -237,9 +237,9 @@ def main(obj, bone_definition, base_names, options):
con.subtarget = mt.body
# add driver
- hinge_driver_path = ex.head_ctrl_p.path_to_id() + '["hinge"]'
+ hinge_driver_path = ex.head_ctrl_p.path_from_id() + '["hinge"]'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
var = driver.variables.new()
driver.type = 'AVERAGE'
@@ -254,12 +254,12 @@ def main(obj, bone_definition, base_names, options):
mod.coefficients[0] = 1.0
mod.coefficients[1] = -1.0
- head_driver_path = ex.head_ctrl_p.path_to_id()
+ head_driver_path = ex.head_ctrl_p.path_from_id()
target_names = [("b%.2d" % (i + 1)) for i in range(len(neck_chain))]
ex.head_ctrl_p["bend_tot"] = 0.0
- fcurve = ex.head_ctrl_p.driver_add('["bend_tot"]', 0)
+ fcurve = ex.head_ctrl_p.driver_add('["bend_tot"]')
driver = fcurve.driver
driver.type = 'SUM'
fcurve.modifiers.remove(0) # grr dont need a modifier
@@ -296,7 +296,7 @@ def main(obj, bone_definition, base_names, options):
con.owner_space = 'LOCAL'
con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'SCRIPTED'
driver.expression = "bend/bend_tot"
@@ -332,7 +332,7 @@ def main(obj, bone_definition, base_names, options):
# last step setup layers
if "ex_layer" in options:
- layer = [n==options["ex_layer"] for n in range(0,32)]
+ layer = [n == options["ex_layer"] for n in range(0, 32)]
else:
layer = list(arm.bones[bone_definition[1]].layer)
for attr in ex_chain.attr_names:
@@ -346,4 +346,3 @@ def main(obj, bone_definition, base_names, options):
# no blending the result of this
return None
-
diff --git a/release/scripts/modules/rigify/palm_curl.py b/release/scripts/modules/rigify/palm_curl.py
index 6626438709d..2bdd28a348a 100644
--- a/release/scripts/modules/rigify/palm_curl.py
+++ b/release/scripts/modules/rigify/palm_curl.py
@@ -156,7 +156,7 @@ def main(obj, bone_definition, base_names, options):
driver_fcurves = pinky_pbone.driver_add("rotation_euler")
- controller_path = control_pbone.path_to_id()
+ controller_path = control_pbone.path_from_id()
# add custom prop
control_pbone["spread"] = 0.0
@@ -248,13 +248,13 @@ def main(obj, bone_definition, base_names, options):
# NOTE: the direction of the Z rotation depends on which side the palm is on.
# we could do a simple side-of-x test but better to work out the direction
# the hand is facing.
- from Mathutils import Vector
+ from mathutils import Vector
from math import degrees
child_pbone_01 = obj.pose.bones[children[0]].bone
child_pbone_02 = obj.pose.bones[children[1]].bone
rel_vec = child_pbone_01.head - child_pbone_02.head
- x_vec = child_pbone_01.matrix.rotation_part() * Vector(1.0, 0.0, 0.0)
+ x_vec = child_pbone_01.matrix.rotation_part() * Vector((1.0, 0.0, 0.0))
return degrees(rel_vec.angle(x_vec)) > 90.0
diff --git a/release/scripts/modules/rigify/shape_key_control.py b/release/scripts/modules/rigify/shape_key_control.py
index fd0e900a7b5..ac3987ca7e1 100644
--- a/release/scripts/modules/rigify/shape_key_control.py
+++ b/release/scripts/modules/rigify/shape_key_control.py
@@ -57,7 +57,7 @@ def addget_shape_key_driver(obj, name="Key"):
if driver_s.data_path == driver_path:
fcurve = driver_s
if fcurve == None:
- fcurve = obj.data.shape_keys.keys[name].driver_add("value", 0)
+ fcurve = obj.data.shape_keys.keys[name].driver_add("value")
fcurve.driver.type = 'AVERAGE'
new = True
diff --git a/release/scripts/modules/rigify/shape_key_distance.py b/release/scripts/modules/rigify/shape_key_distance.py
index 68501ac829b..06dd3d67d4b 100644
--- a/release/scripts/modules/rigify/shape_key_distance.py
+++ b/release/scripts/modules/rigify/shape_key_distance.py
@@ -54,7 +54,7 @@ def addget_shape_key_driver(obj, name="Key"):
if driver_s.data_path == driver_path:
fcurve = driver_s
if fcurve == None:
- fcurve = obj.data.shape_keys.keys[name].driver_add("value", 0)
+ fcurve = obj.data.shape_keys.keys[name].driver_add("value")
fcurve.driver.type = 'AVERAGE'
return fcurve
diff --git a/release/scripts/modules/rigify/shape_key_rotdiff.py b/release/scripts/modules/rigify/shape_key_rotdiff.py
index 2c30d95e666..7049bcf74bb 100644
--- a/release/scripts/modules/rigify/shape_key_rotdiff.py
+++ b/release/scripts/modules/rigify/shape_key_rotdiff.py
@@ -54,7 +54,7 @@ def addget_shape_key_driver(obj, name="Key"):
if driver_s.data_path == driver_path:
fcurve = driver_s
if fcurve == None:
- fcurve = obj.data.shape_keys.keys[name].driver_add("value", 0)
+ fcurve = obj.data.shape_keys.keys[name].driver_add("value")
fcurve.driver.type = 'AVERAGE'
return fcurve
diff --git a/release/scripts/modules/rigify/spine_pivot_flex.py b/release/scripts/modules/rigify/spine_pivot_flex.py
index 3ae5818f908..d3bab72d9a1 100644
--- a/release/scripts/modules/rigify/spine_pivot_flex.py
+++ b/release/scripts/modules/rigify/spine_pivot_flex.py
@@ -147,7 +147,7 @@ def deform(obj, definitions, base_names, options):
def main(obj, bone_definition, base_names, options):
- from Mathutils import Vector, RotationMatrix
+ from mathutils import Vector, RotationMatrix
from math import radians, pi
arm = obj.data
@@ -177,11 +177,11 @@ def main(obj, bone_definition, base_names, options):
# copy the pelvis, offset to make MCH-spine_rotate and MCH-ribcage_hinge
ex.ribcage_hinge_e = copy_bone_simple(arm, mt.pelvis, "MCH-%s_hinge" % base_names[mt.ribcage])
ex.ribcage_hinge = ex.ribcage_hinge_e.name
- ex.ribcage_hinge_e.translate(Vector(0.0, spine_chain_segment_length / 4.0, 0.0))
+ ex.ribcage_hinge_e.translate(Vector((0.0, spine_chain_segment_length / 4.0, 0.0)))
ex.spine_rotate_e = copy_bone_simple(arm, mt.ribcage, "MCH-%s_rotate" % spine_chain_basename)
ex.spine_rotate = ex.spine_rotate_e.name
- ex.spine_rotate_e.translate(Vector(0.0, spine_chain_segment_length / 2.0, 0.0))
+ ex.spine_rotate_e.translate(Vector((0.0, spine_chain_segment_length / 2.0, 0.0)))
ex.spine_rotate_e.connected = False
ex.spine_rotate_e.parent = ex.pelvis_copy_e
@@ -294,14 +294,14 @@ def main(obj, bone_definition, base_names, options):
con.subtarget = ex.pelvis_copy
# add driver
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
var = driver.variables.new()
driver.type = 'AVERAGE'
var.name = "var"
var.targets[0].id_type = 'OBJECT'
var.targets[0].id = obj
- var.targets[0].data_path = ex.ribcage_copy_p.path_to_id() + '["hinge"]'
+ var.targets[0].data_path = ex.ribcage_copy_p.path_from_id() + '["hinge"]'
mod = fcurve.modifiers[0]
mod.poly_order = 1
@@ -347,10 +347,10 @@ def main(obj, bone_definition, base_names, options):
# Constrain 'inbetween' bones
target_names = [("b%.2d" % (i + 1)) for i in range(spine_chain_len - 1)]
- rib_driver_path = ex.ribcage_copy_p.path_to_id()
+ rib_driver_path = ex.ribcage_copy_p.path_from_id()
ex.ribcage_copy_p["bend_tot"] = 0.0
- fcurve = ex.ribcage_copy_p.driver_add('["bend_tot"]', 0)
+ fcurve = ex.ribcage_copy_p.driver_add('["bend_tot"]')
driver = fcurve.driver
driver.type = 'SUM'
fcurve.modifiers.remove(0) # grr dont need a modifier
@@ -385,7 +385,7 @@ def main(obj, bone_definition, base_names, options):
del spine_p
# add driver
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'SCRIPTED'
driver.expression = "bend/bend_tot"
@@ -440,7 +440,7 @@ def main(obj, bone_definition, base_names, options):
if i == spine_chain_len:
con.head_tail = 1.0
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
var = driver.variables.new()
driver.type = 'AVERAGE'
@@ -463,7 +463,7 @@ def main(obj, bone_definition, base_names, options):
# last step setup layers
if "ex_layer" in options:
- layer = [n==options["ex_layer"] for n in range(0,32)]
+ layer = [n == options["ex_layer"] for n in range(0, 32)]
else:
layer = list(arm.bones[bone_definition[1]].layer)
for attr in ex.attr_names:
diff --git a/release/scripts/modules/rigify/stretch.py b/release/scripts/modules/rigify/stretch.py
index 0902b108def..1c3d317b4b1 100644
--- a/release/scripts/modules/rigify/stretch.py
+++ b/release/scripts/modules/rigify/stretch.py
@@ -41,19 +41,18 @@ RIG_TYPE = "stretch"
# pbone = obj.pose.bones['Bone']
# pbone['type'] = 'copy'
-bool_map = {0:False, 1:True,
- 0.0:False, 1.0:True,
- "false":False, "true":True,
- "False":False, "True":True,
- "no":False, "yes":True,
- "No":False, "Yes":True}
+bool_map = {0: False, 1: True,
+ 0.0: False, 1.0: True,
+ "false": False, "true": True,
+ "False": False, "True": True,
+ "no": False, "yes": True,
+ "No": False, "Yes": True}
+
def metarig_definition(obj, orig_bone_name):
return (orig_bone_name,)
-
-
def main(obj, bone_definition, base_names, options):
""" A stretchy bone from one bone to another.
Deformation only (no controls).
@@ -108,4 +107,3 @@ def main(obj, bone_definition, base_names, options):
con.volume = 'NO_VOLUME'
return tuple()
-
diff --git a/release/scripts/modules/rigify/tail_control.py b/release/scripts/modules/rigify/tail_control.py
index 56305b5e07e..47da9778913 100644
--- a/release/scripts/modules/rigify/tail_control.py
+++ b/release/scripts/modules/rigify/tail_control.py
@@ -22,7 +22,7 @@ import bpy
from rigify import RigifyError
from rigify_utils import bone_class_instance, copy_bone_simple
from rna_prop_ui import rna_idprop_ui_prop_get
-from Mathutils import Vector, RotationMatrix
+from mathutils import Vector, RotationMatrix
from math import radians, pi
# not used, defined for completeness
@@ -133,9 +133,9 @@ def main(obj, bone_definitions, base_names, options):
con_h.subtarget = hinge1
# Add drivers
- bone_path = pb[bones[0]].path_to_id()
+ bone_path = pb[bones[0]].path_from_id()
- driver_fcurve = con_f.driver_add("influence", 0)
+ driver_fcurve = con_f.driver_add("influence")
driver = driver_fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -148,7 +148,7 @@ def main(obj, bone_definitions, base_names, options):
mod.coefficients[0] = 1.0
mod.coefficients[1] = -1.0
- driver_fcurve = con_h.driver_add("influence", 0)
+ driver_fcurve = con_h.driver_add("influence")
driver = driver_fcurve.driver
driver.type = 'AVERAGE'
var = driver.variables.new()
@@ -163,4 +163,3 @@ def main(obj, bone_definitions, base_names, options):
return None
-
diff --git a/release/scripts/modules/rigify/tongue.py b/release/scripts/modules/rigify/tongue.py
new file mode 100644
index 00000000000..b6dfe756b71
--- /dev/null
+++ b/release/scripts/modules/rigify/tongue.py
@@ -0,0 +1,361 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+from rigify import RigifyError
+from rigify_utils import bone_class_instance, copy_bone_simple
+from rna_prop_ui import rna_idprop_ui_prop_get
+
+# not used, defined for completeness
+METARIG_NAMES = ("body", "head")
+
+
+def metarig_template():
+ # TODO:
+ ## generated by rigify.write_meta_rig
+ #bpy.ops.object.mode_set(mode='EDIT')
+ #obj = bpy.context.active_object
+ #arm = obj.data
+ #bone = arm.edit_bones.new('body')
+ #bone.head[:] = 0.0000, -0.0276, -0.1328
+ #bone.tail[:] = 0.0000, -0.0170, -0.0197
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #bone = arm.edit_bones.new('head')
+ #bone.head[:] = 0.0000, -0.0170, -0.0197
+ #bone.tail[:] = 0.0000, 0.0726, 0.1354
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['body']
+ #bone = arm.edit_bones.new('neck.01')
+ #bone.head[:] = 0.0000, -0.0170, -0.0197
+ #bone.tail[:] = 0.0000, -0.0099, 0.0146
+ #bone.roll = 0.0000
+ #bone.connected = False
+ #bone.parent = arm.edit_bones['head']
+ #bone = arm.edit_bones.new('neck.02')
+ #bone.head[:] = 0.0000, -0.0099, 0.0146
+ #bone.tail[:] = 0.0000, -0.0242, 0.0514
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.01']
+ #bone = arm.edit_bones.new('neck.03')
+ #bone.head[:] = 0.0000, -0.0242, 0.0514
+ #bone.tail[:] = 0.0000, -0.0417, 0.0868
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.02']
+ #bone = arm.edit_bones.new('neck.04')
+ #bone.head[:] = 0.0000, -0.0417, 0.0868
+ #bone.tail[:] = 0.0000, -0.0509, 0.1190
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.03']
+ #bone = arm.edit_bones.new('neck.05')
+ #bone.head[:] = 0.0000, -0.0509, 0.1190
+ #bone.tail[:] = 0.0000, -0.0537, 0.1600
+ #bone.roll = 0.0000
+ #bone.connected = True
+ #bone.parent = arm.edit_bones['neck.04']
+ #
+ #bpy.ops.object.mode_set(mode='OBJECT')
+ #pbone = obj.pose.bones['head']
+ #pbone['type'] = 'neck_flex'
+ pass
+
+
+def metarig_definition(obj, orig_bone_name):
+ '''
+ The bone given is the tongue control, its parent is the body,
+ # its only child the first of a chain with matching basenames.
+ eg.
+ body -> tongue_control -> tongue_01 -> tongue_02 -> tongue_03.... etc
+ '''
+ arm = obj.data
+ tongue = arm.bones[orig_bone_name]
+ body = tongue.parent
+
+ children = tongue.children
+ if len(children) != 1:
+ raise RigifyError("expected the tongue bone '%s' to have only 1 child." % orig_bone_name)
+
+ child = children[0]
+ bone_definition = [body.name, tongue.name, child.name]
+ bone_definition.extend([child.name for child in child.children_recursive_basename])
+ return bone_definition
+
+
+def deform(obj, definitions, base_names, options):
+ for org_bone_name in definitions[2:]:
+ bpy.ops.object.mode_set(mode='EDIT')
+
+ # Create deform bone.
+ bone = copy_bone_simple(obj.data, org_bone_name, "DEF-%s" % base_names[org_bone_name], parent=True)
+
+ # Store name before leaving edit mode
+ bone_name = bone.name
+
+ # Leave edit mode
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # Get the pose bone
+ bone = obj.pose.bones[bone_name]
+
+ # Constrain to the original bone
+ # XXX. Todo, is this needed if the bone is connected to its parent?
+ con = bone.constraints.new('COPY_TRANSFORMS')
+ con.name = "copy_loc"
+ con.target = obj
+ con.subtarget = org_bone_name
+
+
+# TODO: rename all of the head/neck references to tongue
+def main(obj, bone_definition, base_names, options):
+ from mathutils import Vector
+
+ arm = obj.data
+
+ # Initialize container classes for convenience
+ mt = bone_class_instance(obj, ["body", "head"]) # meta
+ mt.body = bone_definition[0]
+ mt.head = bone_definition[1]
+ mt.update()
+
+ neck_chain = bone_definition[2:]
+
+ mt_chain = bone_class_instance(obj, [("neck_%.2d" % (i + 1)) for i in range(len(neck_chain))]) # 99 bones enough eh?
+ for i, attr in enumerate(mt_chain.attr_names):
+ setattr(mt_chain, attr, neck_chain[i])
+ mt_chain.update()
+
+ neck_chain_basename = base_names[mt_chain.neck_01_e.name].split(".")[0]
+ neck_chain_segment_length = mt_chain.neck_01_e.length
+
+ ex = bone_class_instance(obj, ["head", "head_hinge", "neck_socket", "head_ctrl"]) # hinge & extras
+
+ # Add the head hinge at the bodys location, becomes the parent of the original head
+
+ # apply everything to this copy of the chain
+ ex_chain = mt_chain.copy(base_names=base_names)
+ ex_chain.neck_01_e.parent = mt_chain.neck_01_e.parent
+
+
+ # Copy the head bone and offset
+ ex.head_e = copy_bone_simple(arm, mt.head, "MCH-%s" % base_names[mt.head], parent=True)
+ ex.head_e.connected = False
+ ex.head = ex.head_e.name
+ # offset
+ head_length = ex.head_e.length
+ ex.head_e.head.y += head_length / 2.0
+ ex.head_e.tail.y += head_length / 2.0
+
+ # Yes, use the body bone but call it a head hinge
+ ex.head_hinge_e = copy_bone_simple(arm, mt.body, "MCH-%s_hinge" % base_names[mt.head], parent=False)
+ ex.head_hinge_e.connected = False
+ ex.head_hinge = ex.head_hinge_e.name
+ ex.head_hinge_e.head.y += head_length / 4.0
+ ex.head_hinge_e.tail.y += head_length / 4.0
+
+ # Insert the neck socket, the head copys this loation
+ ex.neck_socket_e = arm.edit_bones.new("MCH-%s_socked" % neck_chain_basename)
+ ex.neck_socket = ex.neck_socket_e.name
+ ex.neck_socket_e.connected = False
+ ex.neck_socket_e.parent = mt.body_e
+ ex.neck_socket_e.head = mt.head_e.head
+ ex.neck_socket_e.tail = mt.head_e.head - Vector((0.0, neck_chain_segment_length / 2.0, 0.0))
+ ex.neck_socket_e.roll = 0.0
+
+
+ # copy of the head for controling
+ ex.head_ctrl_e = copy_bone_simple(arm, mt.head, base_names[mt.head])
+ ex.head_ctrl = ex.head_ctrl_e.name
+ ex.head_ctrl_e.parent = ex.head_hinge_e
+
+ for i, attr in enumerate(ex_chain.attr_names):
+ neck_e = getattr(ex_chain, attr + "_e")
+
+ # dont store parent names, re-reference as each chain bones parent.
+ neck_e_parent = arm.edit_bones.new("MCH-rot_%s" % base_names[getattr(mt_chain, attr)])
+ neck_e_parent.head = neck_e.head
+ neck_e_parent.tail = neck_e.head + (mt.head_e.vector.normalize() * neck_chain_segment_length / 2.0)
+ neck_e_parent.roll = mt.head_e.roll
+
+ orig_parent = neck_e.parent
+ neck_e.connected = False
+ neck_e.parent = neck_e_parent
+ neck_e_parent.connected = False
+
+ if i == 0:
+ neck_e_parent.parent = mt.body_e
+ else:
+ neck_e_parent.parent = orig_parent
+
+ deform(obj, bone_definition, base_names, options)
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ mt.update()
+ mt_chain.update()
+ ex_chain.update()
+ ex.update()
+
+ # Axis locks
+ ex.head_ctrl_p.lock_location = True, True, True
+ ex.head_ctrl_p.lock_scale = True, False, True
+
+ # Simple one off constraints, no drivers
+ con = ex.head_ctrl_p.constraints.new('COPY_LOCATION')
+ con.target = obj
+ con.subtarget = ex.neck_socket
+
+ con = ex.head_p.constraints.new('COPY_ROTATION')
+ con.target = obj
+ con.subtarget = ex.head_ctrl
+
+ # driven hinge
+ prop = rna_idprop_ui_prop_get(ex.head_ctrl_p, "hinge", create=True)
+ ex.head_ctrl_p["hinge"] = 0.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+
+ con = ex.head_hinge_p.constraints.new('COPY_ROTATION')
+ con.name = "hinge"
+ con.target = obj
+ con.subtarget = mt.body
+
+ # add driver
+ hinge_driver_path = ex.head_ctrl_p.path_to_id() + '["hinge"]'
+
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ var = driver.variables.new()
+ driver.type = 'AVERAGE'
+ var.name = "var"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = hinge_driver_path
+
+ #mod = fcurve_driver.modifiers.new('GENERATOR')
+ mod = fcurve.modifiers[0]
+ mod.poly_order = 1
+ mod.coefficients[0] = 1.0
+ mod.coefficients[1] = -1.0
+
+ head_driver_path = ex.head_ctrl_p.path_to_id()
+
+ target_names = [("b%.2d" % (i + 1)) for i in range(len(neck_chain))]
+
+ ex.head_ctrl_p["bend_tot"] = 0.0
+ fcurve = ex.head_ctrl_p.driver_add('["bend_tot"]')
+ driver = fcurve.driver
+ driver.type = 'SUM'
+ fcurve.modifiers.remove(0) # grr dont need a modifier
+
+ for i in range(len(neck_chain)):
+ var = driver.variables.new()
+ var.name = target_names[i]
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = head_driver_path + ('["bend_%.2d"]' % (i + 1))
+
+
+ for i, attr in enumerate(ex_chain.attr_names):
+ neck_p = getattr(ex_chain, attr + "_p")
+ neck_p.lock_location = True, True, True
+ neck_p.lock_location = True, True, True
+ neck_p.lock_rotations_4d = True
+
+ # Add bend prop
+ prop_name = "bend_%.2d" % (i + 1)
+ prop = rna_idprop_ui_prop_get(ex.head_ctrl_p, prop_name, create=True)
+ ex.head_ctrl_p[prop_name] = 1.0
+ prop["soft_min"] = 0.0
+ prop["soft_max"] = 1.0
+
+ # add parent constraint
+ neck_p_parent = neck_p.parent
+
+ # add constraints
+ if i == 0:
+ con = neck_p.constraints.new('COPY_SCALE')
+ con.name = "Copy Scale"
+ con.target = obj
+ con.subtarget = ex.head_ctrl
+ con.owner_space = 'LOCAL'
+ con.target_space = 'LOCAL'
+
+ con = neck_p_parent.constraints.new('COPY_ROTATION')
+ con.name = "Copy Rotation"
+ con.target = obj
+ con.subtarget = ex.head
+ con.owner_space = 'LOCAL'
+ con.target_space = 'LOCAL'
+
+ fcurve = con.driver_add("influence")
+ driver = fcurve.driver
+ driver.type = 'SCRIPTED'
+ driver.expression = "bend/bend_tot"
+
+ fcurve.modifiers.remove(0) # grr dont need a modifier
+
+
+ # add target
+ var = driver.variables.new()
+ var.name = "bend_tot"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = head_driver_path + ('["bend_tot"]')
+
+ var = driver.variables.new()
+ var.name = "bend"
+ var.targets[0].id_type = 'OBJECT'
+ var.targets[0].id = obj
+ var.targets[0].data_path = head_driver_path + ('["%s"]' % prop_name)
+
+
+ # finally constrain the original bone to this one
+ orig_neck_p = getattr(mt_chain, attr + "_p")
+ con = orig_neck_p.constraints.new('COPY_TRANSFORMS')
+ con.target = obj
+ con.subtarget = neck_p.name
+
+
+ # Set the head control's custom shape to use the last
+ # org neck bone for its transform
+ ex.head_ctrl_p.custom_shape_transform = obj.pose.bones[bone_definition[len(bone_definition)-1]]
+
+
+ # last step setup layers
+ if "ex_layer" in options:
+ layer = [n==options["ex_layer"] for n in range(0,32)]
+ else:
+ layer = list(arm.bones[bone_definition[1]].layer)
+ for attr in ex_chain.attr_names:
+ getattr(ex_chain, attr + "_b").layer = layer
+ for attr in ex.attr_names:
+ getattr(ex, attr + "_b").layer = layer
+
+ layer = list(arm.bones[bone_definition[1]].layer)
+ ex.head_ctrl_b.layer = layer
+
+
+ # no blending the result of this
+ return None
+
diff --git a/release/scripts/modules/rigify/track_dual.py b/release/scripts/modules/rigify/track_dual.py
index a926be684e6..38c2a86ab32 100644
--- a/release/scripts/modules/rigify/track_dual.py
+++ b/release/scripts/modules/rigify/track_dual.py
@@ -41,12 +41,12 @@ RIG_TYPE = "track_dual"
# pbone = obj.pose.bones['Bone']
# pbone['type'] = 'copy'
-bool_map = {0:False, 1:True,
- 0.0:False, 1.0:True,
- "false":False, "true":True,
- "False":False, "True":True,
- "no":False, "yes":True,
- "No":False, "Yes":True}
+bool_map = {0: False, 1: True,
+ 0.0: False, 1.0: True,
+ "false": False, "true": True,
+ "False": False, "True": True,
+ "no": False, "yes": True,
+ "No": False, "Yes": True}
def metarig_definition(obj, orig_bone_name):
diff --git a/release/scripts/modules/rigify/track_reverse.py b/release/scripts/modules/rigify/track_reverse.py
index 988f7576294..21d38c28920 100644
--- a/release/scripts/modules/rigify/track_reverse.py
+++ b/release/scripts/modules/rigify/track_reverse.py
@@ -98,4 +98,3 @@ def main(obj, bone_definition, base_names, options):
return tuple()
-
diff --git a/release/scripts/modules/rigify_utils.py b/release/scripts/modules/rigify_utils.py
index 812342b3ebc..25ab6bebf48 100644
--- a/release/scripts/modules/rigify_utils.py
+++ b/release/scripts/modules/rigify_utils.py
@@ -26,7 +26,7 @@
# that a generic function would need to check for.
import bpy
-from Mathutils import Vector
+from mathutils import Vector
from rna_prop_ui import rna_idprop_ui_prop_get
DELIMITER = '-._'
@@ -136,7 +136,7 @@ def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, ta
prop["soft_min"] = 0.0
prop["soft_max"] = 1.0
- driver_path = prop_pbone.path_to_id() + ('["%s"]' % target_prop)
+ driver_path = prop_pbone.path_from_id() + ('["%s"]' % target_prop)
def blend_target(driver):
var = driver.variables.new()
@@ -154,7 +154,7 @@ def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, ta
con.target = obj
con.subtarget = to_bone_name
- fcurve = con.driver_add("influence", 0)
+ fcurve = con.driver_add("influence")
driver = fcurve.driver
driver.type = 'AVERAGE'
fcurve.modifiers.remove(0) # grr dont need a modifier
@@ -204,12 +204,12 @@ def add_pole_target_bone(obj, base_bone_name, name, mode='CROSS'):
offset.length = distance
elif mode == 'ZAVERAGE':
# between both bones Z axis
- z_axis_a = base_ebone.matrix.copy().rotation_part() * Vector(0.0, 0.0, -1.0)
- z_axis_b = parent_ebone.matrix.copy().rotation_part() * Vector(0.0, 0.0, -1.0)
+ z_axis_a = base_ebone.matrix.copy().rotation_part() * Vector((0.0, 0.0, -1.0))
+ z_axis_b = parent_ebone.matrix.copy().rotation_part() * Vector((0.0, 0.0, -1.0))
offset = (z_axis_a + z_axis_b).normalize() * distance
else:
# preset axis
- offset = Vector(0, 0, 0)
+ offset = Vector((0.0, 0.0, 0.0))
if mode[0] == "+":
val = distance
else:
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
index 1c1a32becf9..3fd70fedd8c 100644
--- a/release/scripts/modules/rna_info.py
+++ b/release/scripts/modules/rna_info.py
@@ -25,6 +25,44 @@ import bpy
# use to strip python paths
script_paths = bpy.utils.script_paths()
+_FAKE_STRUCT_SUBCLASS = True
+
+
+def _get_direct_attr(rna_type, attr):
+ props = getattr(rna_type, attr)
+ base = rna_type.base
+
+ if not base:
+ return [prop for prop in props]
+ else:
+ props_base = getattr(base, attr).values()
+ return [prop for prop in props if prop not in props_base]
+
+
+def get_direct_properties(rna_type):
+ return _get_direct_attr(rna_type, "properties")
+
+
+def get_direct_functions(rna_type):
+ return _get_direct_attr(rna_type, "functions")
+
+
+def rna_id_ignore(rna_id):
+ if rna_id == "rna_type":
+ return True
+
+ if "_OT_" in rna_id:
+ return True
+ if "_MT_" in rna_id:
+ return True
+ if "_PT_" in rna_id:
+ return True
+ if "_HT_" in rna_id:
+ return True
+ if "_KSI_" in rna_id:
+ return True
+ return False
+
def range_str(val):
if val < -10000000:
@@ -67,8 +105,8 @@ class InfoStructRNA:
def build(self):
rna_type = self.bl_rna
parent_id = self.identifier
- self.properties[:] = [GetInfoPropertyRNA(rna_prop, parent_id) for rna_id, rna_prop in rna_type.properties.items() if rna_id != "rna_type"]
- self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id) for rna_prop in rna_type.functions.values()]
+ self.properties[:] = [GetInfoPropertyRNA(rna_prop, parent_id) for rna_prop in get_direct_properties(rna_type) if rna_prop.identifier != "rna_type"]
+ self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id) for rna_prop in get_direct_functions(rna_type)]
def get_bases(self):
bases = []
@@ -116,17 +154,17 @@ class InfoStructRNA:
def __repr__(self):
- txt = ''
+ txt = ""
txt += self.identifier
if self.base:
- txt += '(%s)' % self.base.identifier
- txt += ': ' + self.description + '\n'
+ txt += "(%s)" % self.base.identifier
+ txt += ": " + self.description + "\n"
for prop in self.properties:
- txt += prop.__repr__() + '\n'
+ txt += prop.__repr__() + "\n"
for func in self.functions:
- txt += func.__repr__() + '\n'
+ txt += func.__repr__() + "\n"
return txt
@@ -163,40 +201,40 @@ class InfoPropertyRNA:
if self.type == "enum":
self.enum_items[:] = rna_prop.items.keys()
+
if self.array_length:
self.default = tuple(getattr(rna_prop, "default_array", ()))
+ else:
+ self.default = getattr(rna_prop, "default", None)
+ self.default_str = "" # fallback
+
+
+ if self.type == "pointer":
+ # pointer has no default, just set as None
+ self.default = None
+ self.default_str = "None"
+ elif self.type == "string":
+ self.default_str = "\"%s\"" % self.default
+ elif self.type == "enum":
+ self.default_str = "'%s'" % self.default
+ elif self.array_length:
self.default_str = ''
# special case for floats
if len(self.default) > 0:
- if type(self.default[0]) is float:
+ if self.type == "float":
self.default_str = "(%s)" % ", ".join([float_as_string(f) for f in self.default])
if not self.default_str:
self.default_str = str(self.default)
else:
- self.default = getattr(rna_prop, "default", "")
- if type(self.default) is float:
+ if self.type == "float":
self.default_str = float_as_string(self.default)
else:
self.default_str = str(self.default)
self.srna = GetInfoStructRNA(rna_prop.srna) # valid for pointer/collections
- def get_default_string(self):
- # pointer has no default, just set as None
- if self.type == "pointer":
- return "None"
- elif self.type == "string":
- return '"' + self.default_str + '"'
- elif self.type == "enum":
- if self.default_str:
- return "'" + self.default_str + "'"
- else:
- return ""
-
- return self.default_str
-
def get_arg_default(self, force=True):
- default = self.get_default_string()
+ default = self.default_str
if default and (force or self.is_required == False):
return "%s=%s" % (self.identifier, default)
return self.identifier
@@ -212,6 +250,13 @@ class InfoPropertyRNA:
type_str += " in [%s, %s]" % (range_str(self.min), range_str(self.max))
elif self.type == "enum":
type_str += " in [%s]" % ', '.join([("'%s'" % s) for s in self.enum_items])
+
+ if not (as_arg or as_ret):
+ # write default property, ignore function args for this
+ if self.type != "pointer":
+ if self.default_str:
+ type_str += ", default %s" % self.default_str
+
else:
if self.type == "collection":
if self.collection_type:
@@ -223,17 +268,22 @@ class InfoPropertyRNA:
type_str += collection_str + (class_fmt % self.fixed_type.identifier)
+ # setup qualifiers for this value.
+ type_info = []
if as_ret:
pass
elif as_arg:
if not self.is_required:
- type_str += ", (optional)"
+ type_info.append("optional")
else: # readonly is only useful for selfs, not args
if self.is_readonly:
- type_str += ", (readonly)"
+ type_info.append("readonly")
if self.is_never_none:
- type_str += ", (never None)"
+ type_info.append("never None")
+
+ if type_info:
+ type_str += (", (%s)" % ", ".join(type_info))
return type_str
@@ -338,7 +388,7 @@ def _GetInfoRNA(bl_rna, cls, parent_id=''):
key = parent_id, bl_rna.identifier
try:
return cls.global_lookup[key]
- except:
+ except KeyError:
instance = cls.global_lookup[key] = cls(bl_rna)
return instance
@@ -366,22 +416,7 @@ def BuildRNAInfo():
rna_full_path_dict = {} # store the result of full_rna_struct_path(rna_struct)
rna_children_dict = {} # store all rna_structs nested from here
rna_references_dict = {} # store a list of rna path strings that reference this type
- rna_functions_dict = {} # store all functions directly in this type (not inherited)
- rna_words = set()
-
- def rna_id_ignore(rna_id):
- if rna_id == "rna_type":
- return True
-
- if "_OT_" in rna_id:
- return True
- if "_MT_" in rna_id:
- return True
- if "_PT_" in rna_id:
- return True
- if "_HT_" in rna_id:
- return True
- return False
+ # rna_functions_dict = {} # store all functions directly in this type (not inherited)
def full_rna_struct_path(rna_struct):
'''
@@ -427,7 +462,8 @@ def BuildRNAInfo():
rna_full_path_dict[identifier] = full_rna_struct_path(rna_struct)
# Store a list of functions, remove inherited later
- rna_functions_dict[identifier] = list(rna_struct.functions)
+ # NOT USED YET
+ ## rna_functions_dict[identifier] = get_direct_functions(rna_struct)
# fill in these later
@@ -439,12 +475,6 @@ def BuildRNAInfo():
print("Ignoring", rna_type_name)
- # Sucks but we need to copy this so we can check original parent functions
- rna_functions_dict__copy = {}
- for key, val in rna_functions_dict.items():
- rna_functions_dict__copy[key] = val[:]
-
-
structs.sort() # not needed but speeds up sort below, setting items without an inheritance first
# Arrange so classes are always defined in the correct order
@@ -479,41 +509,27 @@ def BuildRNAInfo():
# precalc vars to avoid a lot of looping
for (rna_base, identifier, rna_struct) in structs:
- if rna_base:
- rna_base_prop_keys = rna_struct_dict[rna_base].properties.keys() # could cache
- rna_base_func_keys = [f.identifier for f in rna_struct_dict[rna_base].functions]
- else:
- rna_base_prop_keys = []
- rna_base_func_keys = []
-
# rna_struct_path = full_rna_struct_path(rna_struct)
rna_struct_path = rna_full_path_dict[identifier]
- for rna_prop_identifier, rna_prop in rna_struct.properties.items():
+ for rna_prop in get_direct_properties(rna_struct):
+ rna_prop_identifier = rna_prop.identifier
- if rna_prop_identifier == 'RNA' or \
- rna_id_ignore(rna_prop_identifier) or \
- rna_prop_identifier in rna_base_prop_keys:
+ if rna_prop_identifier == 'RNA' or rna_id_ignore(rna_prop_identifier):
continue
-
for rna_prop_ptr in (getattr(rna_prop, "fixed_type", None), getattr(rna_prop, "srna", None)):
# Does this property point to me?
if rna_prop_ptr:
rna_references_dict[rna_prop_ptr.identifier].append("%s.%s" % (rna_struct_path, rna_prop_identifier))
- for rna_func in rna_struct.functions:
+ for rna_func in get_direct_functions(rna_struct):
for rna_prop_identifier, rna_prop in rna_func.parameters.items():
- if rna_prop_identifier == 'RNA' or \
- rna_id_ignore(rna_prop_identifier) or \
- rna_prop_identifier in rna_base_func_keys:
+ if rna_prop_identifier == 'RNA' or rna_id_ignore(rna_prop_identifier):
continue
- try:
- rna_prop_ptr = rna_prop.fixed_type
- except:
- rna_prop_ptr = None
+ rna_prop_ptr = getattr(rna_prop, "fixed_type", None)
# Does this property point to me?
if rna_prop_ptr:
@@ -526,16 +542,6 @@ def BuildRNAInfo():
rna_children_dict[nested.identifier].append(rna_struct)
- if rna_base:
- rna_funcs = rna_functions_dict[identifier]
- if rna_funcs:
- # Remove inherited functions if we have any
- rna_base_funcs = rna_functions_dict__copy[rna_base]
- rna_funcs[:] = [f for f in rna_funcs if f not in rna_base_funcs]
-
- rna_functions_dict__copy.clear()
- del rna_functions_dict__copy
-
# Sort the refs, just reads nicer
for rna_refs in rna_references_dict.values():
rna_refs.sort()
@@ -574,6 +580,16 @@ def BuildRNAInfo():
for prop in func.return_values:
prop.build()
+ if 1:
+ for rna_info in InfoStructRNA.global_lookup.values():
+ for prop in rna_info.properties:
+ # ERROR CHECK
+ default = prop.default
+ if type(default) in (float, int):
+ if default < prop.min or default > prop.max:
+ print("\t %s.%s, %s not in [%s - %s]" % (rna_info.identifier, prop.identifier, default, prop.min, prop.max))
+
+
# now for operators
op_mods = dir(bpy.ops)
@@ -604,3 +620,23 @@ def BuildRNAInfo():
# print(rna_info)
return InfoStructRNA.global_lookup, InfoFunctionRNA.global_lookup, InfoOperatorRNA.global_lookup, InfoPropertyRNA.global_lookup
+
+
+if __name__ == "__main__":
+ import rna_info
+ struct = rna_info.BuildRNAInfo()[0]
+ data = ""
+ for struct_id, v in sorted(struct.items()):
+ struct_id_str = "".join(sid for sid in struct_id if struct_id)
+ props = [(prop.identifier, prop) for prop in v.properties]
+
+ for prop_id, prop in sorted(props):
+ if prop.type == 'boolean':
+ continue
+ data += "%s.%s -> %s: %s%s %s\n" % (struct_id_str, prop.identifier, prop.identifier, prop.type, ", (read-only)" if prop.is_readonly else "", prop.description)
+
+ if bpy.app.background:
+ print(data)
+ else:
+ text = bpy.data.texts.new(name="api.py")
+ text.from_string(data)
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index 246fa4bdb7d..3e8662c275f 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -61,7 +61,7 @@ def rna_idprop_ui_prop_clear(item, prop):
def draw(layout, context, context_member, use_edit=True):
def assign_props(prop, val, key):
- prop.path = context_member
+ prop.data_path = context_member
prop.property = key
try:
@@ -81,7 +81,7 @@ def draw(layout, context, context_member, use_edit=True):
if use_edit:
row = layout.row()
props = row.operator("wm.properties_add", text="Add")
- props.path = context_member
+ props.data_path = context_member
del row
for key, val in items:
@@ -140,7 +140,7 @@ from bpy.props import *
rna_path = StringProperty(name="Property Edit",
- description="Property path edit", maxlen=1024, default="", options={'HIDDEN'})
+ description="Property data_path edit", maxlen=1024, default="", options={'HIDDEN'})
rna_value = StringProperty(name="Property Value",
description="Property value edit", maxlen=1024, default="")
@@ -153,11 +153,11 @@ rna_max = FloatProperty(name="Max", default=1.0, precision=3)
class WM_OT_properties_edit(bpy.types.Operator):
- '''Internal use (edit a property path)'''
+ '''Internal use (edit a property data_path)'''
bl_idname = "wm.properties_edit"
bl_label = "Edit Property"
- path = rna_path
+ data_path = rna_path
property = rna_property
value = rna_value
min = rna_min
@@ -165,7 +165,7 @@ class WM_OT_properties_edit(bpy.types.Operator):
description = StringProperty(name="Tip", default="")
def execute(self, context):
- path = self.properties.path
+ data_path = self.properties.data_path
value = self.properties.value
prop = self.properties.property
prop_old = self._last_prop[0]
@@ -176,7 +176,7 @@ class WM_OT_properties_edit(bpy.types.Operator):
value_eval = value
# First remove
- item = eval("context.%s" % path)
+ item = eval("context.%s" % data_path)
rna_idprop_ui_prop_clear(item, prop_old)
exec_str = "del item['%s']" % prop_old
@@ -207,7 +207,7 @@ class WM_OT_properties_edit(bpy.types.Operator):
self._last_prop = [self.properties.property]
- item = eval("context.%s" % self.properties.path)
+ item = eval("context.%s" % self.properties.data_path)
# setup defaults
prop_ui = rna_idprop_ui_prop_get(item, self.properties.property, False) # dont create
@@ -225,14 +225,14 @@ class WM_OT_properties_edit(bpy.types.Operator):
class WM_OT_properties_add(bpy.types.Operator):
- '''Internal use (edit a property path)'''
+ '''Internal use (edit a property data_path)'''
bl_idname = "wm.properties_add"
bl_label = "Add Property"
- path = rna_path
+ data_path = rna_path
def execute(self, context):
- item = eval("context.%s" % self.properties.path)
+ item = eval("context.%s" % self.properties.data_path)
def unique_name(names):
prop = 'prop'
@@ -251,14 +251,14 @@ class WM_OT_properties_add(bpy.types.Operator):
class WM_OT_properties_remove(bpy.types.Operator):
- '''Internal use (edit a property path)'''
+ '''Internal use (edit a property data_path)'''
bl_idname = "wm.properties_remove"
- bl_label = "Add Property"
+ bl_label = "Remove Property"
- path = rna_path
+ data_path = rna_path
property = rna_property
def execute(self, context):
- item = eval("context.%s" % self.properties.path)
+ item = eval("context.%s" % self.properties.data_path)
del item[self.properties.property]
return {'FINISHED'}
diff --git a/release/scripts/op/add_armature_human.py b/release/scripts/op/add_armature_human.py
index 1944e73de1b..164bbfb100b 100644
--- a/release/scripts/op/add_armature_human.py
+++ b/release/scripts/op/add_armature_human.py
@@ -18,7 +18,7 @@
# <pep8-80 compliant>
import bpy
-import Mathutils
+import mathutils
from math import cos, sin, pi
# could this be stored elsewhere?
@@ -609,10 +609,10 @@ def register():
bpy.types.register(AddHuman)
bpy.types.INFO_MT_armature_add.append(menu_func)
+
def unregister():
bpy.types.unregister(AddHuman)
bpy.types.INFO_MT_armature_add.remove(menu_func)
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/op/add_mesh_torus.py b/release/scripts/op/add_mesh_torus.py
index e7c7ac86ee6..16bf4e1c92c 100644
--- a/release/scripts/op/add_mesh_torus.py
+++ b/release/scripts/op/add_mesh_torus.py
@@ -18,13 +18,13 @@
# <pep8 compliant>
import bpy
-import Mathutils
+import mathutils
from math import cos, sin, pi
def add_torus(major_rad, minor_rad, major_seg, minor_seg):
- Vector = Mathutils.Vector
- Quaternion = Mathutils.Quaternion
+ Vector = mathutils.Vector
+ Quaternion = mathutils.Quaternion
PI_2 = pi * 2
z_axis = (0, 0, 1)
@@ -39,10 +39,10 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg):
for minor_index in range(minor_seg):
angle = 2 * pi * minor_index / minor_seg
- vec = Vector(major_rad + (cos(angle) * minor_rad), 0.0,
- (sin(angle) * minor_rad)) * quat
+ vec = Vector((major_rad + (cos(angle) * minor_rad), 0.0,
+ (sin(angle) * minor_rad))) * quat
- verts.extend([vec.x, vec.y, vec.z])
+ verts.extend(vec[:])
if minor_index + 1 == minor_seg:
i2 = (major_index) * minor_seg
@@ -102,6 +102,10 @@ class AddTorus(bpy.types.Operator):
description="Total Interior Radius of the torus",
default=0.5, min=0.01, max=100.0)
+ # generic transform props
+ location = FloatVectorProperty(name="Location")
+ rotation = FloatVectorProperty(name="Rotation")
+
def execute(self, context):
props = self.properties
@@ -120,44 +124,16 @@ class AddTorus(bpy.types.Operator):
mesh.add_geometry(int(len(verts_loc) / 3), 0, int(len(faces) / 4))
mesh.verts.foreach_set("co", verts_loc)
mesh.faces.foreach_set("verts_raw", faces)
- mesh.faces.foreach_set("smooth", [False] * len(mesh.faces))
-
- scene = context.scene
-
- # ugh
- for ob in scene.objects:
- ob.selected = False
-
mesh.update()
- ob_new = bpy.data.objects.new("Torus", mesh)
- scene.objects.link(ob_new)
- ob_new.selected = True
-
- ob_new.location = scene.cursor_location
-
- obj_act = scene.objects.active
-
- if obj_act and obj_act.mode == 'EDIT':
- bpy.ops.object.mode_set(mode='OBJECT')
-
- obj_act.selected = True
- scene.update() # apply location
- #scene.objects.active = ob_new
-
- bpy.ops.object.join() # join into the active.
- bpy.ops.object.mode_set(mode='EDIT')
- else:
- scene.objects.active = ob_new
- if context.user_preferences.edit.enter_edit_mode:
- bpy.ops.object.mode_set(mode='EDIT')
+ import add_object_utils
+ add_object_utils.add_object_data(context, mesh, operator=self)
return {'FINISHED'}
-# Add to the menu
-menu_func = (lambda self, context: self.layout.operator(AddTorus.bl_idname,
- text="Torus", icon='MESH_DONUT'))
+def menu_func(self, context):
+ self.layout.operator(AddTorus.bl_idname, text="Torus", icon='MESH_DONUT')
def register():
diff --git a/release/scripts/op/fcurve_euler_filter.py b/release/scripts/op/fcurve_euler_filter.py
index 1c9e9a73312..bba4576ef73 100644
--- a/release/scripts/op/fcurve_euler_filter.py
+++ b/release/scripts/op/fcurve_euler_filter.py
@@ -1,6 +1,6 @@
from math import *
import bpy
-from Mathutils import *
+from mathutils import *
def main(context):
def cleanupEulCurve(fcv):
diff --git a/release/scripts/op/image.py b/release/scripts/op/image.py
index ea5177b1503..be583012d7a 100644
--- a/release/scripts/op/image.py
+++ b/release/scripts/op/image.py
@@ -19,6 +19,67 @@
# <pep8 compliant>
import bpy
+from bpy.props import StringProperty
+
+
+class EditExternally(bpy.types.Operator):
+ '''Edit image in an external application'''
+ bl_idname = "image.external_edit"
+ bl_label = "Image Edit Externally"
+ bl_options = {'REGISTER'}
+
+ filepath = StringProperty(name="File Path", description="Path to an image file", maxlen=1024, default="")
+
+ def _editor_guess(self, context):
+ import platform
+ system = platform.system()
+
+ image_editor = context.user_preferences.filepaths.image_editor
+
+ # use image editor in the preferences when available.
+ if not image_editor:
+ if system == 'Windows':
+ image_editor = ["start"] # not tested!
+ elif system == 'Darwin':
+ image_editor = ["open"]
+ else:
+ image_editor = ["gimp"]
+ else:
+ if system == 'Darwin':
+ # blender file selector treats .app as a folder
+ # and will include a trailing backslash, so we strip it.
+ image_editor.rstrip('\\')
+ image_editor = ["open", "-a", image_editor]
+ else:
+ image_editor = [image_editor]
+
+ return image_editor
+
+ def execute(self, context):
+ import subprocess
+ filepath = self.properties.filepath
+ image_editor = self._editor_guess(context)
+
+ cmd = []
+ cmd.extend(image_editor)
+ cmd.append(bpy.utils.expandpath(filepath))
+
+ subprocess.Popen(cmd)
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ try:
+ filepath = context.space_data.image.filepath
+ except:
+ self.report({'ERROR'}, "Image not found on disk")
+ return {'CANCELLED'}
+
+ self.properties.filepath = filepath
+ self.execute(context)
+
+ return {'FINISHED'}
+
class SaveDirty(bpy.types.Operator):
'''Select object matching a naming pattern'''
@@ -30,23 +91,118 @@ class SaveDirty(bpy.types.Operator):
unique_paths = set()
for image in bpy.data.images:
if image.dirty:
- path = bpy.utils.expandpath(image.filename)
- if "\\" not in path and "/" not in path:
- self.report({'WARNING'}, "Invalid path: " + path)
- elif path in unique_paths:
- self.report({'WARNING'}, "Path used by more then one image: " + path)
+ filepath = bpy.utils.expandpath(image.filepath)
+ if "\\" not in filepath and "/" not in filepath:
+ self.report({'WARNING'}, "Invalid path: " + filepath)
+ elif filepath in unique_paths:
+ self.report({'WARNING'}, "Path used by more then one image: " + filepath)
else:
- unique_paths.add(path)
+ unique_paths.add(filepath)
image.save()
return {'FINISHED'}
+class ProjectEdit(bpy.types.Operator):
+ '''Select object matching a naming pattern'''
+ bl_idname = "image.project_edit"
+ bl_label = "Project Edit"
+ bl_options = {'REGISTER'}
+
+ _proj_hack = [""]
+
+ def execute(self, context):
+ import os
+ import subprocess
+
+ EXT = "png" # could be made an option but for now ok
+
+ for image in bpy.data.images:
+ image.tag = True
+
+ bpy.ops.paint.image_from_view()
+
+ image_new = None
+ for image in bpy.data.images:
+ if not image.tag:
+ image_new = image
+ break
+
+ if not image_new:
+ self.report({'ERROR'}, "Could not make new image")
+ return {'CANCELLED'}
+
+ filepath = os.path.basename(bpy.data.filepath)
+ filepath = os.path.splitext(filepath)[0]
+ # filepath = bpy.utils.clean_name(filepath) # fixes <memory> rubbish, needs checking
+
+ if filepath.startswith(".") or filepath == "":
+ # TODO, have a way to check if the file is saved, assume .B25.blend
+ tmpdir = context.user_preferences.filepaths.temporary_directory
+ filepath = os.path.join(tmpdir, "project_edit")
+ else:
+ filepath = "//" + filepath
+
+ obj = context.object
+
+ if obj:
+ filepath += "_" + bpy.utils.clean_name(obj.name)
+
+ filepath_final = filepath + "." + EXT
+ i = 0
+
+ while os.path.exists(bpy.utils.expandpath(filepath_final)):
+ filepath_final = filepath + ("%.3d.%s" % (i, EXT))
+ i += 1
+
+ image_new.name = os.path.basename(filepath_final)
+ ProjectEdit._proj_hack[0] = image_new.name
+
+ image_new.filepath_raw = filepath_final # TODO, filepath raw is crummy
+ image_new.file_format = 'PNG'
+ image_new.save()
+
+ bpy.ops.image.external_edit(filepath=filepath_final)
+
+ return {'FINISHED'}
+
+
+class ProjectApply(bpy.types.Operator):
+ '''Select object matching a naming pattern'''
+ bl_idname = "image.project_apply"
+ bl_label = "Project Apply"
+ bl_options = {'REGISTER'}
+
+ def execute(self, context):
+ image_name = ProjectEdit._proj_hack[0] # TODO, deal with this nicer
+
+ try:
+ image = bpy.data.images[image_name]
+ except KeyError:
+ self.report({'ERROR'}, "Could not find image '%s'" % image_name)
+ return {'CANCELLED'}
+
+ image.reload()
+ bpy.ops.paint.project_image(image=image_name)
+
+ return {'FINISHED'}
+
+classes = [
+ EditExternally,
+ SaveDirty,
+ ProjectEdit,
+ ProjectApply]
+
+
def register():
- bpy.types.register(SaveDirty)
+ register = bpy.types.register
+ for cls in classes:
+ register(cls)
def unregister():
- bpy.types.unregister(SaveDirty)
+ unregister = bpy.types.unregister
+ for cls in classes:
+ unregister(cls)
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/mesh.py b/release/scripts/op/mesh.py
index 3989e51b6ca..78ca9a18cdc 100644
--- a/release/scripts/op/mesh.py
+++ b/release/scripts/op/mesh.py
@@ -76,7 +76,7 @@ class MeshMirrorUV(bpy.types.Operator):
def execute(self, context):
DIR = 1 # TODO, make an option
- from Mathutils import Vector
+ from mathutils import Vector
ob = context.active_object
is_editmode = (ob.mode == 'EDIT')
diff --git a/release/scripts/op/nla.py b/release/scripts/op/nla.py
new file mode 100644
index 00000000000..d0c53758ba9
--- /dev/null
+++ b/release/scripts/op/nla.py
@@ -0,0 +1,190 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+
+
+def pose_info():
+ from mathutils import Matrix
+
+ info = {}
+
+ obj = bpy.context.object
+ pose = obj.pose
+
+ pose_items = pose.bones.items()
+
+ for name, pbone in pose_items:
+ binfo = {}
+ bone = pbone.bone
+
+ binfo["parent"] = getattr(bone.parent, "name", None)
+ binfo["bone"] = bone
+ binfo["pbone"] = pbone
+ binfo["matrix_local"] = bone.matrix_local.copy()
+ try:
+ binfo["matrix_local_inv"] = binfo["matrix_local"].copy().invert()
+ except:
+ binfo["matrix_local_inv"] = Matrix()
+
+ binfo["matrix"] = bone.matrix.copy()
+ binfo["matrix_pose"] = pbone.matrix.copy()
+ try:
+ binfo["matrix_pose_inv"] = binfo["matrix_pose"].copy().invert()
+ except:
+ binfo["matrix_pose_inv"] = Matrix()
+
+ print(binfo["matrix_pose"])
+ info[name] = binfo
+
+ for name, pbone in pose_items:
+ binfo = info[name]
+ binfo_parent = binfo.get("parent", None)
+ if binfo_parent:
+ binfo_parent = info[binfo_parent]
+
+ matrix = binfo["matrix_pose"]
+ rest_matrix = binfo["matrix_local"]
+
+ if binfo_parent:
+ matrix = binfo_parent["matrix_pose_inv"] * matrix
+ rest_matrix = binfo_parent["matrix_local_inv"] * rest_matrix
+
+ matrix = rest_matrix.copy().invert() * matrix
+
+ binfo["matrix_key"] = matrix.copy()
+
+ return info
+
+
+def bake(frame_start, frame_end, step=1, only_selected=False):
+ # import nla; reload(nla); nla.bake()
+
+ scene = bpy.context.scene
+ obj = bpy.context.object
+ pose = obj.pose
+
+ info_ls = []
+
+ frame_range = range(frame_start, frame_end + 1, step)
+
+ # could spped this up by applying steps here too...
+ for f in frame_range:
+ scene.set_frame(f)
+
+ info = pose_info()
+ info_ls.append(info)
+ f += 1
+
+ action = bpy.data.actions.new("Action")
+
+ bpy.context.object.animation_data.action = action
+
+ pose_items = pose.bones.items()
+
+ for name, pbone in pose_items:
+ if only_selected and not pbone.selected:
+ continue
+
+ for f in frame_range:
+ matrix = info_ls[int((f - frame_start) / step)][name]["matrix_key"]
+
+ #pbone.location = matrix.translation_part()
+ #pbone.rotation_quaternion = matrix.to_quat()
+ pbone.matrix_local = [f for v in matrix for f in v]
+
+ pbone.keyframe_insert("location", -1, f, name)
+
+ rotation_mode = pbone.rotation_mode
+
+ if rotation_mode == 'QUATERNION':
+ pbone.keyframe_insert("rotation_quaternion", -1, f, name)
+ elif rotation_mode == 'AXIS_ANGLE':
+ pbone.keyframe_insert("rotation_axis_angle", -1, f, name)
+ else: # euler, XYZ, ZXY etc
+ pbone.keyframe_insert("rotation_euler", -1, f, name)
+
+ pbone.keyframe_insert("scale", -1, f, name)
+
+ return action
+
+
+from bpy.props import *
+
+
+class BakeAction(bpy.types.Operator):
+ '''Bake animation to an Action'''
+ bl_idname = "nla.bake"
+ bl_label = "Bake Action"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ frame_start = IntProperty(name="Start Frame",
+ description="Start frame for baking",
+ default=1, min=1, max=300000)
+ frame_end = IntProperty(name="End Frame",
+ description="End frame for baking",
+ default=250, min=1, max=300000)
+ step = IntProperty(name="Frame Step",
+ description="Frame Step",
+ default=1, min=1, max=120)
+ only_selected = BoolProperty(name="Only Selected",
+ default=True)
+
+ def execute(self, context):
+ props = self.properties
+
+ action = bake(props.frame_start, props.frame_end, props.step, props.only_selected)
+
+ # basic cleanup, could move elsewhere
+ for fcu in action.fcurves:
+ keyframe_points = fcu.keyframe_points
+ i = 1
+ while i < len(fcu.keyframe_points) - 1:
+ val_prev = keyframe_points[i - 1].co[1]
+ val_next = keyframe_points[i + 1].co[1]
+ val = keyframe_points[i].co[1]
+
+ if abs(val - val_prev) + abs(val - val_next) < 0.0001:
+ keyframe_points.remove(keyframe_points[i])
+ else:
+ i += 1
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ wm = context.manager
+ return wm.invoke_props_dialog(self)
+
+
+#def menu_func(self, context):
+# self.layout.operator(BakeAction.bl_idname, text="Bake Armature Action")
+
+
+def register():
+ bpy.types.register(BakeAction)
+ # bpy.types.INFO_MT_mesh_add.append(menu_func)
+
+
+def unregister():
+ bpy.types.unregister(BakeAction)
+ # bpy.types.INFO_MT_mesh_add.remove(menu_func)
+
+if __name__ == "__main__":
+ register()
diff --git a/release/scripts/op/object.py b/release/scripts/op/object.py
index 5ff25a47b2f..b16d2b0dcf2 100644
--- a/release/scripts/op/object.py
+++ b/release/scripts/op/object.py
@@ -113,24 +113,42 @@ class SelectHierarchy(bpy.types.Operator):
return context.object
def execute(self, context):
- obj = context.object
- if self.properties.direction == 'PARENT':
- parent = obj.parent
- if not parent:
- return {'CANCELLED'}
- obj_act = parent
- else:
- children = obj.children
- if len(children) != 1:
- return {'CANCELLED'}
- obj_act = children[0]
+ objs = context.selected_objects
+ obj_act = context.object
+
+ if context.object not in objs:
+ objs.append(context.object)
if not self.properties.extend:
- # obj.selected = False
+ # for obj in objs:
+ # obj.selected = False
bpy.ops.object.select_all(action='DESELECT')
- obj_act.selected = True
- context.scene.objects.active = obj_act
+ if self.properties.direction == 'PARENT':
+ parents = []
+ for obj in objs:
+ parent = obj.parent
+
+ if parent:
+ parents.append(parent)
+
+ if obj_act == obj:
+ context.scene.objects.active = parent
+
+ parent.selected = True
+
+ if parents:
+ return {'CANCELLED'}
+
+ else:
+ children = []
+ for obj in objs:
+ children += list(obj.children)
+ for obj_iter in children:
+ obj_iter.selected = True
+
+ children.sort(key=lambda obj_iter: obj_iter.name)
+ context.scene.objects.active = children[0]
return {'FINISHED'}
@@ -235,8 +253,8 @@ class ShapeTransfer(bpy.types.Operator):
ob.active_shape_key_index = len(me.shape_keys.keys) - 1
ob.shape_key_lock = True
- from Geometry import BarycentricTransform
- from Mathutils import Vector
+ from geometry import BarycentricTransform
+ from mathutils import Vector
if use_clamp and mode == 'OFFSET':
use_clamp = False
@@ -383,6 +401,7 @@ class ShapeTransfer(bpy.types.Operator):
return {'CANCELLED'}
return self._main(ob_act, objects, self.properties.mode, self.properties.use_clamp)
+
class JoinUVs(bpy.types.Operator):
'''Copy UV Layout to objects with matching geometry'''
bl_idname = "object.join_uvs"
@@ -440,6 +459,7 @@ class JoinUVs(bpy.types.Operator):
self._main(context)
return {'FINISHED'}
+
class MakeDupliFace(bpy.types.Operator):
'''Make linked objects into dupli-faces'''
bl_idname = "object.make_dupli_face"
@@ -450,12 +470,12 @@ class MakeDupliFace(bpy.types.Operator):
return (obj and obj.type == 'MESH')
def _main(self, context):
- from Mathutils import Vector
+ from mathutils import Vector
from math import sqrt
SCALE_FAC = 0.01
offset = 0.5 * SCALE_FAC
- base_tri = Vector(-offset, -offset, 0.0), Vector(offset, -offset, 0.0), Vector(offset, offset, 0.0), Vector(-offset, offset, 0.0)
+ base_tri = Vector((-offset, -offset, 0.0)), Vector((offset, -offset, 0.0)), Vector((offset, offset, 0.0)), Vector((-offset, offset, 0.0))
def matrix_to_quat(matrix):
# scale = matrix.median_scale
@@ -471,7 +491,7 @@ class MakeDupliFace(bpy.types.Operator):
linked.setdefault(data, []).append(obj)
for data, objects in linked.items():
- face_verts = [axis for obj in objects for v in matrix_to_quat(obj.matrix) for axis in v]
+ face_verts = [axis for obj in objects for v in matrix_to_quat(obj.matrix_world) for axis in v]
faces = list(range(int(len(face_verts) / 3)))
mesh = bpy.data.meshes.new(data.name + "_dupli")
@@ -505,6 +525,26 @@ class MakeDupliFace(bpy.types.Operator):
return {'FINISHED'}
+class IsolateTypeRender(bpy.types.Operator):
+ '''Select object matching a naming pattern'''
+ bl_idname = "object.isolate_type_render"
+ bl_label = "Isolate Render Selection"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ def execute(self, context):
+ act_type = context.object.type
+
+ for obj in context.visible_objects:
+
+ if obj.selected:
+ obj.restrict_render = False
+ else:
+ if obj.type == act_type:
+ obj.restrict_render = True
+
+ return {'FINISHED'}
+
+
classes = [
SelectPattern,
SelectCamera,
@@ -512,6 +552,7 @@ classes = [
SubdivisionSet,
ShapeTransfer,
JoinUVs,
+ IsolateTypeRender,
MakeDupliFace]
@@ -520,6 +561,7 @@ def register():
for cls in classes:
register(cls)
+
def unregister():
unregister = bpy.types.unregister
for cls in classes:
@@ -527,4 +569,3 @@ def unregister():
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/op/object_align.py b/release/scripts/op/object_align.py
index c5fcc3d2a32..6e5eef0fbc2 100644
--- a/release/scripts/op/object_align.py
+++ b/release/scripts/op/object_align.py
@@ -19,22 +19,22 @@
# <pep8 compliant>
import bpy
-from Mathutils import Vector
+from mathutils import Vector
def align_objects(align_x, align_y, align_z, align_mode, relative_to):
cursor = bpy.context.scene.cursor_location
- Left_Up_Front_SEL = [[],[],[]]
- Right_Down_Back_SEL = [[],[],[]]
+ Left_Up_Front_SEL = [[], [], []]
+ Right_Down_Back_SEL = [[], [], []]
flag_first = True
for obj in bpy.context.selected_objects:
if obj.type == 'MESH':
- bb_world = [obj.matrix * Vector(v[:]) for v in obj.bound_box]
+ bb_world = [obj.matrix_world * Vector(v[:]) for v in obj.bound_box]
Left_Up_Front = bb_world[1]
Right_Down_Back = bb_world[7]
@@ -43,13 +43,13 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to):
if obj == bpy.context.active_object:
- center_active_x = ( Left_Up_Front[0] + Right_Down_Back[0] ) / 2
- center_active_y = ( Left_Up_Front[1] + Right_Down_Back[1] ) / 2
- center_active_z = ( Left_Up_Front[2] + Right_Down_Back[2] ) / 2
+ center_active_x = (Left_Up_Front[0] + Right_Down_Back[0]) / 2
+ center_active_y = (Left_Up_Front[1] + Right_Down_Back[1]) / 2
+ center_active_z = (Left_Up_Front[2] + Right_Down_Back[2]) / 2
- size_active_x = ( Right_Down_Back[0] - Left_Up_Front[0] ) / 2
- size_active_y = ( Right_Down_Back[1] - Left_Up_Front[1] ) / 2
- size_active_z = ( Left_Up_Front[2] - Right_Down_Back[2] ) / 2
+ size_active_x = (Right_Down_Back[0] - Left_Up_Front[0]) / 2
+ size_active_y = (Right_Down_Back[1] - Left_Up_Front[1]) / 2
+ size_active_z = (Left_Up_Front[2] - Right_Down_Back[2]) / 2
# Selection Center
@@ -85,9 +85,9 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to):
if Right_Down_Back[2] < Right_Down_Back_SEL[2]:
Right_Down_Back_SEL[2] = Right_Down_Back[2]
- center_sel_x = ( Left_Up_Front_SEL[0] + Right_Down_Back_SEL[0] ) / 2
- center_sel_y = ( Left_Up_Front_SEL[1] + Right_Down_Back_SEL[1] ) / 2
- center_sel_z = ( Left_Up_Front_SEL[2] + Right_Down_Back_SEL[2] ) / 2
+ center_sel_x = (Left_Up_Front_SEL[0] + Right_Down_Back_SEL[0]) / 2
+ center_sel_y = (Left_Up_Front_SEL[1] + Right_Down_Back_SEL[1]) / 2
+ center_sel_z = (Left_Up_Front_SEL[2] + Right_Down_Back_SEL[2]) / 2
# Main Loop
@@ -95,14 +95,14 @@ def align_objects(align_x, align_y, align_z, align_mode, relative_to):
if obj.type == 'MESH':
loc_world = obj.location
- bb_world = [obj.matrix * Vector(v[:]) for v in obj.bound_box]
+ bb_world = [obj.matrix_world * Vector(v[:]) for v in obj.bound_box]
Left_Up_Front = bb_world[1]
Right_Down_Back = bb_world[7]
- center_x = ( Left_Up_Front[0] + Right_Down_Back[0] ) / 2
- center_y = ( Left_Up_Front[1] + Right_Down_Back[1] ) / 2
- center_z = ( Left_Up_Front[2] + Right_Down_Back[2] ) / 2
+ center_x = (Left_Up_Front[0] + Right_Down_Back[0]) / 2
+ center_y = (Left_Up_Front[1] + Right_Down_Back[1]) / 2
+ center_z = (Left_Up_Front[2] + Right_Down_Back[2]) / 2
positive_x = Right_Down_Back[0]
positive_y = Right_Down_Back[1]
@@ -240,8 +240,7 @@ class AlignObjects(bpy.types.Operator):
align_mode = bpy.props.EnumProperty(items=(
('OPT_1', "Negative Sides", ""),
('OPT_2', "Centers", ""),
- ('OPT_3', "Positive Sides", "")
- ),
+ ('OPT_3', "Positive Sides", "")),
name="Align Mode:",
description="",
default='OPT_2')
@@ -250,8 +249,7 @@ class AlignObjects(bpy.types.Operator):
('OPT_1', "Scene Origin", ""),
('OPT_2', "3D Cursor", ""),
('OPT_3', "Selection", ""),
- ('OPT_4', "Active", "")
- ),
+ ('OPT_4', "Active", "")),
name="Relative To:",
description="",
default='OPT_4')
diff --git a/release/scripts/op/object_randomize_transform.py b/release/scripts/op/object_randomize_transform.py
index 3d3feb66424..89884b1767f 100644
--- a/release/scripts/op/object_randomize_transform.py
+++ b/release/scripts/op/object_randomize_transform.py
@@ -25,12 +25,12 @@ def randomize_selected(seed, loc, rot, scale, scale_even, scale_min):
import random
from random import uniform
- from Mathutils import Vector
+ from mathutils import Vector
random.seed(seed)
def rand_vec(vec_range):
- return Vector([uniform(- val, val) for val in vec_range])
+ return Vector([uniform(-val, val) for val in vec_range])
for obj in bpy.context.selected_objects:
diff --git a/release/scripts/op/presets.py b/release/scripts/op/presets.py
index 1a8e57f7c32..f80c5e69ddd 100644
--- a/release/scripts/op/presets.py
+++ b/release/scripts/op/presets.py
@@ -27,8 +27,8 @@ class AddPresetBase(bpy.types.Operator):
subclasses must define
- preset_values
- preset_subdir '''
- bl_idname = "render.preset_add"
- bl_label = "Add Render Preset"
+ # bl_idname = "script.preset_base_add"
+ # bl_label = "Add a Python Preset"
name = bpy.props.StringProperty(name="Name", description="Name of the preset, used to make the path name", maxlen=64, default="")
@@ -46,14 +46,18 @@ class AddPresetBase(bpy.types.Operator):
target_path = bpy.utils.preset_paths(self.preset_subdir)[0] # we need some way to tell the user and system preset path
- file_preset = open(os.path.join(target_path, filename), 'w')
+ filepath = os.path.join(target_path, filename)
+ if getattr(self, "save_keyconfig", False):
+ bpy.ops.wm.keyconfig_export(filepath=filepath, kc_name=self.properties.name)
+ file_preset = open(filepath, 'a')
+ file_preset.write("wm.active_keyconfig = kc\n\n")
+ else:
+ file_preset = open(filepath, 'w')
+ file_preset.write("import bpy\n")
for rna_path in self.preset_values:
value = eval(rna_path)
- if type(value) == str:
- value = "'%s'" % value
-
- file_preset.write("%s = %s\n" % (rna_path, value))
+ file_preset.write("%s = %s\n" % (rna_path, repr(value)))
file_preset.close()
@@ -68,6 +72,25 @@ class AddPresetBase(bpy.types.Operator):
return {'RUNNING_MODAL'}
+class ExecutePreset(bpy.types.Operator):
+ ''' Executes a preset '''
+ bl_idname = "script.execute_preset"
+ bl_label = "Execute a Python Preset"
+
+ filepath = bpy.props.StringProperty(name="Path", description="Path of the Python file to execute", maxlen=512, default="")
+ preset_name = bpy.props.StringProperty(name="Preset Name", description="Name of the Preset being executed", default="")
+ menu_idname = bpy.props.StringProperty(name="Menu ID Name", description="ID name of the menu this was called from", default="")
+
+ def execute(self, context):
+ # change the menu title to the most recently chosen option
+ preset_class = getattr(bpy.types, self.properties.menu_idname)
+ preset_class.bl_label = self.properties.preset_name
+
+ # execute the preset using script.python_file_run
+ bpy.ops.script.python_file_run(filepath=self.properties.filepath)
+ return {'FINISHED'}
+
+
class AddPresetRender(AddPresetBase):
'''Add a Render Preset'''
bl_idname = "render.preset_add"
@@ -158,11 +181,35 @@ class AddPresetSunSky(AddPresetBase):
preset_subdir = "sunsky"
+class AddPresetInteraction(AddPresetBase):
+ '''Add an Application Interaction Preset'''
+ bl_idname = "wm.interaction_preset_add"
+ bl_label = "Add Interaction Preset"
+ name = AddPresetBase.name
+ save_keyconfig = True
+
+ preset_values = [
+ "bpy.context.user_preferences.edit.drag_immediately",
+ "bpy.context.user_preferences.edit.insertkey_xyz_to_rgb",
+ "bpy.context.user_preferences.inputs.select_mouse",
+ "bpy.context.user_preferences.inputs.zoom_style",
+ "bpy.context.user_preferences.inputs.zoom_axis",
+ "bpy.context.user_preferences.inputs.view_rotation",
+ "bpy.context.user_preferences.inputs.invert_zoom_direction",
+ "bpy.context.user_preferences.inputs.emulate_numpad",
+ "bpy.context.user_preferences.inputs.emulate_3_button_mouse",
+ "bpy.context.user_preferences.inputs.continuous_mouse",
+ ]
+
+ preset_subdir = "interaction"
+
classes = [
+ ExecutePreset,
AddPresetRender,
AddPresetSSS,
AddPresetCloth,
- AddPresetSunSky]
+ AddPresetSunSky,
+ AddPresetInteraction]
def register():
diff --git a/release/scripts/op/screen_play_rendered_anim.py b/release/scripts/op/screen_play_rendered_anim.py
index 17087183c7d..2ecd445df1d 100644
--- a/release/scripts/op/screen_play_rendered_anim.py
+++ b/release/scripts/op/screen_play_rendered_anim.py
@@ -25,36 +25,40 @@
# Originally written by Matt Ebb
import bpy
-import subprocess
import os
-import platform
def guess_player_path(preset):
+ import platform
+ system = platform.system()
+
if preset == 'BLENDER24':
- player_path = 'blender'
+ player_path = "blender"
- if platform.system() == 'Darwin':
- test_path = '/Applications/blender 2.49.app/Contents/MacOS/blender'
- elif platform.system() == 'Windows':
- test_path = '/Program Files/Blender Foundation/Blender/blender.exe'
+ if system == 'Darwin':
+ test_path = "/Applications/blender 2.49.app/Contents/MacOS/blender"
+ elif system == 'Windows':
+ test_path = "/Program Files/Blender Foundation/Blender/blender.exe"
if os.path.exists(test_path):
player_path = test_path
elif preset == 'DJV':
- player_path = 'djv_view'
+ player_path = "djv_view"
- if platform.system() == 'Darwin':
+ if system == 'Darwin':
test_path = '/Applications/djv-0.8.2.app/Contents/Resources/bin/djv_view'
if os.path.exists(test_path):
player_path = test_path
elif preset == 'FRAMECYCLER':
- player_path = 'framecycler'
+ player_path = "framecycler"
elif preset == 'RV':
- player_path = 'rv'
+ player_path = "rv"
+
+ elif preset == 'MPLAYER':
+ player_path = "mplayer"
return player_path
@@ -62,11 +66,13 @@ def guess_player_path(preset):
class PlayRenderedAnim(bpy.types.Operator):
'''Plays back rendered frames/movies using an external player.'''
- bl_idname = "screen.play_rendered_anim"
+ bl_idname = "render.play_rendered_anim"
bl_label = "Play Rendered Animation"
bl_options = {'REGISTER'}
def execute(self, context):
+ import subprocess
+
scene = context.scene
rd = scene.render
prefs = context.user_preferences
@@ -74,18 +80,32 @@ class PlayRenderedAnim(bpy.types.Operator):
preset = prefs.filepaths.animation_player_preset
player_path = prefs.filepaths.animation_player
file_path = bpy.utils.expandpath(rd.output_path)
+ is_movie = rd.is_movie_format
# try and guess a command line if it doesn't exist
if player_path == '':
player_path = guess_player_path(preset)
- if preset in ('FRAMECYCLER', 'RV'):
+ if is_movie == False and preset in ('FRAMECYCLER', 'RV', 'MPLAYER'):
# replace the number with '#'
- file_a, file_b = rd.frame_path(frame=0), rd.frame_path(frame=1)
+ file_a = rd.frame_path(frame=0)
+
+ # TODO, make an api call for this
+ frame_tmp = 9
+ file_b = rd.frame_path(frame=frame_tmp)
+
+ while len(file_a) == len(file_b):
+ frame_tmp = (frame_tmp * 10) + 9
+ print(frame_tmp)
+ file_b = rd.frame_path(frame=frame_tmp)
+ file_b = rd.frame_path(frame=int(frame_tmp / 10))
+
file = ''.join([(c if file_b[i] == c else "#") for i, c in enumerate(file_a)])
else:
# works for movies and images
- file = rd.frame_path(frame=scene.start_frame)
+ file = rd.frame_path(frame=scene.frame_start)
+
+ file = bpy.utils.expandpath(file) # expand '//'
cmd = [player_path]
# extra options, fps controls etc.
@@ -96,11 +116,20 @@ class PlayRenderedAnim(bpy.types.Operator):
opts = [file, "-playback_speed", str(rd.fps)]
cmd.extend(opts)
elif preset == 'FRAMECYCLER':
- opts = [file, "%d-%d" % (scene.start_frame, scene.end_frame)]
+ opts = [file, "%d-%d" % (scene.frame_start, scene.frame_end)]
cmd.extend(opts)
elif preset == 'RV':
opts = ["-fps", str(rd.fps), "-play", "[ %s ]" % file]
cmd.extend(opts)
+ elif preset == 'MPLAYER':
+ opts = []
+ if is_movie:
+ opts.append(file)
+ else:
+ opts.append("mf://%s" % file.replace("#", "?"))
+ opts += ["-mf", "fps=%.4f" % (rd.fps / rd.fps_base)]
+ opts += ["-loop", "0", "-really-quiet", "-fs"]
+ cmd.extend(opts)
else: # 'CUSTOM'
cmd.append(file)
@@ -123,4 +152,3 @@ def unregister():
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/op/sequencer.py b/release/scripts/op/sequencer.py
index 51bb96442e9..13668498aae 100644
--- a/release/scripts/op/sequencer.py
+++ b/release/scripts/op/sequencer.py
@@ -20,6 +20,9 @@
import bpy
+from bpy.props import *
+
+
class SequencerCrossfadeSounds(bpy.types.Operator):
'''Do crossfading volume animation of two selected sound strips.'''
@@ -48,34 +51,101 @@ class SequencerCrossfadeSounds(bpy.types.Operator):
if seq2 == None:
self.report({'ERROR'}, "Select 2 sound strips.")
return {'CANCELLED'}
- if seq1.start_frame_final > seq2.start_frame_final:
+ if seq1.frame_final_start > seq2.frame_final_start:
s = seq1
seq1 = seq2
seq2 = s
- if seq1.end_frame_final > seq2.start_frame_final:
- tempcfra = context.scene.current_frame
- context.scene.current_frame = seq2.start_frame_final
+ if seq1.frame_final_end > seq2.frame_final_start:
+ tempcfra = context.scene.frame_current
+ context.scene.frame_current = seq2.frame_final_start
seq1.keyframe_insert('volume')
- context.scene.current_frame = seq1.end_frame_final
+ context.scene.frame_current = seq1.frame_final_end
seq1.volume = 0
seq1.keyframe_insert('volume')
seq2.keyframe_insert('volume')
- context.scene.current_frame = seq2.start_frame_final
+ context.scene.frame_current = seq2.frame_final_start
seq2.volume = 0
seq2.keyframe_insert('volume')
- context.scene.current_frame = tempcfra
+ context.scene.frame_current = tempcfra
return {'FINISHED'}
else:
self.report({'ERROR'}, "The selected strips don't overlap.")
return {'CANCELLED'}
+class SequencerCutMulticam(bpy.types.Operator):
+ '''Cut multicam strip and select camera.'''
+
+ bl_idname = "sequencer.cut_multicam"
+ bl_label = "Cut multicam"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ camera = IntProperty(name="Camera",
+ default=1, min=1, max=32, soft_min=1, soft_max=32)
+
+ def poll(self, context):
+ if context.scene and context.scene.sequence_editor and context.scene.sequence_editor.active_strip:
+ return context.scene.sequence_editor.active_strip.type == 'MULTICAM'
+ else:
+ return False
+
+ def execute(self, context):
+ camera = self.properties.camera
+
+ s = context.scene.sequence_editor.active_strip
+
+ if s.multicam_source == camera:
+ return {'FINISHED'}
+
+ if not s.selected:
+ s.selected = True
+
+ cfra = context.scene.frame_current
+ bpy.ops.sequencer.cut(frame=cfra, type='SOFT', side='RIGHT')
+ for s in context.scene.sequence_editor.sequences_all:
+ if s.selected and s.type == 'MULTICAM' and s.frame_final_start <= cfra and cfra < s.frame_final_end:
+ context.scene.sequence_editor.active_strip = s
+
+ context.scene.sequence_editor.active_strip.multicam_source = camera
+ return {'FINISHED'}
+
+
+class SequencerDeinterlaceSelectedMovies(bpy.types.Operator):
+ '''Deinterlace all selected movie sources.'''
+
+ bl_idname = "sequencer.deinterlace_selected_movies"
+ bl_label = "Deinterlace Movies"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ def poll(self, context):
+ if context.scene and context.scene.sequence_editor:
+ return True
+ else:
+ return False
+
+ def execute(self, context):
+ for s in context.scene.sequence_editor.sequences_all:
+ if s.selected and s.type == 'MOVIE':
+ s.de_interlace = True
+
+ return {'FINISHED'}
+
+
def register():
- bpy.types.register(SequencerCrossfadeSounds)
+ register = bpy.types.register
+
+ register(SequencerCrossfadeSounds)
+ register(SequencerCutMulticam)
+ register(SequencerDeinterlaceSelectedMovies)
+
def unregister():
- bpy.types.unregister(SequencerCrossfadeSounds)
+ unregister = bpy.types.unregister
+
+ unregister(SequencerCrossfadeSounds)
+ unregister(SequencerCutMulticam)
+ unregister(SequencerDeinterlaceSelectedMovies)
+
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/op/uv.py b/release/scripts/op/uv.py
index f22db9d87a8..51c1695677b 100644
--- a/release/scripts/op/uv.py
+++ b/release/scripts/op/uv.py
@@ -29,7 +29,7 @@ class ExportUVLayout(bpy.types.Operator):
bl_label = "Export UV Layout"
bl_options = {'REGISTER', 'UNDO'}
- path = StringProperty(name="File Path", description="File path used for exporting the SVG file", maxlen=1024, default="")
+ filepath = StringProperty(name="File Path", description="File path used for exporting the SVG file", maxlen=1024, default="")
check_existing = BoolProperty(name="Check Existing", description="Check and warn on overwriting existing files", default=True, options={'HIDDEN'})
export_all = BoolProperty(name="All UV's", description="Export all UVs in this mesh (not just the visible ones)", default=False)
mode = EnumProperty(items=(
@@ -113,7 +113,7 @@ class ExportUVLayout(bpy.types.Operator):
mode = self.properties.mode
- file = open(self.properties.path, "w")
+ file = open(self.properties.filepath, "w")
fw = file.write
if mode == 'SVG':
@@ -123,7 +123,7 @@ class ExportUVLayout(bpy.types.Operator):
fw(' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n')
fw('<svg width="%dpx" height="%dpx" viewBox="0px 0px %dpx %dpx"\n' % (image_width, image_height, image_width, image_height))
fw(' xmlns="http://www.w3.org/2000/svg" version="1.1">\n')
- desc = "%s, %s, %s (Blender %s)" % (basename(bpy.data.filename), obj.name, mesh.name, bpy.app.version_string)
+ desc = "%s, %s, %s (Blender %s)" % (basename(bpy.data.filepath), obj.name, mesh.name, bpy.app.version_string)
fw('<desc>%s</desc>\n' % escape(desc))
# svg colors
@@ -167,18 +167,34 @@ class ExportUVLayout(bpy.types.Operator):
fw('1 setlinewidth\n')
fw('1 setlinejoin\n')
fw('1 setlinecap\n')
+ fw('/DRAW {')
+ # can remove from here to next comment to disable filling, aparently alpha is not supported
+ fw('gsave\n')
+ fw('0.7 setgray\n')
+ fw('fill\n')
+ fw('grestore\n')
+ fw('0 setgray\n')
+ # remove to here
+ fw('stroke\n')
+ fw('} def\n')
fw('newpath\n')
+ firstline = True
for i, uvs in self._face_uv_iter(context):
for j, uv in enumerate(uvs):
x, y = uv[0], uv[1]
if j == 0:
+ if not firstline:
+ fw('closepath\n')
+ fw('DRAW\n')
+ fw('newpath\n')
+ firstline = False
fw('%.5f %.5f moveto\n' % (x * image_width, y * image_height))
else:
fw('%.5f %.5f lineto\n' % (x * image_width, y * image_height))
fw('closepath\n')
- fw('stroke\n')
+ fw('DRAW\n')
fw('showpage\n')
fw('%%EOF\n')
@@ -194,8 +210,9 @@ class ExportUVLayout(bpy.types.Operator):
def menu_func(self, context):
- default_path = bpy.data.filename.replace(".blend", ".svg")
- self.layout.operator(ExportUVLayout.bl_idname).path = default_path
+ import os
+ default_path = os.path.splitext(bpy.data.filepath)[0] + ".svg"
+ self.layout.operator(ExportUVLayout.bl_idname).filepath = default_path
def register():
@@ -203,7 +220,7 @@ def register():
bpy.types.IMAGE_MT_uvs.append(menu_func)
-def unreguster():
+def unregister():
bpy.types.unregister(ExportUVLayout)
bpy.types.IMAGE_MT_uvs.remove(menu_func)
diff --git a/release/scripts/op/uvcalc_follow_active.py b/release/scripts/op/uvcalc_follow_active.py
index a76bd0d3a98..61c149c8735 100644
--- a/release/scripts/op/uvcalc_follow_active.py
+++ b/release/scripts/op/uvcalc_follow_active.py
@@ -65,9 +65,9 @@ def extend(obj, operator, EXTEND_MODE):
# vertex index is the key, uv is the value
- uvs_vhash_source = dict([(vindex, uvs_source[i]) for i, vindex in enumerate(vidx_source)])
+ uvs_vhash_source = {vindex: uvs_source[i] for i, vindex in enumerate(vidx_source)}
- uvs_vhash_target = dict([(vindex, uvs_target[i]) for i, vindex in enumerate(vidx_target)])
+ uvs_vhash_target = {vindex: uvs_target[i] for i, vindex in enumerate(vidx_target)}
edge_idxs_source = face_edge_vs(vidx_source)
edge_idxs_target = face_edge_vs(vidx_target)
@@ -180,7 +180,7 @@ def extend(obj, operator, EXTEND_MODE):
#SEAM = me.edges.seam
if EXTEND_MODE == 'LENGTH':
- edge_loops = me.edge_loops(face_sel, [ed.key for ed in me.edges if ed.seam])
+ edge_loops = me.edge_loops_from_faces(face_sel, [ed.key for ed in me.edges if ed.seam])
me_verts = me.verts
for loop in edge_loops:
looplen = [0.0]
@@ -266,10 +266,10 @@ def register():
bpy.types.register(FollowActiveQuads)
bpy.types.VIEW3D_MT_uv_map.append(menu_func)
+
def unregister():
bpy.types.unregister(FollowActiveQuads)
bpy.types.VIEW3D_MT_uv_map.remove(menu_func)
if __name__ == "__main__":
register()
-
diff --git a/release/scripts/op/uvcalc_smart_project.py b/release/scripts/op/uvcalc_smart_project.py
index c88faae2818..13bf6244f4d 100644
--- a/release/scripts/op/uvcalc_smart_project.py
+++ b/release/scripts/op/uvcalc_smart_project.py
@@ -22,10 +22,9 @@
# <pep8 compliant>
-#from Blender import Object, Draw, Window, sys, Mesh, Geometry
-from Mathutils import Matrix, Vector, RotationMatrix
+from mathutils import Matrix, Vector, RotationMatrix
import time
-import Geometry
+import geometry
import bpy
from math import cos, radians
@@ -200,7 +199,7 @@ def pointInEdges(pt, edges):
"""
def pointInIsland(pt, island):
- vec1 = Vector(); vec2 = Vector(); vec3 = Vector()
+ vec1, vec2, vec3 = Vector(), Vector(), Vector()
for f in island:
vec1.x, vec1.y = f.uv[0]
vec2.x, vec2.y = f.uv[1]
@@ -227,7 +226,7 @@ def islandIntersectUvIsland(source, target, SourceOffset):
# Edge intersect test
for ed in edgeLoopsSource:
for seg in edgeLoopsTarget:
- i = Geometry.LineIntersect2D(\
+ i = geometry.LineIntersect2D(\
seg[0], seg[1], SourceOffset+ed[0], SourceOffset+ed[1])
if i:
return 1 # LINE INTERSECTION
@@ -390,7 +389,7 @@ def mergeUvIslands(islandList):
w, h = maxx-minx, maxy-miny
totFaceArea = 0
- offset= Vector(minx, miny)
+ offset= Vector((minx, miny))
for f in islandList[islandIdx]:
for uv in f.uv:
uv -= offset
@@ -514,7 +513,7 @@ def mergeUvIslands(islandList):
##testcount+=1
#print 'Testing intersect'
- Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, Vector(boxLeft, boxBottom))
+ Intersect = islandIntersectUvIsland(sourceIsland, targetIsland, Vector((boxLeft, boxBottom)))
#print 'Done', Intersect
if Intersect == 1: # Line intersect, dont bother with this any more
pass
@@ -540,7 +539,7 @@ def mergeUvIslands(islandList):
# Move faces into new island and offset
targetIsland[0].extend(sourceIsland[0])
- offset= Vector(boxLeft, boxBottom)
+ offset= Vector((boxLeft, boxBottom))
for f in sourceIsland[0]:
for uv in f.uv:
@@ -565,7 +564,7 @@ def mergeUvIslands(islandList):
targetIsland[7].extend(sourceIsland[7])
- offset= Vector(boxLeft, boxBottom, 0)
+ offset= Vector((boxLeft, boxBottom, 0.0))
for p in sourceIsland[7]:
p+= offset
@@ -741,7 +740,7 @@ def packIslands(islandList):
#XXX Window.DrawProgressBar(0.7, 'Packing %i UV Islands...' % len(packBoxes) )
time1 = time.time()
- packWidth, packHeight = Geometry.BoxPack2D(packBoxes)
+ packWidth, packHeight = geometry.BoxPack2D(packBoxes)
# print 'Box Packing Time:', time.time() - time1
@@ -781,9 +780,9 @@ def packIslands(islandList):
def VectoMat(vec):
a3 = vec.__copy__().normalize()
- up = Vector(0,0,1)
+ up = Vector((0.0, 0.0, 1.0))
if abs(a3.dot(up)) == 1.0:
- up = Vector(0,1,0)
+ up = Vector((0.0, 1.0, 0.0))
a1 = a3.cross(up).normalize()
a2 = a3.cross(a1)
@@ -936,7 +935,7 @@ def main(context, island_margin, projection_limit):
# Initialize projectVecs
if USER_VIEW_INIT:
# Generate Projection
- projectVecs = [Vector(Window.GetViewVector()) * ob.matrixWorld.copy().invert().rotation_part()] # We add to this allong the way
+ projectVecs = [Vector(Window.GetViewVector()) * ob.matrix_world.copy().invert().rotation_part()] # We add to this allong the way
else:
projectVecs = []
@@ -964,7 +963,7 @@ def main(context, island_margin, projection_limit):
newProjectMeshFaces.append(tempMeshFaces.pop(fIdx))
# Add the average of all these faces normals as a projectionVec
- averageVec = Vector(0,0,0)
+ averageVec = Vector((0.0, 0.0, 0.0))
if USER_AREA_WEIGHT:
for fprop in newProjectMeshFaces:
averageVec += (fprop.no * fprop.area)
@@ -1056,7 +1055,7 @@ def main(context, island_margin, projection_limit):
for f in faceProjectionGroupList[i]:
f_uv = f.uv
for j, v in enumerate(f.v):
- # XXX - note, between Mathutils in 2.4 and 2.5 the order changed.
+ # XXX - note, between mathutils in 2.4 and 2.5 the order changed.
f_uv[j][:] = (v.co * MatProj)[:2]
diff --git a/release/scripts/op/vertexpaint_dirt.py b/release/scripts/op/vertexpaint_dirt.py
index f2c2d5bd864..c1521866a56 100644
--- a/release/scripts/op/vertexpaint_dirt.py
+++ b/release/scripts/op/vertexpaint_dirt.py
@@ -34,7 +34,7 @@ import bpy
import math
import time
-from Mathutils import Vector
+from mathutils import Vector
from bpy.props import *
@@ -58,17 +58,22 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
con[e.verts[0]].append(e.verts[1])
con[e.verts[1]].append(e.verts[0])
- for v in me.verts:
+ for i, v in enumerate(me.verts):
vec = Vector()
no = v.normal
co = v.co
# get the direction of the vectors between the vertex and it's connected vertices
- for c in con[v.index]:
- vec += Vector(me.verts[c].co - co).normalize()
+ for c in con[i]:
+ vec += (me.verts[c].co - co).normalize()
# normalize the vector by dividing by the number of connected verts
- vec /= len(con[v.index])
+ tot_con = len(con[i])
+
+ if tot_con == 0:
+ continue
+
+ vec /= tot_con
# angle is the acos of the dot product between vert and connected verts normals
ang = math.acos(no.dot(vec))
@@ -79,7 +84,7 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
if not dirt_only:
ang = min(clamp_clean, ang)
- vert_tone[v.index] = ang
+ vert_tone[i] = ang
# blur tones
for i in range(blur_iterations):
@@ -146,7 +151,7 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
class VertexPaintDirt(bpy.types.Operator):
- bl_idname = "mesh.vertex_paint_dirt"
+ bl_idname = "paint.vertex_color_dirt"
bl_label = "Dirty Vertex Colors"
bl_options = {'REGISTER', 'UNDO'}
@@ -171,7 +176,7 @@ class VertexPaintDirt(bpy.types.Operator):
print('Dirt calculated in %.6f' % (time.time() - t))
- return('FINISHED',)
+ return {'FINISHED'}
def register():
diff --git a/release/scripts/op/wm.py b/release/scripts/op/wm.py
index 216cb57537e..ed77f32ff6d 100644
--- a/release/scripts/op/wm.py
+++ b/release/scripts/op/wm.py
@@ -16,7 +16,7 @@
#
# ##### END GPL LICENSE BLOCK #####
-# <pep8-80 compliant>
+# <pep8 compliant>
import bpy
@@ -24,8 +24,7 @@ from bpy.props import *
class MESH_OT_delete_edgeloop(bpy.types.Operator):
- '''Export a single object as a stanford PLY with normals,
- colours and texture coordinates.'''
+ '''Delete an edge loop by merging the faces on each side to a single face loop'''
bl_idname = "mesh.delete_edgeloop"
bl_label = "Delete Edge Loop"
@@ -47,10 +46,10 @@ rna_relative_prop = BoolProperty(name="Relative",
default=False)
-def context_path_validate(context, path):
+def context_path_validate(context, data_path):
import sys
try:
- value = eval("context.%s" % path)
+ value = eval("context.%s" % data_path)
except AttributeError:
if "'NoneType'" in str(sys.exc_info()[1]):
# One of the items in the rna path is None, just ignore this
@@ -63,13 +62,13 @@ def context_path_validate(context, path):
def execute_context_assign(self, context):
- if context_path_validate(context, self.properties.path) is Ellipsis:
+ if context_path_validate(context, self.properties.data_path) is Ellipsis:
return {'PASS_THROUGH'}
if getattr(self.properties, "relative", False):
- exec("context.%s+=self.properties.value" % self.properties.path)
+ exec("context.%s+=self.properties.value" % self.properties.data_path)
else:
- exec("context.%s=self.properties.value" % self.properties.path)
+ exec("context.%s=self.properties.value" % self.properties.data_path)
return {'FINISHED'}
@@ -80,7 +79,7 @@ class WM_OT_context_set_boolean(bpy.types.Operator):
bl_label = "Context Set Boolean"
bl_options = {'UNDO'}
- path = rna_path_prop
+ data_path = rna_path_prop
value = BoolProperty(name="Value",
description="Assignment value", default=True)
@@ -93,20 +92,56 @@ class WM_OT_context_set_int(bpy.types.Operator): # same as enum
bl_label = "Context Set"
bl_options = {'UNDO'}
- path = rna_path_prop
+ data_path = rna_path_prop
value = IntProperty(name="Value", description="Assign value", default=0)
relative = rna_relative_prop
execute = execute_context_assign
+class WM_OT_context_scale_int(bpy.types.Operator): # same as enum
+ '''Scale an int context value.'''
+ bl_idname = "wm.context_scale_int"
+ bl_label = "Context Set"
+ bl_options = {'UNDO'}
+
+ data_path = rna_path_prop
+ value = FloatProperty(name="Value", description="Assign value", default=1.0)
+ always_step = BoolProperty(name="Always Step",
+ description="Always adjust the value by a minimum of 1 when 'value' is not 1.0.",
+ default=True)
+
+ def execute(self, context):
+ if context_path_validate(context, self.properties.data_path) is Ellipsis:
+ return {'PASS_THROUGH'}
+
+ value = self.properties.value
+ data_path = self.properties.data_path
+
+ if value == 1.0: # nothing to do
+ return {'CANCELLED'}
+
+ if getattr(self.properties, "always_step", False):
+ if value > 1.0:
+ add = "1"
+ func = "max"
+ else:
+ add = "-1"
+ func = "min"
+ exec("context.%s = %s(round(context.%s * value), context.%s + %s)" % (data_path, func, data_path, data_path, add))
+ else:
+ exec("context.%s *= value" % self.properties.data_path)
+
+ return {'FINISHED'}
+
+
class WM_OT_context_set_float(bpy.types.Operator): # same as enum
'''Set a context value.'''
bl_idname = "wm.context_set_float"
bl_label = "Context Set Float"
bl_options = {'UNDO'}
- path = rna_path_prop
+ data_path = rna_path_prop
value = FloatProperty(name="Value",
description="Assignment value", default=0.0)
relative = rna_relative_prop
@@ -120,7 +155,7 @@ class WM_OT_context_set_string(bpy.types.Operator): # same as enum
bl_label = "Context Set String"
bl_options = {'UNDO'}
- path = rna_path_prop
+ data_path = rna_path_prop
value = StringProperty(name="Value",
description="Assign value", maxlen=1024, default="")
@@ -133,7 +168,7 @@ class WM_OT_context_set_enum(bpy.types.Operator):
bl_label = "Context Set Enum"
bl_options = {'UNDO'}
- path = rna_path_prop
+ data_path = rna_path_prop
value = StringProperty(name="Value",
description="Assignment value (as a string)",
maxlen=1024, default="")
@@ -147,15 +182,15 @@ class WM_OT_context_set_value(bpy.types.Operator):
bl_label = "Context Set Value"
bl_options = {'UNDO'}
- path = rna_path_prop
+ data_path = rna_path_prop
value = StringProperty(name="Value",
description="Assignment value (as a string)",
maxlen=1024, default="")
def execute(self, context):
- if context_path_validate(context, self.properties.path) is Ellipsis:
+ if context_path_validate(context, self.properties.data_path) is Ellipsis:
return {'PASS_THROUGH'}
- exec("context.%s=%s" % (self.properties.path, self.properties.value))
+ exec("context.%s=%s" % (self.properties.data_path, self.properties.value))
return {'FINISHED'}
@@ -165,15 +200,15 @@ class WM_OT_context_toggle(bpy.types.Operator):
bl_label = "Context Toggle"
bl_options = {'UNDO'}
- path = rna_path_prop
+ data_path = rna_path_prop
def execute(self, context):
- if context_path_validate(context, self.properties.path) is Ellipsis:
+ if context_path_validate(context, self.properties.data_path) is Ellipsis:
return {'PASS_THROUGH'}
exec("context.%s=not (context.%s)" %
- (self.properties.path, self.properties.path))
+ (self.properties.data_path, self.properties.data_path))
return {'FINISHED'}
@@ -184,7 +219,7 @@ class WM_OT_context_toggle_enum(bpy.types.Operator):
bl_label = "Context Toggle Values"
bl_options = {'UNDO'}
- path = rna_path_prop
+ data_path = rna_path_prop
value_1 = StringProperty(name="Value", \
description="Toggle enum", maxlen=1024, default="")
@@ -193,12 +228,12 @@ class WM_OT_context_toggle_enum(bpy.types.Operator):
def execute(self, context):
- if context_path_validate(context, self.properties.path) is Ellipsis:
+ if context_path_validate(context, self.properties.data_path) is Ellipsis:
return {'PASS_THROUGH'}
exec("context.%s = ['%s', '%s'][context.%s!='%s']" % \
- (self.properties.path, self.properties.value_1,\
- self.properties.value_2, self.properties.path,
+ (self.properties.data_path, self.properties.value_1,\
+ self.properties.value_2, self.properties.data_path,
self.properties.value_2))
return {'FINISHED'}
@@ -211,12 +246,12 @@ class WM_OT_context_cycle_int(bpy.types.Operator):
bl_label = "Context Int Cycle"
bl_options = {'UNDO'}
- path = rna_path_prop
+ data_path = rna_path_prop
reverse = rna_reverse_prop
def execute(self, context):
- path = self.properties.path
- value = context_path_validate(context, path)
+ data_path = self.properties.data_path
+ value = context_path_validate(context, data_path)
if value is Ellipsis:
return {'PASS_THROUGH'}
@@ -225,16 +260,16 @@ class WM_OT_context_cycle_int(bpy.types.Operator):
else:
value += 1
- exec("context.%s=value" % path)
+ exec("context.%s=value" % data_path)
- if value != eval("context.%s" % path):
+ if value != eval("context.%s" % data_path):
# relies on rna clamping int's out of the range
if self.properties.reverse:
value = (1 << 32)
else:
value = - (1 << 32)
- exec("context.%s=value" % path)
+ exec("context.%s=value" % data_path)
return {'FINISHED'}
@@ -245,19 +280,19 @@ class WM_OT_context_cycle_enum(bpy.types.Operator):
bl_label = "Context Enum Cycle"
bl_options = {'UNDO'}
- path = rna_path_prop
+ data_path = rna_path_prop
reverse = rna_reverse_prop
def execute(self, context):
- value = context_path_validate(context, self.properties.path)
+ value = context_path_validate(context, self.properties.data_path)
if value is Ellipsis:
return {'PASS_THROUGH'}
orig_value = value
# Have to get rna enum values
- rna_struct_str, rna_prop_str = self.properties.path.rsplit('.', 1)
+ rna_struct_str, rna_prop_str = self.properties.data_path.rsplit('.', 1)
i = rna_prop_str.find('[')
# just incse we get "context.foo.bar[0]"
@@ -287,7 +322,7 @@ class WM_OT_context_cycle_enum(bpy.types.Operator):
advance_enum = enums[orig_index + 1]
# set the new value
- exec("context.%s=advance_enum" % self.properties.path)
+ exec("context.%s=advance_enum" % self.properties.data_path)
return {'FINISHED'}
doc_id = StringProperty(name="Doc ID",
@@ -302,27 +337,27 @@ class WM_OT_context_modal_mouse(bpy.types.Operator):
bl_idname = "wm.context_modal_mouse"
bl_label = "Context Modal Mouse"
- path_iter = StringProperty(description="The path relative to the context, must point to an iterable.")
- path_item = StringProperty(description="The path from each iterable to the value (int or float)")
+ data_path_iter = StringProperty(description="The data path relative to the context, must point to an iterable.")
+ data_path_item = StringProperty(description="The data path from each iterable to the value (int or float)")
input_scale = FloatProperty(default=0.01, description="Scale the mouse movement by this value before applying the delta")
invert = BoolProperty(default=False, description="Invert the mouse input")
initial_x = IntProperty(options={'HIDDEN'})
def _values_store(self, context):
- path_iter = self.properties.path_iter
- path_item = self.properties.path_item
+ data_path_iter = self.properties.data_path_iter
+ data_path_item = self.properties.data_path_item
self._values = values = {}
- for item in getattr(context, path_iter):
+ for item in getattr(context, data_path_iter):
try:
- value_orig = eval("item." + path_item)
+ value_orig = eval("item." + data_path_item)
except:
continue
# check this can be set, maybe this is library data.
try:
- exec("item.%s = %s" % (path_item, value_orig))
+ exec("item.%s = %s" % (data_path_item, value_orig))
except:
continue
@@ -333,17 +368,17 @@ class WM_OT_context_modal_mouse(bpy.types.Operator):
if self.properties.invert:
delta = - delta
- path_item = self.properties.path_item
+ data_path_item = self.properties.data_path_item
for item, value_orig in self._values.items():
if type(value_orig) == int:
- exec("item.%s = int(%d)" % (path_item, round(value_orig + delta)))
+ exec("item.%s = int(%d)" % (data_path_item, round(value_orig + delta)))
else:
- exec("item.%s = %f" % (path_item, value_orig + delta))
+ exec("item.%s = %f" % (data_path_item, value_orig + delta))
def _values_restore(self):
- path_item = self.properties.path_item
+ data_path_item = self.properties.data_path_item
for item, value_orig in self._values.items():
- exec("item.%s = %s" % (path_item, value_orig))
+ exec("item.%s = %s" % (data_path_item, value_orig))
self._values.clear()
@@ -371,7 +406,9 @@ class WM_OT_context_modal_mouse(bpy.types.Operator):
self._values_store(context)
if not self._values:
- self.report({'WARNING'}, "Nothing to operate on: %s[ ].%s" % (self.properties.path_iter, self.properties.path_item))
+ self.report({'WARNING'}, "Nothing to operate on: %s[ ].%s" %
+ (self.properties.data_path_iter, self.properties.data_path_item))
+
return {'CANCELLED'}
else:
self.properties.initial_x = event.mouse_x
@@ -380,6 +417,52 @@ class WM_OT_context_modal_mouse(bpy.types.Operator):
return {'RUNNING_MODAL'}
+class WM_OT_url_open(bpy.types.Operator):
+ "Open a website in the Webbrowser"
+ bl_idname = "wm.url_open"
+ bl_label = ""
+
+ url = StringProperty(name="URL", description="URL to open")
+
+ def execute(self, context):
+ import webbrowser
+ webbrowser.open(self.properties.url)
+ return {'FINISHED'}
+
+
+class WM_OT_path_open(bpy.types.Operator):
+ "Open a path in a file browser"
+ bl_idname = "wm.path_open"
+ bl_label = ""
+
+ filepath = StringProperty(name="File Path", maxlen=1024)
+
+ def execute(self, context):
+ import sys
+ import os
+ import subprocess
+
+ filepath = bpy.utils.expandpath(self.properties.filepath)
+ filepath = os.path.normpath(filepath)
+
+ if not os.path.exists(filepath):
+ self.report({'ERROR'}, "File '%s' not found" % filepath)
+ return {'CANCELLED'}
+
+ if sys.platform == 'win32':
+ subprocess.Popen(['start', filepath], shell=True)
+ elif sys.platform == 'darwin':
+ subprocess.Popen(['open', filepath])
+ else:
+ try:
+ subprocess.Popen(['xdg-open', filepath])
+ except OSError:
+ # xdg-open *should* be supported by recent Gnome, KDE, Xfce
+ pass
+
+ return {'FINISHED'}
+
+
class WM_OT_doc_view(bpy.types.Operator):
'''Load online reference docs'''
bl_idname = "wm.doc_view"
@@ -449,7 +532,8 @@ class WM_OT_doc_edit(bpy.types.Operator):
class_name, class_prop = doc_id.split('.')
if not doc_new:
- return {'RUNNING_MODAL'}
+ self.report({'ERROR'}, "No input given for '%s'" % doc_id)
+ return {'CANCELLED'}
# check if this is an operator
op_name = class_name.upper() + '_OT_' + class_prop
@@ -466,10 +550,6 @@ class WM_OT_doc_edit(bpy.types.Operator):
print("op - old:'%s' -> new:'%s'" % (doc_orig, doc_new))
upload["title"] = 'OPERATOR %s:%s' % (doc_id, doc_orig)
- upload["description"] = doc_new
-
- self._send_xmlrpc(upload)
-
else:
rna = getattr(bpy.types, class_name).bl_rna
doc_orig = rna.properties[class_prop].description
@@ -485,20 +565,15 @@ class WM_OT_doc_edit(bpy.types.Operator):
return {'FINISHED'}
+ def draw(self, context):
+ layout = self.layout
+ props = self.properties
+ layout.label(text="Descriptor ID: '%s'" % props.doc_id)
+ layout.prop(props, "doc_new", text="")
+
def invoke(self, context, event):
wm = context.manager
- return wm.invoke_props_popup(self, event)
-
-
-class WM_OT_reload_scripts(bpy.types.Operator):
- '''Load online reference docs'''
- bl_idname = "wm.reload_scripts"
- bl_label = "Reload Scripts"
-
- def execute(self, context):
- MOD = type(bpy)
- bpy.utils.load_scripts(True)
- return {'FINISHED'}
+ return wm.invoke_props_dialog(self, width=600)
import rna_prop_ui
@@ -508,6 +583,7 @@ classes = [
WM_OT_context_set_boolean,
WM_OT_context_set_int,
+ WM_OT_context_scale_int,
WM_OT_context_set_float,
WM_OT_context_set_string,
WM_OT_context_set_enum,
@@ -518,11 +594,12 @@ classes = [
WM_OT_context_cycle_int,
WM_OT_context_modal_mouse,
+ WM_OT_url_open,
+ WM_OT_path_open,
+
WM_OT_doc_view,
WM_OT_doc_edit,
- WM_OT_reload_scripts,
-
# experemental!
rna_prop_ui.WM_OT_properties_edit,
rna_prop_ui.WM_OT_properties_add,
diff --git a/release/scripts/presets/cloth/cotton.py b/release/scripts/presets/cloth/cotton.py
index 7fe8b890b38..695050cf195 100644
--- a/release/scripts/presets/cloth/cotton.py
+++ b/release/scripts/presets/cloth/cotton.py
@@ -1,3 +1,4 @@
+import bpy
bpy.context.cloth.settings.quality = 5
bpy.context.cloth.settings.mass = 0.300
bpy.context.cloth.settings.structural_stiffness = 15.000
diff --git a/release/scripts/presets/cloth/denim.py b/release/scripts/presets/cloth/denim.py
index 4cad384a014..bd72fa873da 100644
--- a/release/scripts/presets/cloth/denim.py
+++ b/release/scripts/presets/cloth/denim.py
@@ -1,3 +1,4 @@
+import bpy
bpy.context.cloth.settings.quality = 12
bpy.context.cloth.settings.mass = 1
bpy.context.cloth.settings.structural_stiffness = 40
diff --git a/release/scripts/presets/cloth/leather.py b/release/scripts/presets/cloth/leather.py
index 11176c7e814..b85f504b0bb 100644
--- a/release/scripts/presets/cloth/leather.py
+++ b/release/scripts/presets/cloth/leather.py
@@ -1,3 +1,4 @@
+import bpy
bpy.context.cloth.settings.quality = 15
bpy.context.cloth.settings.mass = 0.4
bpy.context.cloth.settings.structural_stiffness = 80
diff --git a/release/scripts/presets/cloth/rubber.py b/release/scripts/presets/cloth/rubber.py
index 101c11b141a..c2d7625d333 100644
--- a/release/scripts/presets/cloth/rubber.py
+++ b/release/scripts/presets/cloth/rubber.py
@@ -1,3 +1,4 @@
+import bpy
bpy.context.active_object.modifiers['Cloth'].settings.quality = 7
bpy.context.active_object.modifiers['Cloth'].settings.mass = 3
bpy.context.active_object.modifiers['Cloth'].settings.structural_stiffness = 15
diff --git a/release/scripts/presets/cloth/silk.py b/release/scripts/presets/cloth/silk.py
index a0dea5f1fd3..c2a98c270b8 100644
--- a/release/scripts/presets/cloth/silk.py
+++ b/release/scripts/presets/cloth/silk.py
@@ -1,3 +1,4 @@
+import bpy
bpy.context.cloth.settings.quality = 5
bpy.context.cloth.settings.mass = 0.150
bpy.context.cloth.settings.structural_stiffness = 5
diff --git a/release/scripts/presets/ffmpeg/DV.py b/release/scripts/presets/ffmpeg/DV.py
new file mode 100644
index 00000000000..4cdb2f271b9
--- /dev/null
+++ b/release/scripts/presets/ffmpeg/DV.py
@@ -0,0 +1,10 @@
+import bpy
+is_ntsc = (bpy.context.scene.render.fps != 25)
+
+bpy.context.scene.render.ffmpeg_format = "DV"
+bpy.context.scene.render.resolution_x = 720
+
+if is_ntsc:
+ bpy.context.scene.render.resolution_y = 480
+else:
+ bpy.context.scene.render.resolution_y = 576
diff --git a/release/scripts/presets/ffmpeg/DVD.py b/release/scripts/presets/ffmpeg/DVD.py
new file mode 100644
index 00000000000..233bdab4f20
--- /dev/null
+++ b/release/scripts/presets/ffmpeg/DVD.py
@@ -0,0 +1,19 @@
+import bpy
+is_ntsc = (bpy.context.scene.render.fps != 25)
+
+bpy.context.scene.render.ffmpeg_format = "MPEG2"
+bpy.context.scene.render.resolution_x = 720
+
+if is_ntsc:
+ bpy.context.scene.render.resolution_y = 480
+ bpy.context.scene.render.ffmpeg_gopsize = 18
+else:
+ bpy.context.scene.render.resolution_y = 576
+ bpy.context.scene.render.ffmpeg_gopsize = 15
+
+bpy.context.scene.render.ffmpeg_video_bitrate = 6000
+bpy.context.scene.render.ffmpeg_maxrate = 9000
+bpy.context.scene.render.ffmpeg_minrate = 0
+bpy.context.scene.render.ffmpeg_buffersize = 224*8
+bpy.context.scene.render.ffmpeg_packetsize = 2048
+bpy.context.scene.render.ffmpeg_muxrate = 10080000
diff --git a/release/scripts/presets/ffmpeg/SVCD.py b/release/scripts/presets/ffmpeg/SVCD.py
new file mode 100644
index 00000000000..52f938623b8
--- /dev/null
+++ b/release/scripts/presets/ffmpeg/SVCD.py
@@ -0,0 +1,19 @@
+import bpy
+is_ntsc = (bpy.context.scene.render.fps != 25)
+
+bpy.context.scene.render.ffmpeg_format = "MPEG2"
+bpy.context.scene.render.resolution_x = 480
+
+if is_ntsc:
+ bpy.context.scene.render.resolution_y = 480
+ bpy.context.scene.render.ffmpeg_gopsize = 18
+else:
+ bpy.context.scene.render.resolution_y = 576
+ bpy.context.scene.render.ffmpeg_gopsize = 15
+
+bpy.context.scene.render.ffmpeg_video_bitrate = 2040
+bpy.context.scene.render.ffmpeg_maxrate = 2516
+bpy.context.scene.render.ffmpeg_minrate = 0
+bpy.context.scene.render.ffmpeg_buffersize = 224*8
+bpy.context.scene.render.ffmpeg_packetsize = 2324
+bpy.context.scene.render.ffmpeg_muxrate = 0
diff --git a/release/scripts/presets/ffmpeg/VCD.py b/release/scripts/presets/ffmpeg/VCD.py
new file mode 100644
index 00000000000..876fa2d8ba6
--- /dev/null
+++ b/release/scripts/presets/ffmpeg/VCD.py
@@ -0,0 +1,19 @@
+import bpy
+is_ntsc = (bpy.context.scene.render.fps != 25)
+
+bpy.context.scene.render.ffmpeg_format = "MPEG1"
+bpy.context.scene.render.resolution_x = 352
+
+if is_ntsc:
+ bpy.context.scene.render.resolution_y = 240
+ bpy.context.scene.render.ffmpeg_gopsize = 18
+else:
+ bpy.context.scene.render.resolution_y = 288
+ bpy.context.scene.render.ffmpeg_gopsize = 15
+
+bpy.context.scene.render.ffmpeg_video_bitrate = 1150
+bpy.context.scene.render.ffmpeg_maxrate = 1150
+bpy.context.scene.render.ffmpeg_minrate = 1150
+bpy.context.scene.render.ffmpeg_buffersize = 40*8
+bpy.context.scene.render.ffmpeg_packetsize = 2324
+bpy.context.scene.render.ffmpeg_muxrate = 2352 * 75 * 8
diff --git a/release/scripts/presets/ffmpeg/h264.py b/release/scripts/presets/ffmpeg/h264.py
new file mode 100644
index 00000000000..74e6890a5d4
--- /dev/null
+++ b/release/scripts/presets/ffmpeg/h264.py
@@ -0,0 +1,17 @@
+import bpy
+is_ntsc = (bpy.context.scene.render.fps != 25)
+
+bpy.context.scene.render.ffmpeg_format = "H264"
+bpy.context.scene.render.ffmpeg_codec = "H264"
+
+if is_ntsc:
+ bpy.context.scene.render.ffmpeg_gopsize = 18
+else:
+ bpy.context.scene.render.ffmpeg_gopsize = 15
+
+bpy.context.scene.render.ffmpeg_video_bitrate = 6000
+bpy.context.scene.render.ffmpeg_maxrate = 9000
+bpy.context.scene.render.ffmpeg_minrate = 0
+bpy.context.scene.render.ffmpeg_buffersize = 224*8
+bpy.context.scene.render.ffmpeg_packetsize = 2048
+bpy.context.scene.render.ffmpeg_muxrate = 10080000
diff --git a/release/scripts/presets/ffmpeg/theora.py b/release/scripts/presets/ffmpeg/theora.py
new file mode 100644
index 00000000000..6ce9d4ea7ed
--- /dev/null
+++ b/release/scripts/presets/ffmpeg/theora.py
@@ -0,0 +1,17 @@
+import bpy
+is_ntsc = (bpy.context.scene.render.fps != 25)
+
+bpy.context.scene.render.ffmpeg_format = "OGG"
+bpy.context.scene.render.ffmpeg_codec = "THEORA"
+
+if is_ntsc:
+ bpy.context.scene.render.ffmpeg_gopsize = 18
+else:
+ bpy.context.scene.render.ffmpeg_gopsize = 15
+
+bpy.context.scene.render.ffmpeg_video_bitrate = 6000
+bpy.context.scene.render.ffmpeg_maxrate = 9000
+bpy.context.scene.render.ffmpeg_minrate = 0
+bpy.context.scene.render.ffmpeg_buffersize = 224*8
+bpy.context.scene.render.ffmpeg_packetsize = 2048
+bpy.context.scene.render.ffmpeg_muxrate = 10080000
diff --git a/release/scripts/presets/ffmpeg/xvid.py b/release/scripts/presets/ffmpeg/xvid.py
new file mode 100644
index 00000000000..0c8e3989451
--- /dev/null
+++ b/release/scripts/presets/ffmpeg/xvid.py
@@ -0,0 +1,17 @@
+import bpy
+is_ntsc = (bpy.context.scene.render.fps != 25)
+
+bpy.context.scene.render.ffmpeg_format = "AVI"
+bpy.context.scene.render.ffmpeg_codec = "XVID"
+
+if is_ntsc:
+ bpy.context.scene.render.ffmpeg_gopsize = 18
+else:
+ bpy.context.scene.render.ffmpeg_gopsize = 15
+
+bpy.context.scene.render.ffmpeg_video_bitrate = 6000
+bpy.context.scene.render.ffmpeg_maxrate = 9000
+bpy.context.scene.render.ffmpeg_minrate = 0
+bpy.context.scene.render.ffmpeg_buffersize = 224*8
+bpy.context.scene.render.ffmpeg_packetsize = 2048
+bpy.context.scene.render.ffmpeg_muxrate = 10080000
diff --git a/release/scripts/presets/interaction/blender.py b/release/scripts/presets/interaction/blender.py
new file mode 100644
index 00000000000..63006b2008d
--- /dev/null
+++ b/release/scripts/presets/interaction/blender.py
@@ -0,0 +1,16 @@
+# Configuration Blender
+import bpy
+
+wm = bpy.context.manager
+wm.active_keyconfig = wm.keyconfigs['Blender']
+
+bpy.context.user_preferences.view.auto_depth = False
+bpy.context.user_preferences.view.zoom_to_mouse = False
+bpy.context.user_preferences.view.rotate_around_selection = False
+bpy.context.user_preferences.edit.drag_immediately = False
+bpy.context.user_preferences.edit.insertkey_xyz_to_rgb = False
+bpy.context.user_preferences.inputs.select_mouse = 'RIGHT'
+bpy.context.user_preferences.inputs.zoom_style = 'DOLLY'
+bpy.context.user_preferences.inputs.zoom_axis = 'VERTICAL'
+bpy.context.user_preferences.inputs.view_rotation = 'TRACKBALL'
+bpy.context.user_preferences.inputs.invert_zoom_direction = False
diff --git a/release/scripts/presets/interaction/maya.py b/release/scripts/presets/interaction/maya.py
new file mode 100644
index 00000000000..31652035dff
--- /dev/null
+++ b/release/scripts/presets/interaction/maya.py
@@ -0,0 +1,386 @@
+# Configuration Maya
+import bpy
+
+wm = bpy.context.manager
+kc = wm.add_keyconfig('Maya')
+
+# Map 3D View
+km = kc.add_keymap('3D View', space_type='VIEW_3D', region_type='WINDOW', modal=False)
+
+kmi = km.items.add('view3d.manipulator', 'LEFTMOUSE', 'PRESS', any=True)
+kmi.properties.release_confirm = True
+kmi = km.items.add('view3d.cursor3d', 'ACTIONMOUSE', 'PRESS')
+kmi = km.items.add('view3d.rotate', 'LEFTMOUSE', 'PRESS', alt=True)
+kmi = km.items.add('view3d.move', 'MIDDLEMOUSE', 'PRESS', alt=True)
+kmi = km.items.add('view3d.zoom', 'RIGHTMOUSE', 'PRESS', alt=True)
+kmi = km.items.add('view3d.view_selected', 'NUMPAD_PERIOD', 'PRESS')
+kmi = km.items.add('view3d.view_center_cursor', 'NUMPAD_PERIOD', 'PRESS', ctrl=True)
+kmi = km.items.add('view3d.fly', 'F', 'PRESS', shift=True)
+kmi = km.items.add('view3d.smoothview', 'TIMER1', 'ANY', any=True)
+kmi = km.items.add('view3d.rotate', 'TRACKPADPAN', 'ANY', alt=True)
+kmi = km.items.add('view3d.rotate', 'MOUSEROTATE', 'ANY')
+kmi = km.items.add('view3d.move', 'TRACKPADPAN', 'ANY')
+kmi = km.items.add('view3d.zoom', 'TRACKPADZOOM', 'ANY')
+kmi = km.items.add('view3d.zoom', 'NUMPAD_PLUS', 'PRESS')
+kmi.properties.delta = 1
+kmi = km.items.add('view3d.zoom', 'NUMPAD_MINUS', 'PRESS')
+kmi.properties.delta = -1
+kmi = km.items.add('view3d.zoom', 'EQUAL', 'PRESS', ctrl=True)
+kmi.properties.delta = 1
+kmi = km.items.add('view3d.zoom', 'MINUS', 'PRESS', ctrl=True)
+kmi.properties.delta = -1
+kmi = km.items.add('view3d.zoom', 'WHEELINMOUSE', 'PRESS')
+kmi.properties.delta = 1
+kmi = km.items.add('view3d.zoom', 'WHEELOUTMOUSE', 'PRESS')
+kmi.properties.delta = -1
+kmi = km.items.add('view3d.view_all', 'HOME', 'PRESS')
+kmi.properties.center = False
+kmi = km.items.add('view3d.view_all', 'C', 'PRESS', shift=True)
+kmi.properties.center = True
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_0', 'PRESS')
+kmi.properties.type = 'CAMERA'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_1', 'PRESS')
+kmi.properties.type = 'FRONT'
+kmi = km.items.add('view3d.view_orbit', 'NUMPAD_2', 'PRESS')
+kmi.properties.type = 'ORBITDOWN'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_3', 'PRESS')
+kmi.properties.type = 'RIGHT'
+kmi = km.items.add('view3d.view_orbit', 'NUMPAD_4', 'PRESS')
+kmi.properties.type = 'ORBITLEFT'
+kmi = km.items.add('view3d.view_persportho', 'NUMPAD_5', 'PRESS')
+kmi = km.items.add('view3d.view_orbit', 'NUMPAD_6', 'PRESS')
+kmi.properties.type = 'ORBITRIGHT'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_7', 'PRESS')
+kmi.properties.type = 'TOP'
+kmi = km.items.add('view3d.view_orbit', 'NUMPAD_8', 'PRESS')
+kmi.properties.type = 'ORBITUP'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_1', 'PRESS', ctrl=True)
+kmi.properties.type = 'BACK'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_3', 'PRESS', ctrl=True)
+kmi.properties.type = 'LEFT'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_7', 'PRESS', ctrl=True)
+kmi.properties.type = 'BOTTOM'
+kmi = km.items.add('view3d.view_pan', 'NUMPAD_2', 'PRESS', ctrl=True)
+kmi.properties.type = 'PANDOWN'
+kmi = km.items.add('view3d.view_pan', 'NUMPAD_4', 'PRESS', ctrl=True)
+kmi.properties.type = 'PANLEFT'
+kmi = km.items.add('view3d.view_pan', 'NUMPAD_6', 'PRESS', ctrl=True)
+kmi.properties.type = 'PANRIGHT'
+kmi = km.items.add('view3d.view_pan', 'NUMPAD_8', 'PRESS', ctrl=True)
+kmi.properties.type = 'PANUP'
+kmi = km.items.add('view3d.view_pan', 'WHEELUPMOUSE', 'PRESS', ctrl=True)
+kmi.properties.type = 'PANRIGHT'
+kmi = km.items.add('view3d.view_pan', 'WHEELDOWNMOUSE', 'PRESS', ctrl=True)
+kmi.properties.type = 'PANLEFT'
+kmi = km.items.add('view3d.view_pan', 'WHEELUPMOUSE', 'PRESS', shift=True)
+kmi.properties.type = 'PANUP'
+kmi = km.items.add('view3d.view_pan', 'WHEELDOWNMOUSE', 'PRESS', shift=True)
+kmi.properties.type = 'PANDOWN'
+kmi = km.items.add('view3d.view_orbit', 'WHEELUPMOUSE', 'PRESS', ctrl=True, alt=True)
+kmi.properties.type = 'ORBITLEFT'
+kmi = km.items.add('view3d.view_orbit', 'WHEELDOWNMOUSE', 'PRESS', ctrl=True, alt=True)
+kmi.properties.type = 'ORBITRIGHT'
+kmi = km.items.add('view3d.view_orbit', 'WHEELUPMOUSE', 'PRESS', shift=True, alt=True)
+kmi.properties.type = 'ORBITUP'
+kmi = km.items.add('view3d.view_orbit', 'WHEELDOWNMOUSE', 'PRESS', shift=True, alt=True)
+kmi.properties.type = 'ORBITDOWN'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_1', 'PRESS', shift=True)
+kmi.properties.align_active = True
+kmi.properties.type = 'FRONT'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_3', 'PRESS', shift=True)
+kmi.properties.align_active = True
+kmi.properties.type = 'RIGHT'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_7', 'PRESS', shift=True)
+kmi.properties.align_active = True
+kmi.properties.type = 'TOP'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_1', 'PRESS', shift=True, ctrl=True)
+kmi.properties.align_active = True
+kmi.properties.type = 'BACK'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_3', 'PRESS', shift=True, ctrl=True)
+kmi.properties.align_active = True
+kmi.properties.type = 'LEFT'
+kmi = km.items.add('view3d.viewnumpad', 'NUMPAD_7', 'PRESS', shift=True, ctrl=True)
+kmi.properties.align_active = True
+kmi.properties.type = 'BOTTOM'
+kmi = km.items.add('view3d.localview', 'NUMPAD_SLASH', 'PRESS')
+kmi = km.items.add('view3d.layers', 'ACCENT_GRAVE', 'PRESS')
+kmi.properties.nr = 0
+kmi = km.items.add('view3d.layers', 'ONE', 'PRESS', any=True)
+kmi.properties.nr = 1
+kmi = km.items.add('view3d.layers', 'TWO', 'PRESS', any=True)
+kmi.properties.nr = 2
+kmi = km.items.add('view3d.layers', 'THREE', 'PRESS', any=True)
+kmi.properties.nr = 3
+kmi = km.items.add('view3d.layers', 'FOUR', 'PRESS', any=True)
+kmi.properties.nr = 4
+kmi = km.items.add('view3d.layers', 'FIVE', 'PRESS', any=True)
+kmi.properties.nr = 5
+kmi = km.items.add('view3d.layers', 'SIX', 'PRESS', any=True)
+kmi.properties.nr = 6
+kmi = km.items.add('view3d.layers', 'SEVEN', 'PRESS', any=True)
+kmi.properties.nr = 7
+kmi = km.items.add('view3d.layers', 'EIGHT', 'PRESS', any=True)
+kmi.properties.nr = 8
+kmi = km.items.add('view3d.layers', 'NINE', 'PRESS', any=True)
+kmi.properties.nr = 9
+kmi = km.items.add('view3d.layers', 'ZERO', 'PRESS', any=True)
+kmi.properties.nr = 10
+kmi = km.items.add('wm.context_toggle_enum', 'Z', 'PRESS')
+kmi.properties.data_path = 'space_data.viewport_shading'
+kmi.properties.value_1 = 'SOLID'
+kmi.properties.value_2 = 'WIREFRAME'
+kmi = km.items.add('wm.context_toggle_enum', 'Z', 'PRESS', alt=True)
+kmi.properties.data_path = 'space_data.viewport_shading'
+kmi.properties.value_1 = 'TEXTURED'
+kmi.properties.value_2 = 'SOLID'
+kmi = km.items.add('view3d.select', 'SELECTMOUSE', 'PRESS')
+kmi = km.items.add('view3d.select', 'SELECTMOUSE', 'PRESS', shift=True)
+kmi.properties.extend = True
+kmi = km.items.add('view3d.select', 'SELECTMOUSE', 'PRESS', ctrl=True)
+kmi.properties.center = True
+kmi = km.items.add('view3d.select', 'SELECTMOUSE', 'PRESS', alt=True)
+kmi.properties.enumerate = True
+kmi = km.items.add('view3d.select', 'SELECTMOUSE', 'PRESS', shift=True, ctrl=True)
+kmi.properties.center = True
+kmi.properties.extend = True
+kmi = km.items.add('view3d.select', 'SELECTMOUSE', 'PRESS', ctrl=True, alt=True)
+kmi.properties.center = True
+kmi.properties.enumerate = True
+kmi = km.items.add('view3d.select', 'SELECTMOUSE', 'PRESS', shift=True, alt=True)
+kmi.properties.enumerate = True
+kmi.properties.extend = True
+kmi = km.items.add('view3d.select', 'SELECTMOUSE', 'PRESS', shift=True, ctrl=True, alt=True)
+kmi.properties.center = True
+kmi.properties.enumerate = True
+kmi.properties.extend = True
+kmi = km.items.add('view3d.select_border', 'EVT_TWEAK_S', 'ANY')
+kmi.properties.extend = False
+kmi = km.items.add('view3d.select_lasso', 'EVT_TWEAK_A', 'ANY', ctrl=True)
+kmi = km.items.add('view3d.select_lasso', 'EVT_TWEAK_A', 'ANY', shift=True, ctrl=True)
+kmi.properties.deselect = True
+kmi = km.items.add('view3d.select_circle', 'C', 'PRESS')
+kmi = km.items.add('view3d.clip_border', 'B', 'PRESS', alt=True)
+kmi = km.items.add('view3d.zoom_border', 'B', 'PRESS', shift=True)
+kmi = km.items.add('view3d.render_border', 'B', 'PRESS', shift=True)
+kmi = km.items.add('view3d.camera_to_view', 'NUMPAD_0', 'PRESS', ctrl=True, alt=True)
+kmi = km.items.add('view3d.object_as_camera', 'NUMPAD_0', 'PRESS', ctrl=True)
+kmi = km.items.add('wm.call_menu', 'S', 'PRESS', shift=True)
+kmi.properties.name = 'VIEW3D_MT_snap'
+kmi = km.items.add('wm.context_set_enum', 'COMMA', 'PRESS')
+kmi.properties.data_path = 'space_data.pivot_point'
+kmi.properties.value = 'BOUNDING_BOX_CENTER'
+kmi = km.items.add('wm.context_set_enum', 'COMMA', 'PRESS', ctrl=True)
+kmi.properties.data_path = 'space_data.pivot_point'
+kmi.properties.value = 'MEDIAN_POINT'
+kmi = km.items.add('wm.context_toggle', 'COMMA', 'PRESS', alt=True)
+kmi.properties.data_path = 'space_data.pivot_point_align'
+kmi = km.items.add('wm.context_toggle', 'Q', 'PRESS')
+kmi.properties.data_path = 'space_data.manipulator'
+kmi = km.items.add('wm.context_set_enum', 'PERIOD', 'PRESS')
+kmi.properties.data_path = 'space_data.pivot_point'
+kmi.properties.value = 'CURSOR'
+kmi = km.items.add('wm.context_set_enum', 'PERIOD', 'PRESS', ctrl=True)
+kmi.properties.data_path = 'space_data.pivot_point'
+kmi.properties.value = 'INDIVIDUAL_ORIGINS'
+kmi = km.items.add('wm.context_set_enum', 'PERIOD', 'PRESS', alt=True)
+kmi.properties.data_path = 'space_data.pivot_point'
+kmi.properties.value = 'ACTIVE_ELEMENT'
+kmi = km.items.add('transform.translate', 'G', 'PRESS', shift=True)
+kmi = km.items.add('transform.translate', 'EVT_TWEAK_S', 'ANY')
+kmi = km.items.add('transform.rotate', 'R', 'PRESS', shift=True)
+kmi = km.items.add('transform.resize', 'S', 'PRESS', shift=True)
+kmi = km.items.add('transform.warp', 'W', 'PRESS', shift=True)
+kmi = km.items.add('transform.tosphere', 'S', 'PRESS', shift=True, alt=True)
+kmi = km.items.add('transform.shear', 'S', 'PRESS', shift=True, ctrl=True, alt=True)
+kmi = km.items.add('transform.select_orientation', 'SPACE', 'PRESS', alt=True)
+kmi = km.items.add('transform.create_orientation', 'SPACE', 'PRESS', ctrl=True, alt=True)
+kmi.properties.use = True
+kmi = km.items.add('transform.mirror', 'M', 'PRESS', ctrl=True)
+kmi = km.items.add('wm.context_toggle', 'TAB', 'PRESS', shift=True)
+kmi.properties.data_path = 'tool_settings.snap'
+kmi = km.items.add('transform.snap_type', 'TAB', 'PRESS', shift=True, ctrl=True)
+kmi = km.items.add('view3d.enable_manipulator', 'W', 'PRESS')
+kmi.properties.translate = True
+kmi = km.items.add('view3d.enable_manipulator', 'E', 'PRESS')
+kmi.properties.rotate = True
+kmi = km.items.add('view3d.enable_manipulator', 'R', 'PRESS')
+kmi.properties.scale = True
+kmi = km.items.add('view3d.select_border', 'EVT_TWEAK_S', 'ANY', shift=True)
+kmi.properties.extend = True
+
+# Map Object Mode
+km = kc.add_keymap('Object Mode', space_type='EMPTY', region_type='WINDOW', modal=False)
+
+kmi = km.items.add('wm.context_cycle_enum', 'O', 'PRESS', shift=True)
+kmi.properties.data_path = 'tool_settings.proportional_editing_falloff'
+kmi = km.items.add('wm.context_toggle_enum', 'O', 'PRESS')
+kmi.properties.data_path = 'tool_settings.proportional_editing'
+kmi.properties.value_1 = 'DISABLED'
+kmi.properties.value_2 = 'ENABLED'
+kmi = km.items.add('view3d.game_start', 'P', 'PRESS')
+kmi = km.items.add('object.select_all', 'A', 'PRESS')
+kmi = km.items.add('object.select_inverse', 'I', 'PRESS', ctrl=True)
+kmi = km.items.add('object.select_linked', 'L', 'PRESS', shift=True)
+kmi = km.items.add('object.select_grouped', 'G', 'PRESS', shift=True)
+kmi = km.items.add('object.select_mirror', 'M', 'PRESS', shift=True, ctrl=True)
+kmi = km.items.add('object.select_hierarchy', 'LEFT_BRACKET', 'PRESS')
+kmi.properties.direction = 'PARENT'
+kmi = km.items.add('object.select_hierarchy', 'LEFT_BRACKET', 'PRESS', shift=True)
+kmi.properties.direction = 'PARENT'
+kmi.properties.extend = True
+kmi = km.items.add('object.select_hierarchy', 'RIGHT_BRACKET', 'PRESS')
+kmi.properties.direction = 'CHILD'
+kmi = km.items.add('object.select_hierarchy', 'RIGHT_BRACKET', 'PRESS', shift=True)
+kmi.properties.direction = 'CHILD'
+kmi.properties.extend = True
+kmi = km.items.add('object.parent_set', 'P', 'PRESS', ctrl=True)
+kmi = km.items.add('object.parent_no_inverse_set', 'P', 'PRESS', shift=True, ctrl=True)
+kmi = km.items.add('object.parent_clear', 'P', 'PRESS', alt=True)
+kmi = km.items.add('object.track_set', 'T', 'PRESS', ctrl=True)
+kmi = km.items.add('object.track_clear', 'T', 'PRESS', alt=True)
+kmi = km.items.add('object.constraint_add_with_targets', 'C', 'PRESS', shift=True, ctrl=True)
+kmi = km.items.add('object.constraints_clear', 'C', 'PRESS', ctrl=True, alt=True)
+kmi = km.items.add('object.location_clear', 'G', 'PRESS', alt=True)
+kmi = km.items.add('object.rotation_clear', 'R', 'PRESS', alt=True)
+kmi = km.items.add('object.scale_clear', 'S', 'PRESS', alt=True)
+kmi = km.items.add('object.origin_clear', 'O', 'PRESS', alt=True)
+kmi = km.items.add('object.restrictview_clear', 'H', 'PRESS', alt=True)
+kmi = km.items.add('object.restrictview_set', 'H', 'PRESS')
+kmi = km.items.add('object.restrictview_set', 'H', 'PRESS', shift=True)
+kmi.properties.unselected = True
+kmi = km.items.add('object.move_to_layer', 'M', 'PRESS')
+kmi = km.items.add('object.delete', 'X', 'PRESS')
+kmi = km.items.add('object.delete', 'DEL', 'PRESS')
+kmi = km.items.add('wm.call_menu', 'A', 'PRESS', shift=True)
+kmi.properties.name = 'INFO_MT_add'
+kmi = km.items.add('object.duplicates_make_real', 'A', 'PRESS', shift=True, ctrl=True)
+kmi = km.items.add('wm.call_menu', 'A', 'PRESS', ctrl=True)
+kmi.properties.name = 'VIEW3D_MT_object_apply'
+kmi = km.items.add('wm.call_menu', 'U', 'PRESS')
+kmi.properties.name = 'VIEW3D_MT_make_single_user'
+kmi = km.items.add('wm.call_menu', 'L', 'PRESS', ctrl=True)
+kmi.properties.name = 'VIEW3D_MT_make_links'
+kmi = km.items.add('object.duplicate_move', 'D', 'PRESS', shift=True)
+kmi = km.items.add('object.duplicate_move_linked', 'D', 'PRESS', alt=True)
+kmi = km.items.add('object.join', 'J', 'PRESS', ctrl=True)
+kmi = km.items.add('object.convert', 'C', 'PRESS', alt=True)
+kmi = km.items.add('object.proxy_make', 'P', 'PRESS', ctrl=True, alt=True)
+kmi = km.items.add('object.make_local', 'L', 'PRESS')
+kmi = km.items.add('anim.keyframe_insert_menu', 'I', 'PRESS')
+kmi = km.items.add('anim.keyframe_delete_v3d', 'I', 'PRESS', alt=True)
+kmi = km.items.add('anim.keying_set_active_set', 'I', 'PRESS', shift=True, ctrl=True, alt=True)
+kmi = km.items.add('group.create', 'G', 'PRESS', ctrl=True)
+kmi = km.items.add('group.objects_remove', 'G', 'PRESS', ctrl=True, alt=True)
+kmi = km.items.add('group.objects_add_active', 'G', 'PRESS', shift=True, ctrl=True)
+kmi = km.items.add('group.objects_remove_active', 'G', 'PRESS', shift=True, alt=True)
+kmi = km.items.add('wm.call_menu', 'W', 'PRESS', ctrl=True)
+kmi.properties.name = 'VIEW3D_MT_object_specials'
+kmi = km.items.add('object.subdivision_set', 'ZERO', 'PRESS', ctrl=True)
+kmi.properties.level = 0
+kmi = km.items.add('object.subdivision_set', 'ONE', 'PRESS', ctrl=True)
+kmi.properties.level = 1
+kmi = km.items.add('object.subdivision_set', 'TWO', 'PRESS', ctrl=True)
+kmi.properties.level = 2
+kmi = km.items.add('object.subdivision_set', 'THREE', 'PRESS', ctrl=True)
+kmi.properties.level = 3
+kmi = km.items.add('object.subdivision_set', 'FOUR', 'PRESS', ctrl=True)
+kmi.properties.level = 4
+kmi = km.items.add('object.subdivision_set', 'FIVE', 'PRESS', ctrl=True)
+kmi.properties.level = 5
+kmi = km.items.add('object.select_all', 'SELECTMOUSE', 'CLICK')
+kmi.properties.action = 'DESELECT'
+
+# Map Mesh
+km = kc.add_keymap('Mesh', space_type='EMPTY', region_type='WINDOW', modal=False)
+
+kmi = km.items.add('mesh.loopcut_slide', 'R', 'PRESS', ctrl=True)
+kmi = km.items.add('mesh.loop_select', 'SELECTMOUSE', 'PRESS', ctrl=True, alt=True)
+kmi = km.items.add('mesh.loop_select', 'SELECTMOUSE', 'PRESS', shift=True, alt=True)
+kmi.properties.extend = True
+kmi = km.items.add('mesh.edgering_select', 'SELECTMOUSE', 'PRESS', ctrl=True, alt=True)
+kmi = km.items.add('mesh.edgering_select', 'SELECTMOUSE', 'PRESS', shift=True, ctrl=True, alt=True)
+kmi.properties.extend = True
+kmi = km.items.add('mesh.select_shortest_path', 'SELECTMOUSE', 'PRESS', ctrl=True)
+kmi = km.items.add('mesh.select_all', 'A', 'PRESS')
+kmi = km.items.add('mesh.select_more', 'NUMPAD_PLUS', 'PRESS', ctrl=True)
+kmi = km.items.add('mesh.select_less', 'NUMPAD_MINUS', 'PRESS', ctrl=True)
+kmi = km.items.add('mesh.select_inverse', 'I', 'PRESS', ctrl=True)
+kmi = km.items.add('mesh.select_non_manifold', 'M', 'PRESS', shift=True, ctrl=True, alt=True)
+kmi = km.items.add('mesh.select_linked', 'L', 'PRESS', ctrl=True)
+kmi = km.items.add('mesh.select_linked_pick', 'L', 'PRESS')
+kmi = km.items.add('mesh.select_linked_pick', 'L', 'PRESS', shift=True)
+kmi.properties.deselect = True
+kmi = km.items.add('mesh.faces_select_linked_flat', 'F', 'PRESS', shift=True, ctrl=True, alt=True)
+kmi.properties.sharpness = 135.0
+kmi = km.items.add('mesh.select_similar', 'G', 'PRESS', shift=True)
+kmi = km.items.add('wm.call_menu', 'TAB', 'PRESS', ctrl=True)
+kmi.properties.name = 'VIEW3D_MT_edit_mesh_selection_mode'
+kmi = km.items.add('mesh.hide', 'H', 'PRESS')
+kmi = km.items.add('mesh.hide', 'H', 'PRESS', shift=True)
+kmi.properties.unselected = True
+kmi = km.items.add('mesh.reveal', 'H', 'PRESS', alt=True)
+kmi = km.items.add('mesh.normals_make_consistent', 'N', 'PRESS', ctrl=True)
+kmi = km.items.add('mesh.normals_make_consistent', 'N', 'PRESS', shift=True, ctrl=True)
+kmi.properties.inside = True
+kmi = km.items.add('view3d.edit_mesh_extrude_move_normal', 'E', 'PRESS', ctrl=True)
+kmi = km.items.add('view3d.edit_mesh_extrude_individual_move', 'E', 'PRESS', shift=True)
+kmi = km.items.add('wm.call_menu', 'E', 'PRESS', alt=True)
+kmi.properties.name = 'VIEW3D_MT_edit_mesh_extrude'
+kmi = km.items.add('mesh.spin', 'R', 'PRESS', alt=True)
+kmi = km.items.add('mesh.fill', 'F', 'PRESS', alt=True)
+kmi = km.items.add('mesh.beautify_fill', 'F', 'PRESS', shift=True, alt=True)
+kmi = km.items.add('mesh.quads_convert_to_tris', 'T', 'PRESS', ctrl=True)
+kmi = km.items.add('mesh.tris_convert_to_quads', 'J', 'PRESS', alt=True)
+kmi = km.items.add('mesh.edge_flip', 'F', 'PRESS', shift=True, ctrl=True)
+kmi = km.items.add('mesh.rip_move', 'V', 'PRESS')
+kmi = km.items.add('mesh.merge', 'M', 'PRESS', alt=True)
+kmi = km.items.add('transform.shrink_fatten', 'S', 'PRESS', ctrl=True, alt=True)
+kmi = km.items.add('mesh.edge_face_add', 'F', 'PRESS')
+kmi = km.items.add('mesh.duplicate_move', 'D', 'PRESS', shift=True)
+kmi = km.items.add('wm.call_menu', 'A', 'PRESS', shift=True)
+kmi.properties.name = 'INFO_MT_mesh_add'
+kmi = km.items.add('mesh.separate', 'P', 'PRESS')
+kmi = km.items.add('mesh.split', 'Y', 'PRESS')
+kmi = km.items.add('mesh.dupli_extrude_cursor', 'ACTIONMOUSE', 'CLICK', ctrl=True)
+kmi = km.items.add('mesh.delete', 'X', 'PRESS')
+kmi = km.items.add('mesh.delete', 'DEL', 'PRESS')
+kmi = km.items.add('mesh.knife_cut', 'LEFTMOUSE', 'PRESS', key_modifier='K')
+kmi = km.items.add('mesh.knife_cut', 'LEFTMOUSE', 'PRESS', shift=True, key_modifier='K')
+kmi.properties.type = 'MIDPOINTS'
+kmi = km.items.add('object.vertex_parent_set', 'P', 'PRESS', ctrl=True)
+kmi = km.items.add('wm.call_menu', 'W', 'PRESS', ctrl=True)
+kmi.properties.name = 'VIEW3D_MT_edit_mesh_specials'
+kmi = km.items.add('wm.call_menu', 'F', 'PRESS', ctrl=True)
+kmi.properties.name = 'VIEW3D_MT_edit_mesh_faces'
+kmi = km.items.add('wm.call_menu', 'E', 'PRESS', ctrl=True)
+kmi.properties.name = 'VIEW3D_MT_edit_mesh_edges'
+kmi = km.items.add('wm.call_menu', 'V', 'PRESS', ctrl=True)
+kmi.properties.name = 'VIEW3D_MT_edit_mesh_vertices'
+kmi = km.items.add('wm.call_menu', 'H', 'PRESS', ctrl=True)
+kmi.properties.name = 'VIEW3D_MT_hook'
+kmi = km.items.add('wm.call_menu', 'U', 'PRESS')
+kmi.properties.name = 'VIEW3D_MT_uv_map'
+kmi = km.items.add('wm.call_menu', 'G', 'PRESS', ctrl=True)
+kmi.properties.name = 'VIEW3D_MT_vertex_group'
+kmi = km.items.add('wm.context_cycle_enum', 'O', 'PRESS', shift=True)
+kmi.properties.data_path = 'tool_settings.proportional_editing_falloff'
+kmi = km.items.add('wm.context_toggle_enum', 'O', 'PRESS')
+kmi.properties.data_path = 'tool_settings.proportional_editing'
+kmi.properties.value_1 = 'DISABLED'
+kmi.properties.value_2 = 'ENABLED'
+kmi = km.items.add('wm.context_toggle_enum', 'O', 'PRESS', alt=True)
+kmi.properties.data_path = 'tool_settings.proportional_editing'
+kmi.properties.value_1 = 'DISABLED'
+kmi.properties.value_2 = 'CONNECTED'
+kmi = km.items.add('mesh.select_all', 'SELECTMOUSE', 'CLICK')
+kmi.properties.action = 'DESELECT'
+
+wm.active_keyconfig = kc
+
+bpy.context.user_preferences.edit.drag_immediately = True
+bpy.context.user_preferences.edit.insertkey_xyz_to_rgb = False
+bpy.context.user_preferences.inputs.select_mouse = 'LEFT'
+bpy.context.user_preferences.inputs.zoom_style = 'DOLLY'
+bpy.context.user_preferences.inputs.zoom_axis = 'HORIZONTAL'
+bpy.context.user_preferences.inputs.view_rotation = 'TURNTABLE'
+bpy.context.user_preferences.inputs.invert_zoom_direction = True
diff --git a/release/scripts/presets/render/DVCPRO_HD_1080p.py b/release/scripts/presets/render/DVCPRO_HD_1080p.py
new file mode 100644
index 00000000000..f97b389795e
--- /dev/null
+++ b/release/scripts/presets/render/DVCPRO_HD_1080p.py
@@ -0,0 +1,8 @@
+import bpy
+bpy.context.scene.render.resolution_x = 1280
+bpy.context.scene.render.resolution_y = 1080
+bpy.context.scene.render.resolution_percentage = 100
+bpy.context.scene.render.pixel_aspect_x = 3
+bpy.context.scene.render.pixel_aspect_y = 2
+bpy.context.scene.render.fps = 24
+bpy.context.scene.render.fps_base = 1
diff --git a/release/scripts/presets/render/DVCPRO_HD_720p.py b/release/scripts/presets/render/DVCPRO_HD_720p.py
new file mode 100644
index 00000000000..dbe4c9243d8
--- /dev/null
+++ b/release/scripts/presets/render/DVCPRO_HD_720p.py
@@ -0,0 +1,8 @@
+import bpy
+bpy.context.scene.render.resolution_x = 960
+bpy.context.scene.render.resolution_y = 720
+bpy.context.scene.render.resolution_percentage = 100
+bpy.context.scene.render.pixel_aspect_x = 4
+bpy.context.scene.render.pixel_aspect_y = 3
+bpy.context.scene.render.fps = 24
+bpy.context.scene.render.fps_base = 1
diff --git a/release/scripts/presets/render/HDTV_1080p.py b/release/scripts/presets/render/HDTV_1080p.py
index 7693dae9347..32b771dc4a5 100644
--- a/release/scripts/presets/render/HDTV_1080p.py
+++ b/release/scripts/presets/render/HDTV_1080p.py
@@ -1,3 +1,4 @@
+import bpy
bpy.context.scene.render.resolution_x = 1920
bpy.context.scene.render.resolution_y = 1080
bpy.context.scene.render.resolution_percentage = 100
diff --git a/release/scripts/presets/render/HDTV_720p.py b/release/scripts/presets/render/HDTV_720p.py
index ee16c1e8b33..c5c81eeb790 100644
--- a/release/scripts/presets/render/HDTV_720p.py
+++ b/release/scripts/presets/render/HDTV_720p.py
@@ -1,3 +1,4 @@
+import bpy
bpy.context.scene.render.resolution_x = 1280
bpy.context.scene.render.resolution_y = 720
bpy.context.scene.render.resolution_percentage = 100
diff --git a/release/scripts/presets/render/HDV_1080p.py b/release/scripts/presets/render/HDV_1080p.py
new file mode 100644
index 00000000000..7637648e53a
--- /dev/null
+++ b/release/scripts/presets/render/HDV_1080p.py
@@ -0,0 +1,8 @@
+import bpy
+bpy.context.scene.render.resolution_x = 1440
+bpy.context.scene.render.resolution_y = 1080
+bpy.context.scene.render.resolution_percentage = 100
+bpy.context.scene.render.pixel_aspect_x = 4
+bpy.context.scene.render.pixel_aspect_y = 3
+bpy.context.scene.render.fps = 24
+bpy.context.scene.render.fps_base = 1
diff --git a/release/scripts/presets/render/TV_NTSC_16_colon_9.py b/release/scripts/presets/render/TV_NTSC_16_colon_9.py
new file mode 100644
index 00000000000..12ecaab4800
--- /dev/null
+++ b/release/scripts/presets/render/TV_NTSC_16_colon_9.py
@@ -0,0 +1,8 @@
+import bpy
+bpy.context.scene.render.resolution_x = 720
+bpy.context.scene.render.resolution_y = 480
+bpy.context.scene.render.resolution_percentage = 100
+bpy.context.scene.render.pixel_aspect_x = 40
+bpy.context.scene.render.pixel_aspect_y = 33
+bpy.context.scene.render.fps = 30
+bpy.context.scene.render.fps_base = 1.001
diff --git a/release/scripts/presets/render/TV_NTSC.py b/release/scripts/presets/render/TV_NTSC_4_colon_3.py
index cd6322fd21a..471c45b04d7 100644
--- a/release/scripts/presets/render/TV_NTSC.py
+++ b/release/scripts/presets/render/TV_NTSC_4_colon_3.py
@@ -1,5 +1,6 @@
+import bpy
bpy.context.scene.render.resolution_x = 720
-bpy.context.scene.render.resolution_y = 480
+bpy.context.scene.render.resolution_y = 486
bpy.context.scene.render.resolution_percentage = 100
bpy.context.scene.render.pixel_aspect_x = 10
bpy.context.scene.render.pixel_aspect_y = 11
diff --git a/release/scripts/presets/render/TV_PAL_16_colon_9.py b/release/scripts/presets/render/TV_PAL_16_colon_9.py
index 516209a877d..2add29e9408 100644
--- a/release/scripts/presets/render/TV_PAL_16_colon_9.py
+++ b/release/scripts/presets/render/TV_PAL_16_colon_9.py
@@ -1,7 +1,8 @@
+import bpy
bpy.context.scene.render.resolution_x = 720
bpy.context.scene.render.resolution_y = 576
bpy.context.scene.render.resolution_percentage = 100
-bpy.context.scene.render.pixel_aspect_x = 64
-bpy.context.scene.render.pixel_aspect_y = 45
+bpy.context.scene.render.pixel_aspect_x = 16
+bpy.context.scene.render.pixel_aspect_y = 11
bpy.context.scene.render.fps = 25
bpy.context.scene.render.fps_base = 1
diff --git a/release/scripts/presets/render/TV_PAL.py b/release/scripts/presets/render/TV_PAL_4_colon_3.py
index 4a71ad021fe..92cb794558e 100644
--- a/release/scripts/presets/render/TV_PAL.py
+++ b/release/scripts/presets/render/TV_PAL_4_colon_3.py
@@ -1,7 +1,8 @@
+import bpy
bpy.context.scene.render.resolution_x = 720
bpy.context.scene.render.resolution_y = 576
bpy.context.scene.render.resolution_percentage = 100
-bpy.context.scene.render.pixel_aspect_x = 54
-bpy.context.scene.render.pixel_aspect_y = 51
+bpy.context.scene.render.pixel_aspect_x = 12
+bpy.context.scene.render.pixel_aspect_y = 11
bpy.context.scene.render.fps = 25
bpy.context.scene.render.fps_base = 1
diff --git a/release/scripts/presets/sss/apple.py b/release/scripts/presets/sss/apple.py
index 474769cd36f..d505be2b435 100644
--- a/release/scripts/presets/sss/apple.py
+++ b/release/scripts/presets/sss/apple.py
@@ -1,2 +1,3 @@
+import bpy
bpy.context.active_object.active_material.subsurface_scattering.radius = 11.605, 3.884, 1.754
bpy.context.active_object.active_material.subsurface_scattering.color = 0.430, 0.210, 0.168
diff --git a/release/scripts/presets/sss/chicken.py b/release/scripts/presets/sss/chicken.py
index 6253de09376..53e199455c1 100644
--- a/release/scripts/presets/sss/chicken.py
+++ b/release/scripts/presets/sss/chicken.py
@@ -1,2 +1,3 @@
+import bpy
bpy.context.active_object.active_material.subsurface_scattering.radius = 9.436, 3.348, 1.790
bpy.context.active_object.active_material.subsurface_scattering.color = 0.439, 0.216, 0.141
diff --git a/release/scripts/presets/sss/cream.py b/release/scripts/presets/sss/cream.py
index f0a5292b85c..221739a30ab 100644
--- a/release/scripts/presets/sss/cream.py
+++ b/release/scripts/presets/sss/cream.py
@@ -1,2 +1,3 @@
+import bpy
bpy.context.active_object.active_material.subsurface_scattering.radius = 15.028, 4.664, 2.541
bpy.context.active_object.active_material.subsurface_scattering.color = 0.987, 0.943, 0.827
diff --git a/release/scripts/presets/sss/ketchup.py b/release/scripts/presets/sss/ketchup.py
index caece1ea7ca..96d136dc271 100644
--- a/release/scripts/presets/sss/ketchup.py
+++ b/release/scripts/presets/sss/ketchup.py
@@ -1,2 +1,3 @@
+import bpy
bpy.context.active_object.active_material.subsurface_scattering.radius = 4.762, 0.575, 0.394
bpy.context.active_object.active_material.subsurface_scattering.color = 0.222, 0.008, 0.002
diff --git a/release/scripts/presets/sss/marble.py b/release/scripts/presets/sss/marble.py
index ea894f69800..cd68fd7d26f 100644
--- a/release/scripts/presets/sss/marble.py
+++ b/release/scripts/presets/sss/marble.py
@@ -1,2 +1,3 @@
+import bpy
bpy.context.active_object.active_material.subsurface_scattering.radius = 8.509, 5.566, 3.951
bpy.context.active_object.active_material.subsurface_scattering.color = 0.925, 0.905, 0.884
diff --git a/release/scripts/presets/sss/potato.py b/release/scripts/presets/sss/potato.py
index 89407dff427..7a6c25db833 100644
--- a/release/scripts/presets/sss/potato.py
+++ b/release/scripts/presets/sss/potato.py
@@ -1,2 +1,3 @@
+import bpy
bpy.context.active_object.active_material.subsurface_scattering.radius = 14.266, 7.228, 2.036
bpy.context.active_object.active_material.subsurface_scattering.color = 0.855, 0.740, 0.292
diff --git a/release/scripts/presets/sss/skim_milk.py b/release/scripts/presets/sss/skim_milk.py
index 2e5b19d4f53..5be37b820da 100644
--- a/release/scripts/presets/sss/skim_milk.py
+++ b/release/scripts/presets/sss/skim_milk.py
@@ -1,2 +1,3 @@
+import bpy
bpy.context.active_object.active_material.subsurface_scattering.radius = 18.424, 10.443, 3.502
bpy.context.active_object.active_material.subsurface_scattering.color = 0.889, 0.888, 0.796
diff --git a/release/scripts/presets/sss/skin1.py b/release/scripts/presets/sss/skin1.py
index 42fb1fac43a..76dc64f61f9 100644
--- a/release/scripts/presets/sss/skin1.py
+++ b/release/scripts/presets/sss/skin1.py
@@ -1,2 +1,3 @@
+import bpy
bpy.context.active_object.active_material.subsurface_scattering.radius = 3.673, 1.367, 0.683
bpy.context.active_object.active_material.subsurface_scattering.color = 0.574, 0.313, 0.174
diff --git a/release/scripts/presets/sss/skin2.py b/release/scripts/presets/sss/skin2.py
index 52b649ecd8f..6a72a782638 100644
--- a/release/scripts/presets/sss/skin2.py
+++ b/release/scripts/presets/sss/skin2.py
@@ -1,2 +1,3 @@
+import bpy
bpy.context.active_object.active_material.subsurface_scattering.radius = 4.821, 1.694, 1.090
bpy.context.active_object.active_material.subsurface_scattering.color = 0.749, 0.571, 0.467
diff --git a/release/scripts/presets/sss/whole_milk.py b/release/scripts/presets/sss/whole_milk.py
index 4cb6ccf3dcf..59aaa135933 100644
--- a/release/scripts/presets/sss/whole_milk.py
+++ b/release/scripts/presets/sss/whole_milk.py
@@ -1,2 +1,3 @@
+import bpy
bpy.context.active_object.active_material.subsurface_scattering.radius = 10.899, 6.575, 2.508
bpy.context.active_object.active_material.subsurface_scattering.color = 0.947, 0.931, 0.852
diff --git a/release/scripts/presets/sunsky/classic.py b/release/scripts/presets/sunsky/classic.py
index 9ee35d68dad..4394dcce242 100644
--- a/release/scripts/presets/sunsky/classic.py
+++ b/release/scripts/presets/sunsky/classic.py
@@ -1,3 +1,4 @@
+import bpy
bpy.context.object.data.sky.atmosphere_turbidity = 4.0
bpy.context.object.data.sky.sky_blend_type = 'ADD'
bpy.context.object.data.sky.sky_blend = 1.0
diff --git a/release/scripts/presets/sunsky/desert.py b/release/scripts/presets/sunsky/desert.py
index 26ed4527746..f68ea23845b 100644
--- a/release/scripts/presets/sunsky/desert.py
+++ b/release/scripts/presets/sunsky/desert.py
@@ -1,3 +1,4 @@
+import bpy
bpy.context.object.data.sky.atmosphere_turbidity = 6.0
bpy.context.object.data.sky.sky_blend_type = 'ADD'
bpy.context.object.data.sky.sky_blend = 1.0
diff --git a/release/scripts/presets/sunsky/mountain.py b/release/scripts/presets/sunsky/mountain.py
index e35d3944042..9b81ffd4399 100644
--- a/release/scripts/presets/sunsky/mountain.py
+++ b/release/scripts/presets/sunsky/mountain.py
@@ -1,3 +1,4 @@
+import bpy
bpy.context.object.data.sky.atmosphere_turbidity = 2.00000023842
bpy.context.object.data.sky.sky_blend_type = 'ADD'
bpy.context.object.data.sky.sky_blend = 1.0
diff --git a/release/scripts/templates/gamelogic.py b/release/scripts/templates/gamelogic.py
index b4eac81b492..b31d5d95987 100644
--- a/release/scripts/templates/gamelogic.py
+++ b/release/scripts/templates/gamelogic.py
@@ -7,7 +7,7 @@
# import GameKeys
# support for Vector(), Matrix() types and advanced functions like ScaleMatrix(...) and RotationMatrix(...)
-# import Mathutils
+# import mathutils
# for functions like getWindowWidth(), getWindowHeight()
# import Rasterizer
diff --git a/release/scripts/templates/operator.py b/release/scripts/templates/operator.py
index 23d75607ba3..e20b92c9b6a 100644
--- a/release/scripts/templates/operator.py
+++ b/release/scripts/templates/operator.py
@@ -1,7 +1,6 @@
-
import bpy
-def write_some_data(context, path, use_some_setting):
+def write_some_data(context, filepath, use_some_setting):
print("running write_some_data...")
pass
@@ -16,7 +15,7 @@ class ExportSomeData(bpy.types.Operator):
# to the class instance from the operator settings before calling.
# TODO, add better example props
- path = StringProperty(name="File Path", description="File path used for exporting the PLY file", maxlen= 1024, default= "")
+ filepath = StringProperty(name="File Path", description="File path used for exporting the PLY file", maxlen= 1024, default= "")
use_setting = BoolProperty(name="Example Boolean", description="Example Tooltip", default= True)
type = bpy.props.EnumProperty(items=(('OPT_A', "First Option", "Description one"), ('OPT_B', "Second Option", "Description two.")),
@@ -30,10 +29,10 @@ class ExportSomeData(bpy.types.Operator):
def execute(self, context):
# # Bug, currently isnt working
- #if not self.is_property_set("path"):
+ #if not self.is_property_set("filepath"):
# raise Exception("filename not set")
- write_some_data(self.properties.path, context, self.properties.use_setting)
+ write_some_data(self.properties.filepath, context, self.properties.use_setting)
return {'FINISHED'}
@@ -63,4 +62,4 @@ menu_func = lambda self, context: self.layout.operator("export.some_data", text=
bpy.types.INFO_MT_file_export.append(menu_func)
if __name__ == "__main__":
- bpy.ops.export.some_data('INVOKE_DEFAULT', path="/tmp/test.ply")
+ bpy.ops.export.some_data('INVOKE_DEFAULT', filepath="/tmp/test.ply")
diff --git a/release/scripts/templates/operator_modal.py b/release/scripts/templates/operator_modal.py
index b2839efabe4..e029d91a7fa 100644
--- a/release/scripts/templates/operator_modal.py
+++ b/release/scripts/templates/operator_modal.py
@@ -1,3 +1,4 @@
+import bpy
from bpy.props import *
class ModalOperator(bpy.types.Operator):
diff --git a/release/scripts/templates/operator_modal_draw.py b/release/scripts/templates/operator_modal_draw.py
index 1f0d7a8504f..1f24672346b 100644
--- a/release/scripts/templates/operator_modal_draw.py
+++ b/release/scripts/templates/operator_modal_draw.py
@@ -1,13 +1,16 @@
+import bpy
import bgl
import blf
def draw_callback_px(self, context):
print("mouse points", len(self.mouse_path))
+ font_id = 0 # XXX, need to find out how best to get this.
+
# draw some text
- blf.position(15, 30, 0)
- blf.size(20, 72)
- blf.draw("Hello Word " + str(len(self.mouse_path)))
+ blf.position(font_id, 15, 30, 0)
+ blf.size(font_id, 20, 72)
+ blf.draw(font_id, "Hello Word " + str(len(self.mouse_path)))
# 50% alpha, 2 pixel width line
bgl.glEnable(bgl.GL_BLEND)
@@ -20,7 +23,7 @@ def draw_callback_px(self, context):
bgl.glEnd()
- # restore opengl defaults
+ # restore opengl defaults
bgl.glLineWidth(1)
bgl.glDisable(bgl.GL_BLEND)
bgl.glColor4f(0.0, 0.0, 0.0, 1.0)
@@ -50,7 +53,7 @@ class ModalDrawOperator(bpy.types.Operator):
def invoke(self, context, event):
if context.area.type == 'VIEW_3D':
context.manager.add_modal_handler(self)
-
+
# Add the region OpenGL drawing callback
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
self._handle = context.region.callback_add(draw_callback_px, (self, context), 'POST_PIXEL')
@@ -72,4 +75,4 @@ def unregister():
if __name__ == "__main__":
- register() \ No newline at end of file
+ register()
diff --git a/release/scripts/templates/operator_modal_view3d.py b/release/scripts/templates/operator_modal_view3d.py
new file mode 100644
index 00000000000..da019c2b653
--- /dev/null
+++ b/release/scripts/templates/operator_modal_view3d.py
@@ -0,0 +1,56 @@
+import bpy
+from mathutils import Vector
+from bpy.props import FloatVectorProperty
+
+class ViewOperator(bpy.types.Operator):
+ '''Translate the view using mouse events.'''
+ bl_idname = "view3d.modal_operator"
+ bl_label = "Simple View Operator"
+
+ offset = FloatVectorProperty(name="Offset", size=3)
+
+
+ def execute(self, context):
+ v3d = context.space_data
+ rv3d = v3d.region_3d
+
+ rv3d.view_location = self._initial_location + Vector(self.properties.offset)
+
+ def modal(self, context, event):
+ v3d = context.space_data
+ rv3d = v3d.region_3d
+
+ if event.type == 'MOUSEMOVE':
+ self.properties.offset = (self._initial_mouse - Vector((event.mouse_x, event.mouse_y, 0.0))) * 0.02
+ self.execute(context)
+
+ elif event.type == 'LEFTMOUSE':
+ return {'FINISHED'}
+
+ elif event.type in ('RIGHTMOUSE', 'ESC'):
+ rv3d.view_location = self._initial_location
+ return {'CANCELLED'}
+
+ return {'RUNNING_MODAL'}
+
+ def invoke(self, context, event):
+
+ if context.space_data.type == 'VIEW_3D':
+ v3d = context.space_data
+ rv3d = v3d.region_3d
+
+ context.manager.add_modal_handler(self)
+
+ if rv3d.view_perspective == 'CAMERA':
+ rv3d.view_perspective = 'PERSP'
+
+ self._initial_mouse = Vector((event.mouse_x, event.mouse_y, 0.0))
+ self._initial_location = rv3d.view_location.copy()
+
+ return {'RUNNING_MODAL'}
+ else:
+ self.report({'WARNING'}, "Active space must be a View3d")
+ return {'CANCELLED'}
+
+
+bpy.types.register(ViewOperator)
diff --git a/release/scripts/templates/operator_simple.py b/release/scripts/templates/operator_simple.py
index c62d3720d96..985a628c2d0 100644
--- a/release/scripts/templates/operator_simple.py
+++ b/release/scripts/templates/operator_simple.py
@@ -1,3 +1,4 @@
+import bpy
def main(context):
for ob in context.scene.objects:
@@ -15,7 +16,11 @@ class SimpleOperator(bpy.types.Operator):
main(context)
return {'FINISHED'}
-bpy.types.register(SimpleOperator)
+def register():
+ bpy.types.register(SimpleOperator)
+
+def unregister():
+ bpy.types.unregister(SimpleOperator)
if __name__ == "__main__":
- bpy.ops.object.simple_operator()
+ register()
diff --git a/release/scripts/templates/operator_uv.py b/release/scripts/templates/operator_uv.py
index 36d8333d49d..1003bd6c58b 100644
--- a/release/scripts/templates/operator_uv.py
+++ b/release/scripts/templates/operator_uv.py
@@ -1,3 +1,4 @@
+import bpy
def main(context):
obj = context.active_object
diff --git a/release/scripts/ui/properties_animviz.py b/release/scripts/ui/properties_animviz.py
index 71b49cea2f2..9eb046cc2c8 100644
--- a/release/scripts/ui/properties_animviz.py
+++ b/release/scripts/ui/properties_animviz.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
################################################
# Generic Panels (Independent of DataType)
@@ -49,8 +49,8 @@ class MotionPathButtonsPanel(bpy.types.Panel):
sub.prop(mps, "before_current", text="Before")
sub.prop(mps, "after_current", text="After")
elif (mps.type == 'RANGE'):
- sub.prop(mps, "start_frame", text="Start")
- sub.prop(mps, "end_frame", text="End")
+ sub.prop(mps, "frame_start", text="Start")
+ sub.prop(mps, "frame_end", text="End")
sub.prop(mps, "frame_step", text="Step")
if bones:
@@ -61,6 +61,8 @@ class MotionPathButtonsPanel(bpy.types.Panel):
col.label(text="Display:")
col.prop(mps, "show_frame_numbers", text="Frame Numbers")
col.prop(mps, "highlight_keyframes", text="Keyframes")
+ if bones:
+ col.prop(mps, "search_all_action_keyframes", text="+ Non-Grouped Keyframes")
col.prop(mps, "show_keyframe_numbers", text="Keyframe Numbers")
@@ -88,8 +90,8 @@ class OnionSkinButtonsPanel(bpy.types.Panel):
sub = col.column(align=True)
if arm.ghost_type == 'RANGE':
- sub.prop(arm, "ghost_start_frame", text="Start")
- sub.prop(arm, "ghost_end_frame", text="End")
+ sub.prop(arm, "ghost_frame_start", text="Start")
+ sub.prop(arm, "ghost_frame_end", text="End")
sub.prop(arm, "ghost_size", text="Step")
elif arm.ghost_type == 'CURRENT_FRAME':
sub.prop(arm, "ghost_step", text="Range")
@@ -103,6 +105,7 @@ class OnionSkinButtonsPanel(bpy.types.Panel):
################################################
# Specific Panels for DataTypes
+
class OBJECT_PT_motion_paths(MotionPathButtonsPanel):
#bl_label = "Object Motion Paths"
bl_context = "object"
@@ -129,13 +132,14 @@ class OBJECT_PT_motion_paths(MotionPathButtonsPanel):
col = split.column()
col.operator("object.paths_clear", text="Clear Paths")
+
class OBJECT_PT_onion_skinning(OnionSkinButtonsPanel):
#bl_label = "Object Onion Skinning"
bl_context = "object"
def poll(self, context):
return (context.object)
-
+
def draw(self, context):
layout = self.layout
@@ -144,6 +148,7 @@ class OBJECT_PT_onion_skinning(OnionSkinButtonsPanel):
self.draw_settings(context, ob.animation_visualisation, wide_ui)
+
class DATA_PT_motion_paths(MotionPathButtonsPanel):
#bl_label = "Bones Motion Paths"
bl_context = "data"
@@ -171,6 +176,7 @@ class DATA_PT_motion_paths(MotionPathButtonsPanel):
col = split.column()
col.operator("pose.paths_clear", text="Clear Paths")
+
class DATA_PT_onion_skinning(OnionSkinButtonsPanel):
#bl_label = "Bones Onion Skinning"
bl_context = "data"
@@ -187,17 +193,18 @@ class DATA_PT_onion_skinning(OnionSkinButtonsPanel):
self.draw_settings(context, ob.pose.animation_visualisation, wide_ui, bones=True)
-# NOTE:
+# NOTE:
# The specialised panel types defined here (i.e. OBJECT_PT_*, etc.)
# aren't registered here, but are rather imported to (and registered)
# in the files defining the contexts where they reside. Otherwise,
# these panels appear at the top of the lists by default.
#
# However, we keep these empty register funcs here just in case
-# something will need them again one day, and also to make
+# something will need them again one day, and also to make
# it easier to maintain these scripts.
classes = []
+
def register():
register = bpy.types.register
for cls in classes:
diff --git a/release/scripts/ui/properties_data_armature.py b/release/scripts/ui/properties_data_armature.py
index b7864618de6..38903cc1f27 100644
--- a/release/scripts/ui/properties_data_armature.py
+++ b/release/scripts/ui/properties_data_armature.py
@@ -20,7 +20,7 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class DataButtonsPanel(bpy.types.Panel):
@@ -69,7 +69,10 @@ class DATA_PT_skeleton(DataButtonsPanel):
arm = context.armature
wide_ui = context.region.width > narrowui
- layout.prop(arm, "pose_position", expand=True)
+ if wide_ui:
+ layout.prop(arm, "pose_position", expand=True)
+ else:
+ layout.prop(arm, "pose_position", text="")
split = layout.split()
@@ -79,13 +82,17 @@ class DATA_PT_skeleton(DataButtonsPanel):
col.label(text="Protected Layers:")
col.prop(arm, "layer_protection", text="")
- if wide_ui:
- col = split.column()
col.label(text="Deform:")
+
+ split = layout.split()
+
+ col = split.column()
col.prop(arm, "deform_vertexgroups", text="Vertex Groups")
col.prop(arm, "deform_envelope", text="Envelopes")
+
+ if wide_ui:
+ col = split.column()
col.prop(arm, "deform_quaternion", text="Quaternion")
- col.prop(arm, "deform_bbone_rest", text="B-Bones Rest")
class DATA_PT_display(DataButtonsPanel):
@@ -114,7 +121,6 @@ class DATA_PT_display(DataButtonsPanel):
col = split.column()
col.prop(arm, "draw_group_colors", text="Colors")
col.prop(arm, "delay_deform", text="Delay Refresh")
- col.prop(ob, "x_ray", text="X-Ray (Object)")
class DATA_PT_bone_groups(DataButtonsPanel):
@@ -154,13 +160,16 @@ class DATA_PT_bone_groups(DataButtonsPanel):
col = split.column()
col.template_triColorSet(group, "colors")
- row = layout.row(align=True)
+ row = layout.row()
row.active = (ob.proxy is None)
- row.operator("pose.group_assign", text="Assign")
- row.operator("pose.group_unassign", text="Remove") #row.operator("pose.bone_group_remove_from", text="Remove")
- #row.operator("object.bone_group_select", text="Select")
- #row.operator("object.bone_group_deselect", text="Deselect")
+ sub = row.row(align=True)
+ sub.operator("pose.group_assign", text="Assign")
+ sub.operator("pose.group_unassign", text="Remove") #row.operator("pose.bone_group_remove_from", text="Remove")
+
+ sub = row.row(align=True)
+ sub.operator("pose.group_select", text="Select")
+ sub.operator("pose.group_deselect", text="Deselect")
# TODO: this panel will soon be depreceated too
@@ -186,8 +195,8 @@ class DATA_PT_ghost(DataButtonsPanel):
sub = col.column(align=True)
if arm.ghost_type == 'RANGE':
- sub.prop(arm, "ghost_start_frame", text="Start")
- sub.prop(arm, "ghost_end_frame", text="End")
+ sub.prop(arm, "ghost_frame_start", text="Start")
+ sub.prop(arm, "ghost_frame_end", text="End")
sub.prop(arm, "ghost_size", text="Step")
elif arm.ghost_type == 'CURRENT_FRAME':
sub.prop(arm, "ghost_step", text="Range")
@@ -253,7 +262,7 @@ class DATA_PT_iksolver_itasc(DataButtonsPanel):
row.prop(itasc, "dampmax", text="Damp", slider=True)
row.prop(itasc, "dampeps", text="Eps", slider=True)
-# import generic panels from other files
+# import generic panels from other files
from properties_animviz import DATA_PT_motion_paths, DATA_PT_onion_skinning
classes = [
diff --git a/release/scripts/ui/properties_data_armature_rigify.py b/release/scripts/ui/properties_data_armature_rigify.py
index 99df79ed970..43021858f9f 100644
--- a/release/scripts/ui/properties_data_armature_rigify.py
+++ b/release/scripts/ui/properties_data_armature_rigify.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class PoseTemplateSettings(bpy.types.IDPropertyGroup):
@@ -29,28 +29,6 @@ class PoseTemplateSettings(bpy.types.IDPropertyGroup):
class PoseTemplate(bpy.types.IDPropertyGroup):
pass
-PoseTemplate.StringProperty(attr="name",
- name="Name of the slave",
- description="",
- maxlen=64,
- default="")
-
-
-PoseTemplateSettings.CollectionProperty(attr="templates", type=PoseTemplate, name="Templates", description="")
-PoseTemplateSettings.IntProperty(attr="active_template_index",
- name="Index of the active slave",
- description="",
- default=-1,
- min=-1,
- max=65535)
-
-PoseTemplateSettings.BoolProperty(attr="generate_def_rig",
- name="Create Deform Rig",
- description="Create a copy of the metarig, constrainted by the generated rig",
- default=False)
-
-bpy.types.Scene.PointerProperty(attr="pose_templates", type=PoseTemplateSettings, name="Pose Templates", description="Pose Template Settings")
-
def metarig_templates():
import rigify
@@ -234,7 +212,7 @@ class Graph(bpy.types.Operator):
import bpy
reload(graphviz_export)
obj = bpy.context.object
- path = os.path.splitext(bpy.data.filename)[0] + "-" + bpy.utils.clean_name(obj.name)
+ path = os.path.splitext(bpy.data.filepath)[0] + "-" + bpy.utils.clean_name(obj.name)
path_dot = path + ".dot"
path_png = path + ".png"
saved = graphviz_export.graph_armature(bpy.context.object, path_dot, CONSTRAINTS=False, DRIVERS=False)
@@ -254,14 +232,14 @@ class AsScript(bpy.types.Operator):
bl_label = "Write Metarig to Script"
bl_options = {'REGISTER', 'UNDO'}
- path = StringProperty(name="File Path", description="File path used for exporting the Armature file", maxlen=1024, default="")
+ filepath = StringProperty(name="File Path", description="File path used for exporting the Armature file", maxlen=1024, default="")
def execute(self, context):
import rigify_utils
reload(rigify_utils)
obj = context.object
code = rigify_utils.write_meta_rig(obj)
- path = self.properties.path
+ path = self.properties.filepath
file = open(path, "w")
file.write(code)
file.close()
@@ -271,7 +249,7 @@ class AsScript(bpy.types.Operator):
def invoke(self, context, event):
import os
obj = context.object
- self.properties.path = os.path.splitext(bpy.data.filename)[0] + "-" + bpy.utils.clean_name(obj.name) + ".py"
+ self.properties.filepath = os.path.splitext(bpy.data.filepath)[0] + "-" + bpy.utils.clean_name(obj.name) + ".py"
wm = context.manager
wm.add_fileselect(self)
return {'RUNNING_MODAL'}
@@ -356,6 +334,28 @@ def register():
for cls in classes:
register(cls)
+ PoseTemplate.StringProperty(attr="name",
+ name="Name of the slave",
+ description="",
+ maxlen=64,
+ default="")
+
+
+ PoseTemplateSettings.CollectionProperty(attr="templates", type=PoseTemplate, name="Templates", description="")
+ PoseTemplateSettings.IntProperty(attr="active_template_index",
+ name="Index of the active slave",
+ description="",
+ default=-1,
+ min=-1,
+ max=65535)
+
+ PoseTemplateSettings.BoolProperty(attr="generate_def_rig",
+ name="Create Deform Rig",
+ description="Create a copy of the metarig, constrainted by the generated rig",
+ default=False)
+
+ bpy.types.Scene.PointerProperty(attr="pose_templates", type=PoseTemplateSettings, name="Pose Templates", description="Pose Template Settings")
+
space_info.INFO_MT_armature_add.append(menu_func)
diff --git a/release/scripts/ui/properties_data_bone.py b/release/scripts/ui/properties_data_bone.py
index a6bac3e6aaa..b6b638ef380 100644
--- a/release/scripts/ui/properties_data_bone.py
+++ b/release/scripts/ui/properties_data_bone.py
@@ -20,7 +20,7 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class BoneButtonsPanel(bpy.types.Panel):
@@ -257,6 +257,9 @@ class BONE_PT_inverse_kinematics(BoneButtonsPanel):
pchan = ob.pose.bones[bone.name]
wide_ui = context.region.width > narrowui
+ row = layout.row()
+ row.prop(ob.pose, "ik_solver")
+
split = layout.split(percentage=0.25)
split.prop(pchan, "ik_dof_x", text="X")
split.active = pchan.has_ik
diff --git a/release/scripts/ui/properties_data_camera.py b/release/scripts/ui/properties_data_camera.py
index be0a4f84145..3abd460c427 100644
--- a/release/scripts/ui/properties_data_camera.py
+++ b/release/scripts/ui/properties_data_camera.py
@@ -20,7 +20,7 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class DataButtonsPanel(bpy.types.Panel):
@@ -29,12 +29,14 @@ class DataButtonsPanel(bpy.types.Panel):
bl_context = "data"
def poll(self, context):
- return context.camera
+ engine = context.scene.render.engine
+ return context.camera and (engine in self.COMPAT_ENGINES)
class DATA_PT_context_camera(DataButtonsPanel):
bl_label = ""
bl_show_header = False
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -61,10 +63,12 @@ class DATA_PT_context_camera(DataButtonsPanel):
class DATA_PT_custom_props_camera(DataButtonsPanel, PropertyPanel):
_context_path = "object.data"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
class DATA_PT_camera(DataButtonsPanel):
bl_label = "Lens"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -125,6 +129,7 @@ class DATA_PT_camera(DataButtonsPanel):
class DATA_PT_camera_display(DataButtonsPanel):
bl_label = "Display"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/ui/properties_data_curve.py b/release/scripts/ui/properties_data_curve.py
index 9848e423665..fd836f5e5d4 100644
--- a/release/scripts/ui/properties_data_curve.py
+++ b/release/scripts/ui/properties_data_curve.py
@@ -20,7 +20,7 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class DataButtonsPanel(bpy.types.Panel):
@@ -44,7 +44,7 @@ class DataButtonsPanelActive(DataButtonsPanel):
def poll(self, context):
curve = context.curve
- return (curve and curve.active_spline)
+ return (curve and type(curve) is not bpy.types.TextCurve and curve.splines.active)
class DATA_PT_context_curve(DataButtonsPanel):
@@ -120,13 +120,13 @@ class DATA_PT_shape_curve(DataButtonsPanel):
if is_curve or is_text:
sub = col.column()
- sub.active = (curve.dimensions == '2D')
sub.label(text="Caps:")
sub.prop(curve, "front")
sub.prop(curve, "back")
+ sub.prop(curve, "use_deform_fill")
col.label(text="Textures:")
-# col.prop(curve, "uv_orco")
+ col.prop(curve, "map_along_length")
col.prop(curve, "auto_texspace")
@@ -204,7 +204,7 @@ class DATA_PT_active_spline(DataButtonsPanelActive):
ob = context.object
curve = context.curve
- act_spline = curve.active_spline
+ act_spline = curve.splines.active
is_surf = (ob.type == 'SURFACE')
is_poly = (act_spline.type == 'POLY')
@@ -308,10 +308,11 @@ class DATA_PT_font(DataButtonsPanel):
split = layout.split()
- col = split.column(align=True)
- col.label(text="Underline:")
- col.prop(text, "ul_position", text="Position")
- col.prop(text, "ul_height", text="Thickness")
+ col = split.column()
+ colsub = col.column(align=True)
+ colsub.label(text="Underline:")
+ colsub.prop(text, "ul_position", text="Position")
+ colsub.prop(text, "ul_height", text="Thickness")
if wide_ui:
col = split.column()
@@ -319,8 +320,13 @@ class DATA_PT_font(DataButtonsPanel):
col.prop(char, "bold")
col.prop(char, "italic")
col.prop(char, "underline")
-# col.prop(char, "style")
-# col.prop(char, "wrap")
+
+ split = layout.split()
+ col = split.column()
+ col.prop(text, "small_caps_scale", text="Small Caps")
+
+ col = split.column()
+ col.prop(char, "use_small_caps")
class DATA_PT_paragraph(DataButtonsPanel):
@@ -368,20 +374,35 @@ class DATA_PT_textboxes(DataButtonsPanel):
text = context.curve
wide_ui = context.region.width > narrowui
- for box in text.textboxes:
- split = layout.box().split()
+ split = layout.split()
+ col = split.column()
+ col.operator("font.textbox_add", icon='ZOOMIN')
+ if wide_ui:
+ col = split.column()
+
+ for i, box in enumerate(text.textboxes):
+
+ boxy = layout.box()
+
+ row = boxy.row()
+
+ split = row.split()
col = split.column(align=True)
+
col.label(text="Dimensions:")
col.prop(box, "width", text="Width")
col.prop(box, "height", text="Height")
if wide_ui:
col = split.column(align=True)
+
col.label(text="Offset:")
col.prop(box, "x", text="X")
col.prop(box, "y", text="Y")
+ row.operator("font.textbox_remove", text='', icon='X', emboss=False).index = i
+
classes = [
DATA_PT_context_curve,
diff --git a/release/scripts/ui/properties_data_empty.py b/release/scripts/ui/properties_data_empty.py
index a0999fb9d4a..577e32ed840 100644
--- a/release/scripts/ui/properties_data_empty.py
+++ b/release/scripts/ui/properties_data_empty.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class DataButtonsPanel(bpy.types.Panel):
diff --git a/release/scripts/ui/properties_data_lamp.py b/release/scripts/ui/properties_data_lamp.py
index 9a99959a610..14493301b1e 100644
--- a/release/scripts/ui/properties_data_lamp.py
+++ b/release/scripts/ui/properties_data_lamp.py
@@ -20,13 +20,14 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class LAMP_MT_sunsky_presets(bpy.types.Menu):
- bl_label = "Render Presets"
+ bl_label = "Sun & Sky Presets"
preset_subdir = "sunsky"
- preset_operator = "script.python_file_run"
+ preset_operator = "script.execute_preset"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
draw = bpy.types.Menu.draw_preset
@@ -36,11 +37,13 @@ class DataButtonsPanel(bpy.types.Panel):
bl_context = "data"
def poll(self, context):
- return context.lamp
+ engine = context.scene.render.engine
+ return context.lamp and (engine in self.COMPAT_ENGINES)
class DATA_PT_preview(DataButtonsPanel):
bl_label = "Preview"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
self.layout.template_preview(context.lamp)
@@ -49,6 +52,7 @@ class DATA_PT_preview(DataButtonsPanel):
class DATA_PT_context_lamp(DataButtonsPanel):
bl_label = ""
bl_show_header = False
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -75,10 +79,12 @@ class DATA_PT_context_lamp(DataButtonsPanel):
class DATA_PT_custom_props_lamp(DataButtonsPanel, PropertyPanel):
_context_path = "object.data"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
class DATA_PT_lamp(DataButtonsPanel):
bl_label = "Lamp"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -125,10 +131,12 @@ class DATA_PT_lamp(DataButtonsPanel):
class DATA_PT_sunsky(DataButtonsPanel):
bl_label = "Sky & Atmosphere"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
lamp = context.lamp
- return (lamp and lamp.type == 'SUN')
+ engine = context.scene.render.engine
+ return (lamp and lamp.type == 'SUN') and (engine in self.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -138,8 +146,8 @@ class DATA_PT_sunsky(DataButtonsPanel):
row = layout.row(align=True)
row.prop(lamp, "use_sky")
- row.menu("LAMP_MT_sunsky_presets", text="Presets")
- row.operator("lamp.sunsky_preset_add", text="Add")
+ row.menu("LAMP_MT_sunsky_presets", text=bpy.types.LAMP_MT_sunsky_presets.bl_label)
+ row.operator("lamp.sunsky_preset_add", text="", icon="ZOOMIN")
row = layout.row()
row.active = lamp.use_sky or lamp.use_atmosphere
@@ -196,10 +204,12 @@ class DATA_PT_sunsky(DataButtonsPanel):
class DATA_PT_shadow(DataButtonsPanel):
bl_label = "Shadow"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
lamp = context.lamp
- return (lamp and lamp.type in ('POINT', 'SUN', 'SPOT', 'AREA'))
+ engine = context.scene.render.engine
+ return (lamp and lamp.type in ('POINT', 'SUN', 'SPOT', 'AREA')) and (engine in self.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -319,10 +329,12 @@ class DATA_PT_shadow(DataButtonsPanel):
class DATA_PT_area(DataButtonsPanel):
bl_label = "Area Shape"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
lamp = context.lamp
- return (lamp and lamp.type == 'AREA')
+ engine = context.scene.render.engine
+ return (lamp and lamp.type == 'AREA') and (engine in self.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -344,10 +356,12 @@ class DATA_PT_area(DataButtonsPanel):
class DATA_PT_spot(DataButtonsPanel):
bl_label = "Spot Shape"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
lamp = context.lamp
- return (lamp and lamp.type == 'SPOT')
+ engine = context.scene.render.engine
+ return (lamp and lamp.type == 'SPOT') and (engine in self.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -379,11 +393,13 @@ class DATA_PT_spot(DataButtonsPanel):
class DATA_PT_falloff_curve(DataButtonsPanel):
bl_label = "Falloff Curve"
bl_default_closed = True
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
lamp = context.lamp
+ engine = context.scene.render.engine
- return (lamp and lamp.type in ('POINT', 'SPOT') and lamp.falloff_type == 'CUSTOM_CURVE')
+ return (lamp and lamp.type in ('POINT', 'SPOT') and lamp.falloff_type == 'CUSTOM_CURVE') and (engine in self.COMPAT_ENGINES)
def draw(self, context):
lamp = context.lamp
diff --git a/release/scripts/ui/properties_data_lattice.py b/release/scripts/ui/properties_data_lattice.py
index 0c1f9d8001c..2aa719437a7 100644
--- a/release/scripts/ui/properties_data_lattice.py
+++ b/release/scripts/ui/properties_data_lattice.py
@@ -20,7 +20,7 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class DataButtonsPanel(bpy.types.Panel):
@@ -93,7 +93,9 @@ class DATA_PT_lattice(DataButtonsPanel):
col = split.column()
col.prop(lat, "interpolation_type_w", text="")
- layout.prop(lat, "outside")
+ row = layout.row()
+ row.prop(lat, "outside")
+ row.prop_object(lat, "vertex_group", context.object, "vertex_groups", text="")
classes = [
diff --git a/release/scripts/ui/properties_data_mesh.py b/release/scripts/ui/properties_data_mesh.py
index d48d2ec8046..44d3d19e793 100644
--- a/release/scripts/ui/properties_data_mesh.py
+++ b/release/scripts/ui/properties_data_mesh.py
@@ -20,11 +20,12 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class MESH_MT_vertex_group_specials(bpy.types.Menu):
bl_label = "Vertex Group Specials"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -38,6 +39,7 @@ class MESH_MT_vertex_group_specials(bpy.types.Menu):
class MESH_MT_shape_key_specials(bpy.types.Menu):
bl_label = "Shape Key Specials"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -53,12 +55,14 @@ class DataButtonsPanel(bpy.types.Panel):
bl_context = "data"
def poll(self, context):
- return context.mesh
+ engine = context.scene.render.engine
+ return context.mesh and (engine in self.COMPAT_ENGINES)
class DATA_PT_context_mesh(DataButtonsPanel):
bl_label = ""
bl_show_header = False
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -85,10 +89,12 @@ class DATA_PT_context_mesh(DataButtonsPanel):
class DATA_PT_custom_props_mesh(DataButtonsPanel, PropertyPanel):
_context_path = "object.data"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
class DATA_PT_normals(DataButtonsPanel):
bl_label = "Normals"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -114,6 +120,7 @@ class DATA_PT_normals(DataButtonsPanel):
class DATA_PT_settings(DataButtonsPanel):
bl_label = "Settings"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -125,9 +132,11 @@ class DATA_PT_settings(DataButtonsPanel):
class DATA_PT_vertex_groups(DataButtonsPanel):
bl_label = "Vertex Groups"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
- return (context.object and context.object.type in ('MESH', 'LATTICE'))
+ engine = context.scene.render.engine
+ return (context.object and context.object.type in ('MESH', 'LATTICE') and (engine in self.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -146,6 +155,9 @@ class DATA_PT_vertex_groups(DataButtonsPanel):
col.operator("object.vertex_group_add", icon='ZOOMIN', text="")
col.operator("object.vertex_group_remove", icon='ZOOMOUT', text="")
col.menu("MESH_MT_vertex_group_specials", icon='DOWNARROW_HLT', text="")
+ if group:
+ col.operator("object.vertex_group_move", icon='TRIA_UP', text="").direction = 'UP'
+ col.operator("object.vertex_group_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
if group:
row = layout.row()
@@ -167,9 +179,11 @@ class DATA_PT_vertex_groups(DataButtonsPanel):
class DATA_PT_shape_keys(DataButtonsPanel):
bl_label = "Shape Keys"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
- return (context.object and context.object.type in ('MESH', 'LATTICE', 'CURVE', 'SURFACE'))
+ engine = context.scene.render.engine
+ return (context.object and context.object.type in ('MESH', 'LATTICE', 'CURVE', 'SURFACE') and (engine in self.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -263,6 +277,7 @@ class DATA_PT_shape_keys(DataButtonsPanel):
class DATA_PT_uv_texture(DataButtonsPanel):
bl_label = "UV Texture"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -283,8 +298,56 @@ class DATA_PT_uv_texture(DataButtonsPanel):
layout.prop(lay, "name")
+class DATA_PT_texface(DataButtonsPanel):
+ bl_label = "Texture Face"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ def poll(self, context):
+ ob = context.active_object
+ rd = context.scene.render
+
+ return (context.mode == 'EDIT_MESH') and (rd.engine == 'BLENDER_GAME') and ob and ob.type == 'MESH'
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column()
+
+ wide_ui = context.region.width > narrowui
+ me = context.mesh
+
+ tf = me.faces.active_tface
+
+ if tf:
+ split = layout.split()
+ col = split.column()
+
+ col.prop(tf, "tex")
+ col.prop(tf, "light")
+ col.prop(tf, "invisible")
+ col.prop(tf, "collision")
+
+ col.prop(tf, "shared")
+ col.prop(tf, "twoside")
+ col.prop(tf, "object_color")
+
+ if wide_ui:
+ col = split.column()
+
+ col.prop(tf, "halo")
+ col.prop(tf, "billboard")
+ col.prop(tf, "shadow")
+ col.prop(tf, "text")
+ col.prop(tf, "alpha_sort")
+
+ col = layout.column()
+ col.prop(tf, "transp")
+ else:
+ col.label(text="No UV Texture")
+
+
class DATA_PT_vertex_colors(DataButtonsPanel):
bl_label = "Vertex Colors"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -315,6 +378,7 @@ classes = [
DATA_PT_vertex_groups,
DATA_PT_shape_keys,
DATA_PT_uv_texture,
+ DATA_PT_texface,
DATA_PT_vertex_colors,
DATA_PT_custom_props_mesh]
diff --git a/release/scripts/ui/properties_data_metaball.py b/release/scripts/ui/properties_data_metaball.py
index b751a9f9059..e0155059b98 100644
--- a/release/scripts/ui/properties_data_metaball.py
+++ b/release/scripts/ui/properties_data_metaball.py
@@ -20,7 +20,7 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class DataButtonsPanel(bpy.types.Panel):
diff --git a/release/scripts/ui/properties_data_modifier.py b/release/scripts/ui/properties_data_modifier.py
index 8364d070d1a..dfa0d8029b2 100644
--- a/release/scripts/ui/properties_data_modifier.py
+++ b/release/scripts/ui/properties_data_modifier.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
narrowmod = 260
@@ -164,7 +164,7 @@ class DATA_PT_modifiers(DataButtonsPanel):
split = layout.split()
col = split.column()
- col.prop(md, "start")
+ col.prop(md, "frame_start")
col.prop(md, "length")
if wide_ui:
@@ -229,7 +229,7 @@ class DATA_PT_modifiers(DataButtonsPanel):
def DECIMATE(self, layout, ob, md, wide_ui):
layout.prop(md, "ratio")
- layout.prop(md, "face_count")
+ layout.label(text="Face Count: %s" % str(md.face_count))
def DISPLACE(self, layout, ob, md, wide_ui):
split = layout.split()
@@ -291,6 +291,7 @@ class DATA_PT_modifiers(DataButtonsPanel):
col.prop(md, "unborn")
col.prop(md, "alive")
col.prop(md, "dead")
+ col.prop(md, "size")
layout.operator("object.explode_refresh", text="Refresh")
@@ -368,7 +369,6 @@ class DATA_PT_modifiers(DataButtonsPanel):
sub = col.column()
sub.label(text="Object:")
sub.prop(md, "object", text="")
- sub.prop(md, "mode", text="")
sub.active = not md.is_bound
if wide_ui:
col = split.column()
@@ -386,15 +386,14 @@ class DATA_PT_modifiers(DataButtonsPanel):
else:
layout.operator("object.meshdeform_bind", text="Bind")
- if md.mode == 'VOLUME':
- split = layout.split()
+ split = layout.split()
- col = split.column()
- col.prop(md, "precision")
+ col = split.column()
+ col.prop(md, "precision")
- if wide_ui:
- col = split.column()
- col.prop(md, "dynamic")
+ if wide_ui:
+ col = split.column()
+ col.prop(md, "dynamic")
def MIRROR(self, layout, ob, md, wide_ui):
layout.prop(md, "merge_limit")
@@ -438,6 +437,7 @@ class DATA_PT_modifiers(DataButtonsPanel):
col.prop(md, "levels", text="Preview")
col.prop(md, "sculpt_levels", text="Sculpt")
col.prop(md, "render_levels", text="Render")
+ col.prop(bpy.context.tool_settings.sculpt, "fast_navigate")
if wide_ui:
col = split.column()
@@ -453,12 +453,12 @@ class DATA_PT_modifiers(DataButtonsPanel):
col = layout.column()
row = col.row()
if md.external:
- row.operator("object.multires_pack_external", text="Pack External")
+ row.operator("object.multires_external_pack", text="Pack External")
row.label()
row = col.row()
- row.prop(md, "filename", text="")
+ row.prop(md, "filepath", text="")
else:
- row.operator("object.multires_save_external", text="Save External...")
+ row.operator("object.multires_external_save", text="Save External...")
row.label()
def PARTICLE_INSTANCE(self, layout, ob, md, wide_ui):
@@ -481,10 +481,10 @@ class DATA_PT_modifiers(DataButtonsPanel):
layout.separator()
- layout.prop(md, "path", text="Create Along Paths")
+ layout.prop(md, "use_path", text="Create Along Paths")
split = layout.split()
- split.active = md.path
+ split.active = md.use_path
col = split.column()
col.row().prop(md, "axis", expand=True)
col.prop(md, "keep_shape")
@@ -497,6 +497,28 @@ class DATA_PT_modifiers(DataButtonsPanel):
def PARTICLE_SYSTEM(self, layout, ob, md, wide_ui):
layout.label(text="See Particle panel.")
+ def SCREW(self, layout, ob, md, wide_ui):
+ split = layout.split()
+
+ col = split.column()
+ col.prop(md, "axis")
+ col.prop(md, "object", text="AxisOb")
+ col.prop(md, "angle")
+ col.prop(md, "steps")
+ col.prop(md, "render_steps")
+
+ if wide_ui:
+ col = split.column()
+ row = col.row()
+ row.active = (md.object is None or md.use_object_screw_offset == False)
+ row.prop(md, "screw_offset")
+ row = col.row()
+ row.active = (md.object is not None)
+ row.prop(md, "use_object_screw_offset")
+ col.prop(md, "use_normal_calculate")
+ col.prop(md, "use_normal_flip")
+ col.prop(md, "iterations")
+
def SHRINKWRAP(self, layout, ob, md, wide_ui):
split = layout.split()
col = split.column()
@@ -602,11 +624,13 @@ class DATA_PT_modifiers(DataButtonsPanel):
layout.label(text="See Soft Body panel.")
def SOLIDIFY(self, layout, ob, md, wide_ui):
- layout.prop(md, "offset")
split = layout.split()
col = split.column()
+ col.prop(md, "thickness")
+ col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
+
col.label(text="Crease:")
col.prop(md, "edge_crease_inner", text="Inner")
col.prop(md, "edge_crease_outer", text="Outer")
@@ -614,11 +638,20 @@ class DATA_PT_modifiers(DataButtonsPanel):
if wide_ui:
col = split.column()
- col.label()
- col.prop(md, "use_rim")
+
+ col.prop(md, "offset")
+ colsub = col.column()
+ colsub.active = (md.vertex_group is not "")
+ colsub.prop(md, "invert", text="Invert")
+
col.prop(md, "use_even_offset")
col.prop(md, "use_quality_normals")
+ col.prop(md, "use_rim")
+ colsub = col.column()
+ colsub.active = md.use_rim
+ colsub.prop(md, "use_rim_material")
+
# col = layout.column()
# col.label(text="Vertex Group:")
# col.prop_object(md, "vertex_group", ob, "vertex_groups", text="")
@@ -638,6 +671,7 @@ class DATA_PT_modifiers(DataButtonsPanel):
if wide_ui:
col = split.column()
col.label(text="Options:")
+ col.prop(md, "subsurf_uv")
col.prop(md, "optimal_display")
def SURFACE(self, layout, ob, md, wide_ui):
@@ -666,9 +700,12 @@ class DATA_PT_modifiers(DataButtonsPanel):
if wide_ui:
col = split.column()
sub = col.column(align=True)
- sub.label(text="Aspect Ratio:")
- sub.prop(md, "horizontal_aspect_ratio", text="Horizontal")
- sub.prop(md, "vertical_aspect_ratio", text="Vertical")
+ sub.prop(md, "aspect_x", text="Aspect X")
+ sub.prop(md, "aspect_y", text="Aspect Y")
+
+ sub = col.column(align=True)
+ sub.prop(md, "scale_x", text="Scale X")
+ sub.prop(md, "scale_y", text="Scale Y")
def WAVE(self, layout, ob, md, wide_ui):
split = layout.split()
diff --git a/release/scripts/ui/properties_game.py b/release/scripts/ui/properties_game.py
index 41af955d9ec..9ec7168f834 100644
--- a/release/scripts/ui/properties_game.py
+++ b/release/scripts/ui/properties_game.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class PhysicsButtonsPanel(bpy.types.Panel):
@@ -30,11 +30,12 @@ class PhysicsButtonsPanel(bpy.types.Panel):
def poll(self, context):
ob = context.active_object
rd = context.scene.render
- return ob and ob.game and (rd.engine == 'BLENDER_GAME')
+ return ob and ob.game and (rd.engine in self.COMPAT_ENGINES)
class PHYSICS_PT_game_physics(PhysicsButtonsPanel):
bl_label = "Physics"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -163,11 +164,12 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel):
class PHYSICS_PT_game_collision_bounds(PhysicsButtonsPanel):
bl_label = "Collision Bounds"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def poll(self, context):
game = context.object.game
rd = context.scene.render
- return (game.physics_type in ('DYNAMIC', 'RIGID_BODY', 'SENSOR', 'SOFT_BODY', 'STATIC')) and (rd.engine == 'BLENDER_GAME')
+ return (game.physics_type in ('DYNAMIC', 'RIGID_BODY', 'SENSOR', 'SOFT_BODY', 'STATIC')) and (rd.engine in self.COMPAT_ENGINES)
def draw_header(self, context):
game = context.active_object.game
@@ -203,11 +205,12 @@ class RenderButtonsPanel(bpy.types.Panel):
def poll(self, context):
rd = context.scene.render
- return (rd.engine == 'BLENDER_GAME')
+ return (rd.engine in self.COMPAT_ENGINES)
class RENDER_PT_game(RenderButtonsPanel):
bl_label = "Game"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -219,6 +222,7 @@ class RENDER_PT_game(RenderButtonsPanel):
class RENDER_PT_game_player(RenderButtonsPanel):
bl_label = "Standalone Player"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -256,6 +260,7 @@ class RENDER_PT_game_player(RenderButtonsPanel):
class RENDER_PT_game_stereo(RenderButtonsPanel):
bl_label = "Stereo"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -315,6 +320,7 @@ class RENDER_PT_game_stereo(RenderButtonsPanel):
class RENDER_PT_game_shading(RenderButtonsPanel):
bl_label = "Shading"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -343,6 +349,7 @@ class RENDER_PT_game_shading(RenderButtonsPanel):
class RENDER_PT_game_performance(RenderButtonsPanel):
bl_label = "Performance"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -368,6 +375,7 @@ class RENDER_PT_game_performance(RenderButtonsPanel):
class RENDER_PT_game_sound(RenderButtonsPanel):
bl_label = "Sound"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -390,12 +398,13 @@ class WorldButtonsPanel(bpy.types.Panel):
def poll(self, context):
scene = context.scene
- return (scene.render.engine == 'BLENDER_GAME') and (scene.world is not None)
+ return (scene.render.engine in self.COMPAT_ENGINES) and (scene.world is not None)
class WORLD_PT_game_context_world(WorldButtonsPanel):
bl_label = ""
bl_show_header = False
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def poll(self, context):
rd = context.scene.render
@@ -424,6 +433,7 @@ class WORLD_PT_game_context_world(WorldButtonsPanel):
class WORLD_PT_game_world(WorldButtonsPanel):
bl_label = "World"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -443,11 +453,12 @@ class WORLD_PT_game_world(WorldButtonsPanel):
class WORLD_PT_game_mist(WorldButtonsPanel):
bl_label = "Mist"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw_header(self, context):
world = context.world
- self.layout.prop(world.mist, "enabled", text="")
+ self.layout.prop(world.mist, "use_mist", text="")
def draw(self, context):
layout = self.layout
@@ -455,7 +466,7 @@ class WORLD_PT_game_mist(WorldButtonsPanel):
world = context.world
wide_ui = context.region.width > narrowui
- layout.active = world.mist.enabled
+ layout.active = world.mist.use_mist
split = layout.split()
col = split.column()
@@ -468,6 +479,7 @@ class WORLD_PT_game_mist(WorldButtonsPanel):
class WORLD_PT_game_physics(WorldButtonsPanel):
bl_label = "Physics"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/ui/properties_material.py b/release/scripts/ui/properties_material.py
index 13bfd7a7f5d..1526bd004a0 100644
--- a/release/scripts/ui/properties_material.py
+++ b/release/scripts/ui/properties_material.py
@@ -20,7 +20,7 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
def active_node_mat(mat):
@@ -39,7 +39,7 @@ def active_node_mat(mat):
class MATERIAL_MT_sss_presets(bpy.types.Menu):
bl_label = "SSS Presets"
preset_subdir = "sss"
- preset_operator = "script.python_file_run"
+ preset_operator = "script.execute_preset"
draw = bpy.types.Menu.draw_preset
@@ -505,8 +505,8 @@ class MATERIAL_PT_sss(MaterialButtonsPanel):
row = layout.row().split()
sub = row.row(align=True).split(percentage=0.75)
- sub.menu("MATERIAL_MT_sss_presets", text="Presets")
- sub.operator("material.sss_preset_add", text="Add")
+ sub.menu("MATERIAL_MT_sss_presets", text=bpy.types.MATERIAL_MT_sss_presets.bl_label)
+ sub.operator("material.sss_preset_add", text="", icon="ZOOMIN")
split = layout.split()
@@ -570,10 +570,11 @@ class MATERIAL_PT_mirror(MaterialButtonsPanel):
col = split.column()
col.separator()
- col.prop(raym, "distance", text="Max Dist")
col.prop(raym, "depth")
+ col.prop(raym, "distance", text="Max Dist")
col.separator()
sub = col.split(percentage=0.4)
+ sub.active = raym.distance > 0.0
sub.label(text="Fade To:")
sub.prop(raym, "fade_to", text="")
@@ -913,6 +914,32 @@ class MATERIAL_PT_volume_integration(VolumeButtonsPanel):
col.prop(vol, "depth_cutoff")
+class MATERIAL_PT_volume_options(VolumeButtonsPanel):
+ bl_label = "Options"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ bl_default_closed = True
+
+ def draw(self, context):
+ layout = self.layout
+
+ mat = active_node_mat(context.material)
+ wide_ui = context.region.width > narrowui
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(mat, "traceable")
+ col.prop(mat, "full_oversampling")
+ col.prop(mat, "exclude_mist")
+
+ col = split.column()
+ col.label(text="Light Group:")
+ col.prop(mat, "light_group", text="")
+ row = col.row()
+ row.active = bool(mat.light_group)
+ row.prop(mat, "light_group_exclusive", text="Exclusive")
+
+
classes = [
MATERIAL_PT_context_material,
MATERIAL_PT_preview,
@@ -937,8 +964,8 @@ classes = [
MATERIAL_PT_volume_shading,
MATERIAL_PT_volume_lighting,
MATERIAL_PT_volume_transp,
-
MATERIAL_PT_volume_integration,
+ MATERIAL_PT_volume_options,
MATERIAL_PT_custom_props]
diff --git a/release/scripts/ui/properties_object.py b/release/scripts/ui/properties_object.py
index b11180411f4..4e60879d665 100644
--- a/release/scripts/ui/properties_object.py
+++ b/release/scripts/ui/properties_object.py
@@ -20,7 +20,7 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class ObjectButtonsPanel(bpy.types.Panel):
@@ -35,12 +35,15 @@ class OBJECT_PT_context_object(ObjectButtonsPanel):
def draw(self, context):
layout = self.layout
-
+ space = context.space_data
ob = context.object
row = layout.row()
row.label(text="", icon='OBJECT_DATA')
- row.prop(ob, "name", text="")
+ if space.use_pin_id:
+ row.template_ID(space, "pin_id")
+ else:
+ row.prop(ob, "name", text="")
class OBJECT_PT_custom_props(ObjectButtonsPanel, PropertyPanel):
@@ -152,13 +155,11 @@ class OBJECT_PT_groups(ObjectButtonsPanel):
ob = context.object
wide_ui = context.region.width > narrowui
- if wide_ui:
- split = layout.split()
- split.operator_menu_enum("object.group_add", "group")
- split.label()
- else:
- layout.operator_menu_enum("object.group_add", "group")
+ row = layout.row(align=True)
+ row.operator("object.group_link", text="Add to Group")
+ row.operator("object.group_add", text="", icon='ZOOMIN')
+ # XXX, this is bad practice, yes, I wrote it :( - campbell
index = 0
value = str(tuple(context.scene.cursor_location))
for group in bpy.data.groups:
@@ -169,7 +170,7 @@ class OBJECT_PT_groups(ObjectButtonsPanel):
row = col.box().row()
row.prop(group, "name", text="")
- row.operator("object.group_remove", text="", icon='X')
+ row.operator("object.group_remove", text="", icon='X', emboss=False)
split = col.box().split()
@@ -181,7 +182,7 @@ class OBJECT_PT_groups(ObjectButtonsPanel):
col.prop(group, "dupli_offset", text="")
prop = col.operator("wm.context_set_value", text="From Cursor")
- prop.path = "object.group_users[%d].dupli_offset" % index
+ prop.data_path = "object.users_group[%d].dupli_offset" % index
prop.value = value
index += 1
@@ -213,6 +214,7 @@ class OBJECT_PT_display(ObjectButtonsPanel):
col.prop(ob, "draw_name", text="Name")
col.prop(ob, "draw_axis", text="Axis")
col.prop(ob, "draw_wire", text="Wire")
+ col.prop(ob, "color", text="Object Color")
if wide_ui:
col = split.column()
@@ -268,9 +270,12 @@ class OBJECT_PT_duplication(ObjectButtonsPanel):
else:
layout.prop(ob, "dupli_group", text="")
+# XXX: the following options are all quite buggy, ancient hacks that should be dropped
+
class OBJECT_PT_animation(ObjectButtonsPanel):
- bl_label = "Animation"
+ bl_label = "Animation Hacks"
+ bl_default_closed = True
def draw(self, context):
layout = self.layout
@@ -294,17 +299,15 @@ class OBJECT_PT_animation(ObjectButtonsPanel):
row.active = (ob.parent is not None)
col.prop(ob, "time_offset", text="Offset")
+ # XXX: these are still used for a few curve-related tracking features
if wide_ui:
col = split.column()
- col.label(text="Track:")
- col.prop(ob, "track", text="")
+ col.label(text="Tracking Axes:")
col.prop(ob, "track_axis", text="Axis")
col.prop(ob, "up_axis", text="Up Axis")
- row = col.row()
- row.prop(ob, "track_override_parent", text="Override Parent")
- row.active = (ob.parent is not None)
-# import generic panels from other files
+
+# import generic panels from other files
from properties_animviz import OBJECT_PT_motion_paths, OBJECT_PT_onion_skinning
classes = [
@@ -315,8 +318,8 @@ classes = [
OBJECT_PT_groups,
OBJECT_PT_display,
OBJECT_PT_duplication,
- OBJECT_PT_animation,
-
+ OBJECT_PT_animation, # XXX: panel of old hacks pending to be removed...
+
OBJECT_PT_motion_paths,
#OBJECT_PT_onion_skinning,
diff --git a/release/scripts/ui/properties_object_constraint.py b/release/scripts/ui/properties_object_constraint.py
index 6f6fcfc1641..335bd25b501 100644
--- a/release/scripts/ui/properties_object_constraint.py
+++ b/release/scripts/ui/properties_object_constraint.py
@@ -19,7 +19,8 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
+narrowcon = 260
class ConstraintButtonsPanel(bpy.types.Panel):
@@ -30,14 +31,15 @@ class ConstraintButtonsPanel(bpy.types.Panel):
def draw_constraint(self, context, con):
layout = self.layout
- box = layout.template_constraint(con)
wide_ui = context.region.width > narrowui
+ compact_con = context.region.width < narrowcon
+ box = layout.template_constraint(con, compact=compact_con)
if box:
# match enum type to our functions, avoids a lookup table.
getattr(self, con.type)(context, box, con, wide_ui)
- if con.type not in ('RIGID_BODY_JOINT', 'SPLINE_IK', 'NULL'):
+ if con.type not in ('RIGID_BODY_JOINT', 'NULL'):
box.prop(con, "influence")
def space_template(self, layout, con, wide_ui, target=True, owner=True):
@@ -76,7 +78,7 @@ class ConstraintButtonsPanel(bpy.types.Panel):
else:
layout.prop_object(con, "subtarget", con.target.data, "bones", text="")
- if con.type in ('COPY_LOCATION', 'STRETCH_TO', 'TRACK_TO'):
+ if con.type in ('COPY_LOCATION', 'STRETCH_TO', 'TRACK_TO', 'PIVOT'):
row = layout.row()
row.label(text="Head/Tail:")
row.prop(con, "head_tail", text="")
@@ -97,12 +99,12 @@ class ConstraintButtonsPanel(bpy.types.Panel):
split = layout.split(percentage=0.33)
col = split.column()
- col.prop(con, "tail")
- col.prop(con, "stretch")
+ col.prop(con, "use_tail")
+ col.prop(con, "use_stretch")
col = split.column()
col.prop(con, "chain_length")
- col.prop(con, "targetless")
+ col.prop(con, "use_target")
def CHILD_OF(self, context, layout, con, wide_ui):
self.target_template(layout, con, wide_ui)
@@ -205,10 +207,10 @@ class ConstraintButtonsPanel(bpy.types.Panel):
row.label(text="Axis Ref:")
row.prop(con, "axis_reference", expand=True)
split = layout.split(percentage=0.33)
- split.row().prop(con, "position")
+ split.row().prop(con, "use_position")
row = split.row()
row.prop(con, "weight", text="Weight", slider=True)
- row.active = con.position
+ row.active = con.use_position
split = layout.split(percentage=0.33)
row = split.row()
row.label(text="Lock:")
@@ -219,7 +221,7 @@ class ConstraintButtonsPanel(bpy.types.Panel):
split.active = con.use_position
split = layout.split(percentage=0.33)
- split.row().prop(con, "rotation")
+ split.row().prop(con, "use_rotation")
row = split.row()
row.prop(con, "orient_weight", text="Weight", slider=True)
row.active = con.use_rotation
@@ -461,6 +463,17 @@ class ConstraintButtonsPanel(bpy.types.Panel):
self.space_template(layout, con, wide_ui)
+ def MAINTAIN_VOLUME(self, context, layout, con, wide_ui):
+
+ row = layout.row()
+ if wide_ui:
+ row.label(text="Free:")
+ row.prop(con, "axis", expand=True)
+
+ layout.prop(con, "volume")
+
+ self.space_template(layout, con, wide_ui)
+
def COPY_TRANSFORMS(self, context, layout, con, wide_ui):
self.target_template(layout, con, wide_ui)
@@ -485,8 +498,8 @@ class ConstraintButtonsPanel(bpy.types.Panel):
col = split.column(align=True)
col.label(text="Action Length:")
- col.prop(con, "start_frame", text="Start")
- col.prop(con, "end_frame", text="End")
+ col.prop(con, "frame_start", text="Start")
+ col.prop(con, "frame_end", text="End")
if wide_ui:
col = split.column(align=True)
@@ -719,6 +732,23 @@ class ConstraintButtonsPanel(bpy.types.Panel):
col.prop(con, "xz_scaling_mode", text="")
col.prop(con, "use_curve_radius")
+ def PIVOT(self, context, layout, con, wide_ui):
+ self.target_template(layout, con, wide_ui)
+
+ if con.target:
+ col = layout.column()
+ col.prop(con, "offset", text="Pivot Offset")
+ else:
+ col = layout.column()
+ col.prop(con, "use_relative_position")
+ if con.use_relative_position:
+ col.prop(con, "offset", text="Relative Pivot Point")
+ else:
+ col.prop(con, "offset", text="Absolute Pivot Point")
+
+ col = layout.column()
+ col.prop(con, "enabled_rotation_range", text="Pivot When")
+
class OBJECT_PT_constraints(ConstraintButtonsPanel):
bl_label = "Object Constraints"
diff --git a/release/scripts/ui/properties_particle.py b/release/scripts/ui/properties_particle.py
index dbd2b90fea2..58e602dd1e2 100644
--- a/release/scripts/ui/properties_particle.py
+++ b/release/scripts/ui/properties_particle.py
@@ -25,18 +25,21 @@ from properties_physics_common import effector_weights_ui
from properties_physics_common import basic_force_field_settings_ui
from properties_physics_common import basic_force_field_falloff_ui
+narrowui = bpy.context.user_preferences.view.properties_width_check
+
def particle_panel_enabled(context, psys):
return (psys.point_cache.baked is False) and (not psys.edited) and (not context.particle_system_editable)
-def particle_panel_poll(context):
+def particle_panel_poll(panel, context):
psys = context.particle_system
+ engine = context.scene.render.engine
if psys is None:
return False
if psys.settings is None:
return False
- return psys.settings.type in ('EMITTER', 'REACTOR', 'HAIR')
+ return psys.settings.type in ('EMITTER', 'REACTOR', 'HAIR') and (engine in panel.COMPAT_ENGINES)
class ParticleButtonsPanel(bpy.types.Panel):
@@ -45,15 +48,17 @@ class ParticleButtonsPanel(bpy.types.Panel):
bl_context = "particle"
def poll(self, context):
- return particle_panel_poll(context)
+ return particle_panel_poll(self, context)
class PARTICLE_PT_context_particles(ParticleButtonsPanel):
bl_label = ""
bl_show_header = False
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def poll(self, context):
- return (context.particle_system or context.object)
+ engine = context.scene.render.engine
+ return (context.particle_system or context.object) and (engine in self.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -132,14 +137,16 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel):
class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel):
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
_context_path = "particle_system.settings"
class PARTICLE_PT_emission(ParticleButtonsPanel):
bl_label = "Emission"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def poll(self, context):
- if particle_panel_poll(context):
+ if particle_panel_poll(self, context):
return not context.particle_system.point_cache.external
else:
return False
@@ -149,6 +156,7 @@ class PARTICLE_PT_emission(ParticleButtonsPanel):
psys = context.particle_system
part = psys.settings
+ wide_ui = context.region.width > narrowui
layout.enabled = particle_panel_enabled(context, psys) and not psys.multiple_caches
@@ -160,8 +168,8 @@ class PARTICLE_PT_emission(ParticleButtonsPanel):
split = layout.split()
col = split.column(align=True)
- col.prop(part, "start")
- col.prop(part, "end")
+ col.prop(part, "frame_start")
+ col.prop(part, "frame_end")
col = split.column(align=True)
col.prop(part, "lifetime")
@@ -170,7 +178,10 @@ class PARTICLE_PT_emission(ParticleButtonsPanel):
layout.row().label(text="Emit From:")
row = layout.row()
- row.prop(part, "emit_from", expand=True)
+ if wide_ui:
+ row.prop(part, "emit_from", expand=True)
+ else:
+ row.prop(part, "emit_from", text="")
row = layout.row()
row.prop(part, "trand")
if part.distribution != 'GRID':
@@ -178,7 +189,10 @@ class PARTICLE_PT_emission(ParticleButtonsPanel):
if part.emit_from == 'FACE' or part.emit_from == 'VOLUME':
row = layout.row()
- row.prop(part, "distribution", expand=True)
+ if wide_ui:
+ row.prop(part, "distribution", expand=True)
+ else:
+ row.prop(part, "distribution", text="")
row = layout.row()
@@ -192,14 +206,16 @@ class PARTICLE_PT_emission(ParticleButtonsPanel):
class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel):
bl_label = "Hair dynamics"
bl_default_closed = True
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def poll(self, context):
psys = context.particle_system
+ engine = context.scene.render.engine
if psys is None:
return False
if psys.settings is None:
return False
- return psys.settings.type == 'HAIR'
+ return psys.settings.type == 'HAIR' and (engine in self.COMPAT_ENGINES)
def draw_header(self, context):
#cloth = context.cloth.collision_settings
@@ -247,9 +263,11 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel):
class PARTICLE_PT_cache(ParticleButtonsPanel):
bl_label = "Cache"
bl_default_closed = True
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def poll(self, context):
psys = context.particle_system
+ engine = context.scene.render.engine
if psys is None:
return False
if psys.settings is None:
@@ -257,20 +275,20 @@ class PARTICLE_PT_cache(ParticleButtonsPanel):
phystype = psys.settings.physics_type
if phystype == 'NO' or phystype == 'KEYED':
return False
- return psys.settings.type in ('EMITTER', 'REACTOR') or (psys.settings.type == 'HAIR' and psys.hair_dynamics)
+ return (psys.settings.type in ('EMITTER', 'REACTOR') or (psys.settings.type == 'HAIR' and psys.hair_dynamics)) and engine in self.COMPAT_ENGINES
def draw(self, context):
-
psys = context.particle_system
- point_cache_ui(self, context, psys.point_cache, particle_panel_enabled(context, psys), not psys.hair_dynamics, 0)
+ point_cache_ui(self, context, psys.point_cache, True, 'HAIR' if psys.hair_dynamics else 'PSYS')
class PARTICLE_PT_velocity(ParticleButtonsPanel):
bl_label = "Velocity"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def poll(self, context):
- if particle_panel_poll(context):
+ if particle_panel_poll(self, context):
psys = context.particle_system
return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.external
else:
@@ -314,9 +332,10 @@ class PARTICLE_PT_velocity(ParticleButtonsPanel):
class PARTICLE_PT_rotation(ParticleButtonsPanel):
bl_label = "Rotation"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def poll(self, context):
- if particle_panel_poll(context):
+ if particle_panel_poll(self, context):
psys = context.particle_system
return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.external
else:
@@ -327,6 +346,7 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel):
psys = context.particle_system
part = psys.settings
+ wide_ui = context.region.width > narrowui
layout.enabled = particle_panel_enabled(context, psys)
@@ -344,7 +364,10 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel):
sub.prop(part, "random_phase_factor", text="Random", slider=True)
layout.row().label(text="Angular Velocity:")
- layout.row().prop(part, "angular_velocity_mode", expand=True)
+ if wide_ui:
+ layout.row().prop(part, "angular_velocity_mode", expand=True)
+ else:
+ layout.row().prop(part, "angular_velocity_mode", text="")
split = layout.split()
sub = split.column()
@@ -355,9 +378,10 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel):
class PARTICLE_PT_physics(ParticleButtonsPanel):
bl_label = "Physics"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def poll(self, context):
- if particle_panel_poll(context):
+ if particle_panel_poll(self, context):
return not context.particle_system.point_cache.external
else:
return False
@@ -367,11 +391,16 @@ class PARTICLE_PT_physics(ParticleButtonsPanel):
psys = context.particle_system
part = psys.settings
+ wide_ui = context.region.width > narrowui
layout.enabled = particle_panel_enabled(context, psys)
row = layout.row()
- row.prop(part, "physics_type", expand=True)
+ if wide_ui:
+ row.prop(part, "physics_type", expand=True)
+ else:
+ row.prop(part, "physics_type", text="")
+
if part.physics_type != 'NO':
row = layout.row()
col = row.column(align=True)
@@ -390,10 +419,53 @@ class PARTICLE_PT_physics(ParticleButtonsPanel):
sub.prop(part, "drag_factor", slider=True)
sub.prop(part, "damp_factor", slider=True)
sub = split.column()
+ sub.label(text="Integration:")
+ sub.prop(part, "integrator", text="")
+ sub.prop(part, "time_tweak")
+ sub.prop(part, "subframes")
+ sub = layout.row()
sub.prop(part, "size_deflect")
sub.prop(part, "die_on_collision")
- sub.prop(part, "integrator")
+
+ elif part.physics_type == 'FLUID':
+ fluid = part.fluid
+ split = layout.split()
+ sub = split.column()
+
+ sub.label(text="Forces:")
+ sub.prop(part, "brownian_factor")
+ sub.prop(part, "drag_factor", slider=True)
+ sub.prop(part, "damp_factor", slider=True)
+ sub = split.column()
+ sub.label(text="Integration:")
+ sub.prop(part, "integrator", text="")
sub.prop(part, "time_tweak")
+ sub.prop(part, "subframes")
+ sub = layout.row()
+ sub.prop(part, "size_deflect")
+ sub.prop(part, "die_on_collision")
+
+ split = layout.split()
+ sub = split.column()
+ sub.label(text="Fluid Interaction:")
+ sub.prop(fluid, "fluid_radius", slider=True)
+ sub.prop(fluid, "stiffness_k")
+ sub.prop(fluid, "stiffness_knear")
+ sub.prop(fluid, "rest_density")
+
+ sub.label(text="Viscosity:")
+ sub.prop(fluid, "viscosity_omega", text="Linear")
+ sub.prop(fluid, "viscosity_beta", text="Square")
+
+ sub = split.column()
+
+ sub.label(text="Springs:")
+ sub.prop(fluid, "spring_k", text="Force", slider=True)
+ sub.prop(fluid, "rest_length", slider=True)
+ layout.label(text="Multiple fluids interactions:")
+
+ sub.label(text="Buoyancy:")
+ sub.prop(fluid, "buoyancy", slider=True)
elif part.physics_type == 'KEYED':
split = layout.split()
@@ -454,7 +526,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel):
col.prop(boids, "banking", slider=True)
col.prop(boids, "height", slider=True)
- if part.physics_type == 'KEYED' or part.physics_type == 'BOIDS':
+ if part.physics_type == 'KEYED' or part.physics_type == 'BOIDS' or part.physics_type == 'FLUID':
if part.physics_type == 'BOIDS':
layout.label(text="Relations:")
@@ -484,7 +556,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel):
col.active = psys.keyed_timing
col.prop(key, "time")
col.prop(key, "duration")
- else:
+ elif part.physics_type == 'BOIDS':
sub = row.row()
#doesn't work yet
#sub.red_alert = key.valid
@@ -492,20 +564,28 @@ class PARTICLE_PT_physics(ParticleButtonsPanel):
sub.prop(key, "system", text="System")
layout.prop(key, "mode", expand=True)
+ elif part.physics_type == 'FLUID':
+ sub = row.row()
+ #doesn't work yet
+ #sub.red_alert = key.valid
+ sub.prop(key, "object", text="")
+ sub.prop(key, "system", text="System")
class PARTICLE_PT_boidbrain(ParticleButtonsPanel):
bl_label = "Boid Brain"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def poll(self, context):
psys = context.particle_system
+ engine = context.scene.render.engine
if psys is None:
return False
if psys.settings is None:
return False
if psys.point_cache.external:
return False
- return psys.settings.physics_type == 'BOIDS'
+ return psys.settings.physics_type == 'BOIDS' and engine in self.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
@@ -594,20 +674,23 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel):
class PARTICLE_PT_render(ParticleButtonsPanel):
bl_label = "Render"
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def poll(self, context):
psys = context.particle_system
+ engine = context.scene.render.engine
if psys is None:
return False
if psys.settings is None:
return False
- return True
+ return engine in self.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = psys.settings
+ wide_ui = context.region.width > narrowui
row = layout.row()
row.prop(part, "material")
@@ -623,7 +706,10 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
sub.prop(part, "died")
row = layout.row()
- row.prop(part, "ren_as", expand=True)
+ if wide_ui:
+ row.prop(part, "ren_as", expand=True)
+ else:
+ row.prop(part, "ren_as", text="")
split = layout.split()
@@ -635,12 +721,6 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
sub = split.column()
sub.prop(part, "velocity_length")
elif part.ren_as == 'PATH':
-
- if part.type != 'HAIR' and part.physics_type != 'KEYED' and (psys.point_cache.baked is False):
- box = layout.box()
- box.label(text="Baked or keyed particles needed for correct rendering.")
- return
-
sub.prop(part, "render_strand")
subsub = sub.column()
subsub.active = (part.render_strand is False)
@@ -716,7 +796,10 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
sub.label(text="Align:")
row = layout.row()
- row.prop(part, "billboard_align", expand=True)
+ if wide_ui:
+ row.prop(part, "billboard_align", expand=True)
+ else:
+ row.prop(part, "billboard_align", text="")
row.prop(part, "billboard_lock", text="Lock")
row = layout.row()
row.prop(part, "billboard_object")
@@ -741,9 +824,9 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
row.prop(psys, "billboard_split_uv")
row = layout.row()
row.label(text="Animate:")
- row.prop(part, "billboard_animation", expand=True)
+ row.prop(part, "billboard_animation", text="")
row.label(text="Offset:")
- row.prop(part, "billboard_split_offset", expand=True)
+ row.prop(part, "billboard_split_offset", text="")
if part.ren_as == 'HALO' or part.ren_as == 'LINE' or part.ren_as == 'BILLBOARD':
row = layout.row()
@@ -762,34 +845,35 @@ class PARTICLE_PT_render(ParticleButtonsPanel):
class PARTICLE_PT_draw(ParticleButtonsPanel):
bl_label = "Display"
bl_default_closed = True
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def poll(self, context):
psys = context.particle_system
+ engine = context.scene.render.engine
if psys is None:
return False
if psys.settings is None:
return False
- return True
+ return engine in self.COMPAT_ENGINES
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = psys.settings
+ wide_ui = context.region.width > narrowui
row = layout.row()
- row.prop(part, "draw_as", expand=True)
+ if wide_ui:
+ row.prop(part, "draw_as", expand=True)
+ else:
+ row.prop(part, "draw_as", text="")
if part.draw_as == 'NONE' or (part.ren_as == 'NONE' and part.draw_as == 'RENDER'):
return
path = (part.ren_as == 'PATH' and part.draw_as == 'RENDER') or part.draw_as == 'PATH'
- if path and part.type != 'HAIR' and part.physics_type != 'KEYED' and psys.point_cache.baked is False:
- box = layout.box()
- box.label(text="Baked or keyed particles needed for correct drawing.")
- return
-
row = layout.row()
row.prop(part, "display", slider=True)
if part.draw_as != 'RENDER' or part.ren_as == 'HALO':
@@ -820,14 +904,19 @@ class PARTICLE_PT_draw(ParticleButtonsPanel):
class PARTICLE_PT_children(ParticleButtonsPanel):
bl_label = "Children"
bl_default_closed = True
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
psys = context.particle_system
part = psys.settings
+ wide_ui = context.region.width > narrowui
- layout.row().prop(part, "child_type", expand=True)
+ if wide_ui:
+ layout.row().prop(part, "child_type", expand=True)
+ else:
+ layout.row().prop(part, "child_type", text="")
if part.child_type == 'NONE':
return
@@ -883,7 +972,10 @@ class PARTICLE_PT_children(ParticleButtonsPanel):
col.label(text="hair parting controls")
layout.row().label(text="Kink:")
- layout.row().prop(part, "kink", expand=True)
+ if wide_ui:
+ layout.row().prop(part, "kink", expand=True)
+ else:
+ layout.row().prop(part, "kink", text="")
split = layout.split()
@@ -897,6 +989,7 @@ class PARTICLE_PT_children(ParticleButtonsPanel):
class PARTICLE_PT_field_weights(ParticleButtonsPanel):
bl_label = "Field Weights"
bl_default_closed = True
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
part = context.particle_system.settings
@@ -909,6 +1002,7 @@ class PARTICLE_PT_field_weights(ParticleButtonsPanel):
class PARTICLE_PT_force_fields(ParticleButtonsPanel):
bl_label = "Force Field Settings"
bl_default_closed = True
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
@@ -936,6 +1030,7 @@ class PARTICLE_PT_force_fields(ParticleButtonsPanel):
class PARTICLE_PT_vertexgroups(ParticleButtonsPanel):
bl_label = "Vertexgroups"
bl_default_closed = True
+ COMPAT_ENGINES = {'BLENDER_RENDER'}
def draw(self, context):
layout = self.layout
diff --git a/release/scripts/ui/properties_physics_cloth.py b/release/scripts/ui/properties_physics_cloth.py
index 7a65420e172..61e1fe81812 100644
--- a/release/scripts/ui/properties_physics_cloth.py
+++ b/release/scripts/ui/properties_physics_cloth.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
from properties_physics_common import point_cache_ui
@@ -36,7 +36,7 @@ class CLOTH_MT_presets(bpy.types.Menu):
'''
bl_label = "Cloth Presets"
preset_subdir = "cloth"
- preset_operator = "script.python_file_run"
+ preset_operator = "script.execute_preset"
draw = bpy.types.Menu.draw_preset
@@ -62,7 +62,6 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel):
wide_ui = context.region.width > narrowui
split = layout.split()
- split.operator_context = 'EXEC_DEFAULT'
if md:
# remove modifier + settings
@@ -76,9 +75,7 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel):
# add modifier
split.operator("object.modifier_add", text="Add").type = 'CLOTH'
if wide_ui:
- split.column()
-
- split.operator_context = 'INVOKE_DEFAULT'
+ split.label()
if md:
cloth = md.settings
@@ -90,9 +87,9 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel):
col = split.column()
col.label(text="Presets:")
- sub = col.row(align=True).split(percentage=0.75)
- sub.menu("CLOTH_MT_presets", text="Presets")
- sub.operator("cloth.preset_add", text="Add")
+ sub = col.row(align=True)
+ sub.menu("CLOTH_MT_presets", text=bpy.types.CLOTH_MT_presets.bl_label)
+ sub.operator("cloth.preset_add", text="", icon="ZOOMIN")
col.label(text="Quality:")
col.prop(cloth, "quality", text="Steps", slider=True)
@@ -129,6 +126,12 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel):
col.prop(cloth, "goal_friction", text="Friction")
"""
+ key = ob.data.shape_keys
+
+ if key:
+ col.label(text="Rest Shape Key:")
+ col.prop_object(cloth, "rest_shape_key", key, "keys", text="")
+
class PHYSICS_PT_cloth_cache(PhysicButtonsPanel):
bl_label = "Cloth Cache"
@@ -139,7 +142,7 @@ class PHYSICS_PT_cloth_cache(PhysicButtonsPanel):
def draw(self, context):
md = context.cloth
- point_cache_ui(self, context, md.point_cache, cloth_panel_enabled(md), 0, 0)
+ point_cache_ui(self, context, md.point_cache, cloth_panel_enabled(md), 'CLOTH')
class PHYSICS_PT_cloth_collision(PhysicButtonsPanel):
@@ -179,6 +182,8 @@ class PHYSICS_PT_cloth_collision(PhysicButtonsPanel):
sub.prop(cloth, "self_collision_quality", slider=True, text="Quality")
sub.prop(cloth, "self_min_distance", slider=True, text="Distance")
+ layout.prop(cloth, "group")
+
class PHYSICS_PT_cloth_stiffness(PhysicButtonsPanel):
bl_label = "Cloth Stiffness Scaling"
diff --git a/release/scripts/ui/properties_physics_common.py b/release/scripts/ui/properties_physics_common.py
index b81fa25b1a1..be8972e4fe6 100644
--- a/release/scripts/ui/properties_physics_common.py
+++ b/release/scripts/ui/properties_physics_common.py
@@ -18,14 +18,18 @@
# <pep8 compliant>
-narrowui = 180
+import bpy
+narrowui = bpy.context.user_preferences.view.properties_width_check
-def point_cache_ui(self, context, cache, enabled, particles, smoke):
+#cachetype can be 'PSYS' 'HAIR' 'SMOKE' etc
+
+
+def point_cache_ui(self, context, cache, enabled, cachetype):
layout = self.layout
wide_ui = context.region.width > narrowui
- layout.set_context_pointer("PointCache", cache)
+ layout.set_context_pointer("point_cache", cache)
row = layout.row()
row.template_list(cache, "point_cache_list", cache, "active_point_cache_index", rows=2)
@@ -34,60 +38,75 @@ def point_cache_ui(self, context, cache, enabled, particles, smoke):
col.operator("ptcache.remove", icon='ZOOMOUT', text="")
row = layout.row()
- row.label(text="File Name:")
- if particles:
+ if cachetype in ('PSYS', 'HAIR', 'SMOKE'):
row.prop(cache, "external")
if cache.external:
split = layout.split(percentage=0.80)
- split.prop(cache, "name", text="")
+ split.prop(cache, "name", text="File Name")
split.prop(cache, "index", text="")
- layout.label(text="File Path:")
+ row = layout.row()
+ row.label(text="File Path:")
+ row.prop(cache, "use_library_path", "Use Lib Path")
+
layout.prop(cache, "filepath", text="")
layout.label(text=cache.info)
else:
- layout.prop(cache, "name", text="")
+ layout.prop(cache, "name", text="File Name")
- if not particles:
- row = layout.row()
- row.enabled = enabled
- row.prop(cache, "start_frame")
- row.prop(cache, "end_frame")
+ split = layout.split()
+ col = split.column(align=True)
- row = layout.row()
+ if cachetype != 'PSYS':
+ col.enabled = enabled
+ col.prop(cache, "frame_start")
+ col.prop(cache, "frame_end")
+ if cachetype != 'SMOKE':
+ col.prop(cache, "step")
- if cache.baked == True:
- row.operator("ptcache.free_bake", text="Free Bake")
- else:
- row.operator("ptcache.bake", text="Bake").bake = True
+ if wide_ui:
+ col = split.column()
- sub = row.row()
- sub.enabled = (cache.frames_skipped or cache.outdated) and enabled
- sub.operator("ptcache.bake", "bake", False, text="Calculate to Current Frame")
-
- row = layout.row()
- row.enabled = enabled
- row.operator("ptcache.bake_from_cache", text="Current Cache to Bake")
- if not smoke:
- row.prop(cache, "step")
-
- if not smoke:
- row = layout.row()
- sub = row.row()
+ if cachetype != 'SMOKE':
+ sub = col.column()
sub.enabled = enabled
sub.prop(cache, "quick_cache")
- row.prop(cache, "disk_cache")
- layout.label(text=cache.info)
+ sub = col.column()
+ sub.enabled = bpy.data.file_is_saved
+ sub.prop(cache, "disk_cache")
+ col.label(text=cache.info)
+
+ sub = col.column()
+ sub.prop(cache, "use_library_path", "Use Lib Path")
layout.separator()
- row = layout.row()
- row.operator("ptcache.bake_all", text="Bake All Dynamics").bake = True
- row.operator("ptcache.free_bake_all", text="Free All Bakes")
- layout.operator("ptcache.bake_all", "bake", False, text="Update All Dynamics to current frame")
+ split = layout.split()
+
+ col = split.column()
+
+ if cache.baked == True:
+ col.operator("ptcache.free_bake", text="Free Bake")
+ else:
+ col.operator("ptcache.bake", text="Bake").bake = True
+
+ sub = col.row()
+ sub.enabled = (cache.frames_skipped or cache.outdated) and enabled
+ sub.operator("ptcache.bake", text="Calculate To Frame").bake = False
+
+ sub = col.column()
+ sub.enabled = enabled
+ sub.operator("ptcache.bake_from_cache", text="Current Cache to Bake")
+
+
+ if wide_ui:
+ col = split.column()
+ col.operator("ptcache.bake_all", text="Bake All Dynamics").bake = True
+ col.operator("ptcache.free_bake_all", text="Free All Bakes")
+ col.operator("ptcache.bake_all", text="Update All To Frame").bake = False
def effector_weights_ui(self, context, weights):
diff --git a/release/scripts/ui/properties_physics_field.py b/release/scripts/ui/properties_physics_field.py
index e0be01d4c1c..57fa40e4c5d 100644
--- a/release/scripts/ui/properties_physics_field.py
+++ b/release/scripts/ui/properties_physics_field.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
from properties_physics_common import basic_force_field_settings_ui
@@ -72,6 +72,7 @@ class PHYSICS_PT_field(PhysicButtonsPanel):
col.prop(field, "guide_free")
col.prop(field, "falloff_power")
col.prop(field, "guide_path_add")
+ col.prop(field, "use_guide_path_weight")
if wide_ui:
col = split.column()
@@ -184,7 +185,6 @@ class PHYSICS_PT_collision(PhysicButtonsPanel):
wide_ui = context.region.width > narrowui
split = layout.split()
- split.operator_context = 'EXEC_DEFAULT'
if md:
# remove modifier + settings
diff --git a/release/scripts/ui/properties_physics_fluid.py b/release/scripts/ui/properties_physics_fluid.py
index 9b36b98bc24..32acd88654d 100644
--- a/release/scripts/ui/properties_physics_fluid.py
+++ b/release/scripts/ui/properties_physics_fluid.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class PhysicButtonsPanel(bpy.types.Panel):
@@ -43,7 +43,6 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel):
wide_ui = context.region.width > narrowui
split = layout.split()
- split.operator_context = 'EXEC_DEFAULT'
if md:
# remove modifier + settings
@@ -67,9 +66,18 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel):
if fluid:
if wide_ui:
- layout.prop(fluid, "type")
+ row = layout.row()
+ row.prop(fluid, "type")
+ if fluid.type not in ('NONE', 'DOMAIN', 'PARTICLE'):
+ row.prop(fluid, "active", text="")
else:
layout.prop(fluid, "type", text="")
+ if fluid.type not in ('NONE', 'DOMAIN', 'PARTICLE'):
+ layout.prop(fluid, "active", text="")
+
+ layout = layout.column()
+ if fluid.type not in ('NONE', 'DOMAIN', 'PARTICLE'):
+ layout.active = fluid.active
if fluid.type == 'DOMAIN':
layout.operator("fluid.bake", text="Bake Fluid Simulation", icon='MOD_FLUIDSIM')
@@ -220,15 +228,29 @@ class PHYSICS_PT_domain_gravity(PhysicButtonsPanel):
layout = self.layout
fluid = context.fluid.settings
+ scene = context.scene
wide_ui = context.region.width > narrowui
split = layout.split()
col = split.column()
- col.label(text="Gravity:")
- col.prop(fluid, "gravity", text="")
- col.label(text="Real World Size:")
- col.prop(fluid, "real_world_size", text="Metres")
+ if scene.use_gravity:
+ col.label(text="Using Scene Gravity", icon="SCENE_DATA")
+ sub = col.column()
+ sub.enabled = False
+ sub.prop(fluid, "gravity", text="")
+ else:
+ col.label(text="Gravity:")
+ col.prop(fluid, "gravity", text="")
+
+ if scene.unit_settings.system != 'NONE':
+ col.label(text="Using Scene Size Units", icon="SCENE_DATA")
+ sub = col.column()
+ sub.enabled = False
+ sub.prop(fluid, "real_world_size", text="Metres")
+ else:
+ col.label(text="Real World Size:")
+ col.prop(fluid, "real_world_size", text="Metres")
if wide_ui:
col = split.column()
diff --git a/release/scripts/ui/properties_physics_smoke.py b/release/scripts/ui/properties_physics_smoke.py
index 1f91b761e1a..c5357c515de 100644
--- a/release/scripts/ui/properties_physics_smoke.py
+++ b/release/scripts/ui/properties_physics_smoke.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
from properties_physics_common import point_cache_ui
@@ -48,7 +48,6 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel):
wide_ui = context.region.width > narrowui
split = layout.split()
- split.operator_context = 'EXEC_DEFAULT'
if md:
# remove modifier + settings
@@ -71,8 +70,7 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel):
else:
layout.prop(md, "smoke_type", text="")
- if md.smoke_type == 'TYPE_DOMAIN':
-
+ if md.smoke_type == 'DOMAIN':
domain = md.domain_settings
split = layout.split()
@@ -94,8 +92,7 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel):
sub.prop(domain, "dissolve_speed", text="Time")
sub.prop(domain, "dissolve_smoke_log", text="Slow")
- elif md.smoke_type == 'TYPE_FLOW':
-
+ elif md.smoke_type == 'FLOW':
flow = md.flow_settings
split = layout.split()
@@ -115,7 +112,7 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel):
col.prop(flow, "temperature")
col.prop(flow, "density")
- #elif md.smoke_type == 'TYPE_COLL':
+ #elif md.smoke_type == 'COLLISION':
# layout.separator()
@@ -125,7 +122,7 @@ class PHYSICS_PT_smoke_groups(PhysicButtonsPanel):
def poll(self, context):
md = context.smoke
- return md and (md.smoke_type == 'TYPE_DOMAIN')
+ return md and (md.smoke_type == 'DOMAIN')
def draw(self, context):
layout = self.layout
@@ -154,20 +151,18 @@ class PHYSICS_PT_smoke_cache(PhysicButtonsPanel):
def poll(self, context):
md = context.smoke
- return md and (md.smoke_type == 'TYPE_DOMAIN')
+ return md and (md.smoke_type == 'DOMAIN')
def draw(self, context):
layout = self.layout
- domain = context.smoke.domain_settings
-
- layout.label(text="Compression:")
- layout.prop(domain, "smoke_cache_comp", expand=True)
-
md = context.smoke.domain_settings
cache = md.point_cache_low
- point_cache_ui(self, context, cache, (cache.baked is False), 0, 1)
+ layout.label(text="Compression:")
+ layout.prop(md, "smoke_cache_comp", expand=True)
+
+ point_cache_ui(self, context, cache, (cache.baked is False), 'SMOKE')
class PHYSICS_PT_smoke_highres(PhysicButtonsPanel):
@@ -176,12 +171,12 @@ class PHYSICS_PT_smoke_highres(PhysicButtonsPanel):
def poll(self, context):
md = context.smoke
- return md and (md.smoke_type == 'TYPE_DOMAIN')
+ return md and (md.smoke_type == 'DOMAIN')
def draw_header(self, context):
- high = context.smoke.domain_settings
+ md = context.smoke.domain_settings
- self.layout.prop(high, "highres", text="")
+ self.layout.prop(md, "highres", text="")
def draw(self, context):
layout = self.layout
@@ -189,6 +184,8 @@ class PHYSICS_PT_smoke_highres(PhysicButtonsPanel):
md = context.smoke.domain_settings
wide_ui = context.region.width > narrowui
+ layout.active = md.highres
+
split = layout.split()
col = split.column()
@@ -209,21 +206,18 @@ class PHYSICS_PT_smoke_cache_highres(PhysicButtonsPanel):
def poll(self, context):
md = context.smoke
- return md and (md.smoke_type == 'TYPE_DOMAIN') and md.domain_settings.highres
+ return md and (md.smoke_type == 'DOMAIN') and md.domain_settings.highres
def draw(self, context):
layout = self.layout
- domain = context.smoke.domain_settings
-
- layout.label(text="Compression:")
- layout.prop(domain, "smoke_cache_high_comp", expand=True)
-
-
md = context.smoke.domain_settings
cache = md.point_cache_high
- point_cache_ui(self, context, cache, (cache.baked is False), 0, 1)
+ layout.label(text="Compression:")
+ layout.prop(md, "smoke_cache_high_comp", expand=True)
+
+ point_cache_ui(self, context, cache, (cache.baked is False), 'SMOKE')
class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel):
@@ -232,7 +226,7 @@ class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel):
def poll(self, context):
smoke = context.smoke
- return (smoke and smoke.smoke_type == 'TYPE_DOMAIN')
+ return (smoke and smoke.smoke_type == 'DOMAIN')
def draw(self, context):
domain = context.smoke.domain_settings
diff --git a/release/scripts/ui/properties_physics_softbody.py b/release/scripts/ui/properties_physics_softbody.py
index 8a59e087dc3..60149cf533b 100644
--- a/release/scripts/ui/properties_physics_softbody.py
+++ b/release/scripts/ui/properties_physics_softbody.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
from properties_physics_common import point_cache_ui
@@ -38,7 +38,9 @@ class PhysicButtonsPanel(bpy.types.Panel):
def poll(self, context):
ob = context.object
rd = context.scene.render
- return (ob and ob.type == 'MESH') and (not rd.use_game_engine)
+# return (ob and ob.type == 'MESH') and (not rd.use_game_engine)
+# i really hate touching things i do not understand completely .. but i think this should read (bjornmose)
+ return (ob and (ob.type == 'MESH' or ob.type == 'LATTICE'or ob.type == 'CURVE')) and (not rd.use_game_engine)
class PHYSICS_PT_softbody(PhysicButtonsPanel):
@@ -52,7 +54,6 @@ class PHYSICS_PT_softbody(PhysicButtonsPanel):
wide_ui = context.region.width > narrowui
split = layout.split()
- split.operator_context = 'EXEC_DEFAULT'
if md:
# remove modifier + settings
@@ -96,7 +97,7 @@ class PHYSICS_PT_softbody_cache(PhysicButtonsPanel):
def draw(self, context):
md = context.soft_body
- point_cache_ui(self, context, md.point_cache, softbody_panel_enabled(md), 0, 0)
+ point_cache_ui(self, context, md.point_cache, softbody_panel_enabled(md), 'SOFTBODY')
class PHYSICS_PT_softbody_goal(PhysicButtonsPanel):
@@ -185,10 +186,13 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel):
sub.active = softbody.stiff_quads
sub.prop(softbody, "shear")
- col.prop(softbody, "new_aero", text="Aero")
- sub = col.column()
- sub.enabled = softbody.new_aero
- sub.prop(softbody, "aero", text="Factor")
+ col.label(text="Aerodynamics:")
+ col.row().prop(softbody, "aerodynamics_type", expand=True)
+ col.prop(softbody, "aero", text="Factor")
+
+ #sub = col.column()
+ #sub.enabled = softbody.aero > 0
+
col.label(text="Collision:")
col.prop(softbody, "edge_collision", text="Edge")
@@ -196,7 +200,7 @@ class PHYSICS_PT_softbody_edge(PhysicButtonsPanel):
class PHYSICS_PT_softbody_collision(PhysicButtonsPanel):
- bl_label = "Soft Body Collision"
+ bl_label = "Soft Body Self Collision"
bl_default_closed = True
def poll(self, context):
@@ -217,7 +221,7 @@ class PHYSICS_PT_softbody_collision(PhysicButtonsPanel):
layout.active = softbody.self_collision and softbody_panel_enabled(md)
- layout.label(text="Collision Type:")
+ layout.label(text="Collision Ball Size Calculation:")
if wide_ui:
layout.prop(softbody, "collision_type", expand=True)
else:
diff --git a/release/scripts/ui/properties_render.py b/release/scripts/ui/properties_render.py
index 8bf3318c3e2..829416b86d3 100644
--- a/release/scripts/ui/properties_render.py
+++ b/release/scripts/ui/properties_render.py
@@ -19,12 +19,19 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class RENDER_MT_presets(bpy.types.Menu):
bl_label = "Render Presets"
preset_subdir = "render"
+ preset_operator = "script.execute_preset"
+ draw = bpy.types.Menu.draw_preset
+
+
+class RENDER_MT_ffmpeg_presets(bpy.types.Menu):
+ bl_label = "FFMPEG Presets"
+ preset_subdir = "ffmpeg"
preset_operator = "script.python_file_run"
draw = bpy.types.Menu.draw_preset
@@ -53,11 +60,11 @@ class RENDER_PT_render(RenderButtonsPanel):
split = layout.split()
col = split.column()
- col.operator("screen.render", text="Image", icon='RENDER_STILL')
+ col.operator("render.render", text="Image", icon='RENDER_STILL')
if wide_ui:
col = split.column()
- col.operator("screen.render", text="Animation", icon='RENDER_ANIMATION').animation = True
+ col.operator("render.render", text="Animation", icon='RENDER_ANIMATION').animation = True
layout.prop(rd, "display_mode", text="Display")
@@ -89,13 +96,16 @@ class RENDER_PT_layers(RenderButtonsPanel):
split = layout.split()
col = split.column()
- col.prop(scene, "visible_layers", text="Scene")
+ col.prop(scene, "layers", text="Scene")
+ col.label(text="")
+ col.prop(rl, "light_override", text="Light")
+ col.prop(rl, "material_override", text="Material")
if wide_ui:
col = split.column()
col.prop(rl, "visible_layers", text="Layer")
+ col.label(text="Mask Layers:")
+ col.prop(rl, "zmask_layers", text="")
- layout.prop(rl, "light_override", text="Light")
- layout.prop(rl, "material_override", text="Material")
layout.separator()
layout.label(text="Include:")
@@ -119,11 +129,6 @@ class RENDER_PT_layers(RenderButtonsPanel):
col.prop(rl, "edge")
col.prop(rl, "strand")
- if rl.zmask:
- split = layout.split()
- split.label(text="Zmask Layers:")
- split.column().prop(rl, "zmask_layers", text="")
-
layout.separator()
split = layout.split()
@@ -145,28 +150,28 @@ class RENDER_PT_layers(RenderButtonsPanel):
col.prop(rl, "pass_diffuse")
row = col.row()
row.prop(rl, "pass_specular")
- row.prop(rl, "pass_specular_exclude", text="", icon='X')
+ row.prop(rl, "pass_specular_exclude", text="")
row = col.row()
row.prop(rl, "pass_shadow")
- row.prop(rl, "pass_shadow_exclude", text="", icon='X')
+ row.prop(rl, "pass_shadow_exclude", text="")
row = col.row()
row.prop(rl, "pass_emit")
- row.prop(rl, "pass_emit_exclude", text="", icon='X')
+ row.prop(rl, "pass_emit_exclude", text="")
row = col.row()
row.prop(rl, "pass_ao")
- row.prop(rl, "pass_ao_exclude", text="", icon='X')
+ row.prop(rl, "pass_ao_exclude", text="")
row = col.row()
row.prop(rl, "pass_environment")
- row.prop(rl, "pass_environment_exclude", text="", icon='X')
+ row.prop(rl, "pass_environment_exclude", text="")
row = col.row()
row.prop(rl, "pass_indirect")
- row.prop(rl, "pass_indirect_exclude", text="", icon='X')
+ row.prop(rl, "pass_indirect_exclude", text="")
row = col.row()
row.prop(rl, "pass_reflection")
- row.prop(rl, "pass_reflection_exclude", text="", icon='X')
+ row.prop(rl, "pass_reflection_exclude", text="")
row = col.row()
row.prop(rl, "pass_refraction")
- row.prop(rl, "pass_refraction_exclude", text="", icon='X')
+ row.prop(rl, "pass_refraction_exclude", text="")
class RENDER_PT_shading(RenderButtonsPanel):
@@ -182,14 +187,14 @@ class RENDER_PT_shading(RenderButtonsPanel):
split = layout.split()
col = split.column()
- col.prop(rd, "render_textures", text="Textures")
- col.prop(rd, "render_shadows", text="Shadows")
- col.prop(rd, "render_sss", text="Subsurface Scattering")
- col.prop(rd, "render_envmaps", text="Environment Map")
+ col.prop(rd, "use_textures", text="Textures")
+ col.prop(rd, "use_shadows", text="Shadows")
+ col.prop(rd, "use_sss", text="Subsurface Scattering")
+ col.prop(rd, "use_envmaps", text="Environment Map")
if wide_ui:
col = split.column()
- col.prop(rd, "render_raytracing", text="Ray Tracing")
+ col.prop(rd, "use_raytracing", text="Ray Tracing")
col.prop(rd, "color_management")
col.prop(rd, "alpha_mode", text="Alpha")
@@ -211,7 +216,7 @@ class RENDER_PT_performance(RenderButtonsPanel):
col.label(text="Threads:")
col.row().prop(rd, "threads_mode", expand=True)
sub = col.column()
- sub.enabled = rd.threads_mode == 'THREADS_FIXED'
+ sub.enabled = rd.threads_mode == 'FIXED'
sub.prop(rd, "threads")
sub = col.column(align=True)
sub.label(text="Tiles:")
@@ -228,7 +233,7 @@ class RENDER_PT_performance(RenderButtonsPanel):
sub.active = rd.use_compositing
sub.prop(rd, "free_image_textures")
sub = col.column()
- sub.active = rd.render_raytracing
+ sub.active = rd.use_raytracing
sub.label(text="Acceleration structure:")
sub.prop(rd, "raytrace_structure", text="")
if rd.raytrace_structure == 'OCTREE':
@@ -305,11 +310,20 @@ class RENDER_PT_output(RenderButtonsPanel):
col.prop(rd, "use_overwrite")
col.prop(rd, "use_placeholder")
- if rd.file_format in ('AVIJPEG', 'JPEG'):
+ if rd.file_format in ('AVI_JPEG', 'JPEG'):
split = layout.split()
- split.prop(rd, "quality", slider=True)
+ split.prop(rd, "file_quality", slider=True)
+
+ elif rd.file_format == 'MULTILAYER':
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Codec:")
+ col.prop(rd, "exr_codec", text="")
+ if wide_ui:
+ col = split.column()
- elif rd.file_format == 'OPENEXR':
+ elif rd.file_format == 'OPEN_EXR':
split = layout.split()
col = split.column()
@@ -355,14 +369,38 @@ class RENDER_PT_output(RenderButtonsPanel):
elif rd.file_format == 'QUICKTIME_CARBON':
split = layout.split()
- split.operator("scene.render_set_quicktime_codec")
+ split.operator("scene.render_data_set_quicktime_codec")
elif rd.file_format == 'QUICKTIME_QTKIT':
split = layout.split()
col = split.column()
- col.prop(rd, "quicktime_codec_type")
+ col.prop(rd, "quicktime_codec_type", text="Video Codec")
col.prop(rd, "quicktime_codec_spatial_quality", text="Quality")
+ # Audio
+ col.prop(rd, "quicktime_audiocodec_type", text="Audio Codec")
+ if rd.quicktime_audiocodec_type != 'No audio':
+ split = layout.split()
+ col = split.column()
+ if rd.quicktime_audiocodec_type == 'LPCM':
+ col.prop(rd, "quicktime_audio_bitdepth", text="")
+ if wide_ui:
+ col = split.column()
+ col.prop(rd, "quicktime_audio_samplerate", text="")
+
+ split = layout.split()
+ col = split.column()
+ if rd.quicktime_audiocodec_type == 'AAC':
+ col.prop(rd, "quicktime_audio_bitrate")
+ if wide_ui:
+ subsplit = split.split()
+ col = subsplit.column()
+ if rd.quicktime_audiocodec_type == 'AAC':
+ col.prop(rd, "quicktime_audio_codec_isvbr")
+ if wide_ui:
+ col = subsplit.column()
+ col.prop(rd, "quicktime_audio_resampling_hq")
+
class RENDER_PT_encoding(RenderButtonsPanel):
bl_label = "Encoding"
@@ -379,6 +417,8 @@ class RENDER_PT_encoding(RenderButtonsPanel):
rd = context.scene.render
wide_ui = context.region.width > narrowui
+ layout.menu("RENDER_MT_ffmpeg_presets", text="Presets")
+
split = layout.split()
col = split.column()
@@ -441,14 +481,14 @@ class RENDER_PT_antialiasing(RenderButtonsPanel):
def draw_header(self, context):
rd = context.scene.render
- self.layout.prop(rd, "antialiasing", text="")
+ self.layout.prop(rd, "render_antialiasing", text="")
def draw(self, context):
layout = self.layout
rd = context.scene.render
wide_ui = context.region.width > narrowui
- layout.active = rd.antialiasing
+ layout.active = rd.render_antialiasing
split = layout.split()
@@ -482,6 +522,7 @@ class RENDER_PT_motion_blur(RenderButtonsPanel):
row = layout.row()
row.prop(rd, "motion_blur_samples")
+ row.prop(rd, "motion_blur_shutter")
class RENDER_PT_dimensions(RenderButtonsPanel):
@@ -495,10 +536,9 @@ class RENDER_PT_dimensions(RenderButtonsPanel):
rd = scene.render
wide_ui = context.region.width > narrowui
- row = layout.row().split()
- sub = row.row(align=True).split(percentage=0.75)
- sub.menu("RENDER_MT_presets", text="Presets")
- sub.operator("render.preset_add", text="Add")
+ row = layout.row(align=True)
+ row.menu("RENDER_MT_presets", text=bpy.types.RENDER_MT_presets.bl_label)
+ row.operator("render.preset_add", text="", icon="ZOOMIN")
split = layout.split()
@@ -523,8 +563,8 @@ class RENDER_PT_dimensions(RenderButtonsPanel):
col = split.column()
sub = col.column(align=True)
sub.label(text="Frame Range:")
- sub.prop(scene, "start_frame", text="Start")
- sub.prop(scene, "end_frame", text="End")
+ sub.prop(scene, "frame_start", text="Start")
+ sub.prop(scene, "frame_end", text="End")
sub.prop(scene, "frame_step", text="Step")
sub.label(text="Frame Rate:")
@@ -627,6 +667,7 @@ class RENDER_PT_bake(RenderButtonsPanel):
classes = [
RENDER_MT_presets,
+ RENDER_MT_ffmpeg_presets,
RENDER_PT_render,
RENDER_PT_layers,
RENDER_PT_dimensions,
diff --git a/release/scripts/ui/properties_scene.py b/release/scripts/ui/properties_scene.py
index 0209140ef4e..06ad1eda835 100644
--- a/release/scripts/ui/properties_scene.py
+++ b/release/scripts/ui/properties_scene.py
@@ -20,7 +20,7 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class SceneButtonsPanel(bpy.types.Panel):
@@ -96,17 +96,16 @@ class SCENE_PT_keying_sets(SceneButtonsPanel):
col.operator("anim.keying_set_remove", icon='ZOOMOUT', text="")
ks = scene.active_keying_set
- if ks:
+ if ks and ks.absolute:
row = layout.row()
col = row.column()
col.prop(ks, "name")
- col.prop(ks, "absolute")
subcol = col.column()
subcol.operator_context = 'INVOKE_DEFAULT'
op = subcol.operator("anim.keying_set_export", text="Export to File")
- op.path = "keyingset.py"
+ op.filepath = "keyingset.py"
if wide_ui:
col = row.column()
@@ -120,7 +119,7 @@ class SCENE_PT_keying_set_paths(SceneButtonsPanel):
bl_label = "Active Keying Set"
def poll(self, context):
- return (context.scene.active_keying_set is not None)
+ return (context.scene.active_keying_set and context.scene.active_keying_set.absolute)
def draw(self, context):
layout = self.layout
@@ -164,6 +163,11 @@ class SCENE_PT_keying_set_paths(SceneButtonsPanel):
if ksp.grouping == 'NAMED':
col.prop(ksp, "group")
+ col.label(text="Keyframing Settings:")
+ col.prop(ksp, "insertkey_needed", text="Needed")
+ col.prop(ksp, "insertkey_visual", text="Visual")
+ col.prop(ksp, "insertkey_xyz_to_rgb", text="XYZ to RGB")
+
class SCENE_PT_physics(SceneButtonsPanel):
bl_label = "Gravity"
@@ -225,18 +229,16 @@ class ANIM_OT_keying_set_export(bpy.types.Operator):
bl_idname = "anim.keying_set_export"
bl_label = "Export Keying Set..."
- path = bpy.props.StringProperty(name="File Path", description="File path to write file to.")
- filename = bpy.props.StringProperty(name="File Name", description="Name of the file.")
- directory = bpy.props.StringProperty(name="Directory", description="Directory of the file.")
+ filepath = bpy.props.StringProperty(name="File Path", description="Filepath to write file to.")
filter_folder = bpy.props.BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'})
filter_text = bpy.props.BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'})
filter_python = bpy.props.BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'})
def execute(self, context):
- if not self.properties.path:
- raise Exception("File path not set.")
+ if not self.properties.filepath:
+ raise Exception("Filepath not set.")
- f = open(self.properties.path, "w")
+ f = open(self.properties.filepath, "w")
if not f:
raise Exception("Could not open file.")
@@ -295,9 +297,9 @@ class ANIM_OT_keying_set_export(bpy.types.Operator):
# write paths
f.write("# Path Definitions\n")
for ksp in ks.paths:
- f.write("ksp = ks.add_destination(")
+ f.write("ksp = ks.paths.add(")
- # id-block + RNA-path
+ # id-block + data_path
if ksp.id:
# find the relevant shorthand from the cache
id_bpy_path = id_to_paths_cache[ksp.id][0]
@@ -306,8 +308,10 @@ class ANIM_OT_keying_set_export(bpy.types.Operator):
f.write("%s, '%s'" % (id_bpy_path, ksp.data_path))
# array index settings (if applicable)
- if ksp.entire_array is False:
- f.write(", entire_array=False, array_index=%d" % ksp.array_index)
+ if ksp.entire_array:
+ f.write(", index=-1")
+ else:
+ f.write(", index=%d" % ksp.array_index)
# grouping settings (if applicable)
# NOTE: the current default is KEYINGSET, but if this changes, change this code too
diff --git a/release/scripts/ui/properties_texture.py b/release/scripts/ui/properties_texture.py
index 8794b19bd4d..2bfbe188c9e 100644
--- a/release/scripts/ui/properties_texture.py
+++ b/release/scripts/ui/properties_texture.py
@@ -20,24 +20,38 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
-def active_node_mat(mat):
- if mat:
- mat_node = mat.active_node_material
- if mat_node:
- return mat_node
- else:
- return mat
+class TEXTURE_MT_specials(bpy.types.Menu):
+ bl_label = "Texture Specials"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("texture.slot_copy", icon='COPYDOWN')
+ layout.operator("texture.slot_paste", icon='PASTEDOWN')
+
+
+class TEXTURE_MT_envmap_specials(bpy.types.Menu):
+ bl_label = "Environment Map Specials"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ def draw(self, context):
+ layout = self.layout
- return None
+ layout.operator("texture.envmap_save", icon='IMAGEFILE')
+ layout.operator("texture.envmap_clear", icon='FILE_REFRESH')
+ layout.operator("texture.envmap_clear_all", icon='FILE_REFRESH')
+
+from properties_material import active_node_mat
def context_tex_datablock(context):
- idblock = active_node_mat(context.material)
+ idblock = context.material
if idblock:
- return idblock
+ return active_node_mat(idblock)
idblock = context.lamp
if idblock:
@@ -58,18 +72,21 @@ class TextureButtonsPanel(bpy.types.Panel):
def poll(self, context):
tex = context.texture
- return (tex and (tex.type != 'NONE' or tex.use_nodes))
+ if not tex:
+ return False
+ engine = context.scene.render.engine
+ return (tex.type != 'NONE' or tex.use_nodes) and (engine in self.COMPAT_ENGINES)
class TEXTURE_PT_preview(TextureButtonsPanel):
bl_label = "Preview"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
tex = context.texture
- slot = context.texture_slot
-
+ slot = getattr(context, "texture_slot", None)
idblock = context_tex_datablock(context)
if idblock:
@@ -81,9 +98,14 @@ class TEXTURE_PT_preview(TextureButtonsPanel):
class TEXTURE_PT_context_texture(TextureButtonsPanel):
bl_label = ""
bl_show_header = False
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
- return (context.material or context.world or context.lamp or context.brush or context.texture)
+ engine = context.scene.render.engine
+ if not hasattr(context, "texture_slot"):
+ return False
+ return ((context.material or context.world or context.lamp or context.brush or context.texture)
+ and (engine in self.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -103,6 +125,7 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel):
col = row.column(align=True)
col.operator("texture.slot_move", text="", icon='TRIA_UP').type = 'UP'
col.operator("texture.slot_move", text="", icon='TRIA_DOWN').type = 'DOWN'
+ col.menu("TEXTURE_MT_specials", icon='DOWNARROW_HLT', text="")
if wide_ui:
split = layout.split(percentage=0.65)
@@ -145,14 +168,17 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel):
class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel):
_context_path = "texture"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context): # use alternate poll since NONE texture type is ok
- return context.texture
+ engine = context.scene.render.engine
+ return context.texture and (engine in self.COMPAT_ENGINES)
class TEXTURE_PT_colors(TextureButtonsPanel):
bl_label = "Colors"
bl_default_closed = True
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -178,19 +204,36 @@ class TEXTURE_PT_colors(TextureButtonsPanel):
col.label(text="Adjust:")
col.prop(tex, "brightness")
col.prop(tex, "contrast")
+ col.prop(tex, "saturation")
# Texture Slot Panels #
class TextureSlotPanel(TextureButtonsPanel):
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
- return (context.texture_slot and
- TextureButtonsPanel.poll(self, context))
+ if not hasattr(context, "texture_slot"):
+ return False
+
+ engine = context.scene.render.engine
+ return TextureButtonsPanel.poll(self, context) and (engine in self.COMPAT_ENGINES)
class TEXTURE_PT_mapping(TextureSlotPanel):
bl_label = "Mapping"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ def poll(self, context):
+ idblock = context_tex_datablock(context)
+ if type(idblock) == bpy.types.Brush and not context.sculpt_object:
+ return False
+
+ if not getattr(context, "texture_slot", None):
+ return False
+
+ engine = context.scene.render.engine
+ return (engine in self.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -231,15 +274,13 @@ class TEXTURE_PT_mapping(TextureSlotPanel):
split.prop(tex, "object", text="")
if type(idblock) == bpy.types.Brush:
- layout.prop(tex, "map_mode", expand=True)
-
- row = layout.row()
- row.active = tex.map_mode in ('FIXED', 'TILED')
- row.prop(tex, "angle")
+ if context.sculpt_object:
+ layout.label(text="Brush Mapping:")
+ layout.prop(tex, "map_mode", expand=True)
- row = layout.row()
- row.active = tex.map_mode in ('TILED', '3D')
- row.column().prop(tex, "size")
+ row = layout.row()
+ row.active = tex.map_mode in ('FIXED', 'TILED')
+ row.prop(tex, "angle")
else:
if type(idblock) == bpy.types.Material:
split = layout.split(percentage=0.3)
@@ -263,26 +304,33 @@ class TEXTURE_PT_mapping(TextureSlotPanel):
row.prop(tex, "y_mapping", text="")
row.prop(tex, "z_mapping", text="")
- # any non brush
- split = layout.split()
+ split = layout.split()
+
+ col = split.column()
+ col.prop(tex, "offset")
+ if wide_ui:
col = split.column()
- col.prop(tex, "offset")
+ else:
+ col.separator()
- if wide_ui:
- col = split.column()
- col.prop(tex, "size")
+ col.prop(tex, "size")
class TEXTURE_PT_influence(TextureSlotPanel):
bl_label = "Influence"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
idblock = context_tex_datablock(context)
if type(idblock) == bpy.types.Brush:
return False
- return context.texture_slot
+ if not getattr(context, "texture_slot", None):
+ return False
+
+ engine = context.scene.render.engine
+ return (engine in self.COMPAT_ENGINES)
def draw(self, context):
@@ -326,7 +374,8 @@ class TEXTURE_PT_influence(TextureSlotPanel):
factor_but(col, tex.map_raymir, "map_raymir", "raymir_factor", "Ray Mirror")
col.label(text="Geometry:")
- factor_but(col, tex.map_normal, "map_normal", "normal_factor", "Normal")
+ # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
+ factor_but(col, (tex.map_normal or tex.map_displacement), "map_normal", "normal_factor", "Normal")
factor_but(col, tex.map_warp, "map_warp", "warp_factor", "Warp")
factor_but(col, tex.map_displacement, "map_displacement", "displacement_factor", "Displace")
@@ -345,7 +394,7 @@ class TEXTURE_PT_influence(TextureSlotPanel):
if wide_ui:
col = split.column()
col.label(text=" ")
- factor_but(col, tex.map_alpha, "map_coloremission", "coloremission_factor", "Emission Color")
+ factor_but(col, tex.map_coloremission, "map_coloremission", "coloremission_factor", "Emission Color")
factor_but(col, tex.map_colortransmission, "map_colortransmission", "colortransmission_factor", "Transmission Color")
factor_but(col, tex.map_colorreflection, "map_colorreflection", "colorreflection_factor", "Reflection Color")
@@ -394,15 +443,18 @@ class TEXTURE_PT_influence(TextureSlotPanel):
class TextureTypePanel(TextureButtonsPanel):
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
tex = context.texture
- return (tex and tex.type == self.tex_type and not tex.use_nodes)
+ engine = context.scene.render.engine
+ return ((tex and tex.type == self.tex_type and not tex.use_nodes) and (engine in self.COMPAT_ENGINES))
class TEXTURE_PT_clouds(TextureTypePanel):
bl_label = "Clouds"
tex_type = 'CLOUDS'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -432,6 +484,7 @@ class TEXTURE_PT_clouds(TextureTypePanel):
class TEXTURE_PT_wood(TextureTypePanel):
bl_label = "Wood"
tex_type = 'WOOD'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -468,6 +521,7 @@ class TEXTURE_PT_wood(TextureTypePanel):
class TEXTURE_PT_marble(TextureTypePanel):
bl_label = "Marble"
tex_type = 'MARBLE'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -499,6 +553,7 @@ class TEXTURE_PT_marble(TextureTypePanel):
class TEXTURE_PT_magic(TextureTypePanel):
bl_label = "Magic"
tex_type = 'MAGIC'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -519,6 +574,7 @@ class TEXTURE_PT_magic(TextureTypePanel):
class TEXTURE_PT_blend(TextureTypePanel):
bl_label = "Blend"
tex_type = 'BLEND'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -540,6 +596,7 @@ class TEXTURE_PT_blend(TextureTypePanel):
class TEXTURE_PT_stucci(TextureTypePanel):
bl_label = "Stucci"
tex_type = 'STUCCI'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -568,6 +625,7 @@ class TEXTURE_PT_stucci(TextureTypePanel):
class TEXTURE_PT_image(TextureTypePanel):
bl_label = "Image"
tex_type = 'IMAGE'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -577,10 +635,24 @@ class TEXTURE_PT_image(TextureTypePanel):
layout.template_image(tex, "image", tex.image_user)
+def texture_filter_common(tex, layout):
+ layout.label(text="Filter:")
+ layout.prop(tex, "filter", text="")
+ if tex.mipmap and tex.filter in ('AREA', 'EWA', 'FELINE'):
+ if tex.filter == 'FELINE':
+ layout.prop(tex, "filter_probes", text="Probes")
+ else:
+ layout.prop(tex, "filter_eccentricity", text="Eccentricity")
+
+ layout.prop(tex, "filter_size")
+ layout.prop(tex, "filter_size_minimum")
+
+
class TEXTURE_PT_image_sampling(TextureTypePanel):
bl_label = "Image Sampling"
bl_default_closed = True
tex_type = 'IMAGE'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -608,28 +680,20 @@ class TEXTURE_PT_image_sampling(TextureTypePanel):
row.active = tex.normal_map
row.prop(tex, "normal_space", text="")
- col.label(text="Filter:")
- col.prop(tex, "filter", text="")
- col.prop(tex, "filter_size")
- col.prop(tex, "filter_size_minimum")
col.prop(tex, "mipmap")
-
row = col.row()
row.active = tex.mipmap
row.prop(tex, "mipmap_gauss")
-
col.prop(tex, "interpolation")
- if tex.mipmap and tex.filter != 'DEFAULT':
- if tex.filter == 'FELINE':
- col.prop(tex, "filter_probes", text="Probes")
- else:
- col.prop(tex, "filter_eccentricity", text="Eccentricity")
+
+ texture_filter_common(tex, col)
class TEXTURE_PT_image_mapping(TextureTypePanel):
bl_label = "Image Mapping"
bl_default_closed = True
tex_type = 'IMAGE'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -687,6 +751,7 @@ class TEXTURE_PT_image_mapping(TextureTypePanel):
class TEXTURE_PT_plugin(TextureTypePanel):
bl_label = "Plugin"
tex_type = 'PLUGIN'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -699,18 +764,62 @@ class TEXTURE_PT_plugin(TextureTypePanel):
class TEXTURE_PT_envmap(TextureTypePanel):
bl_label = "Environment Map"
tex_type = 'ENVIRONMENT_MAP'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
- # tex = context.texture
+ tex = context.texture
+ env = tex.environment_map
- layout.label(text="Nothing yet")
+ wide_ui = context.region.width > narrowui
+
+ row = layout.row()
+ row.prop(env, "source", expand=True)
+ row.menu("TEXTURE_MT_envmap_specials", icon='DOWNARROW_HLT', text="")
+
+ if env.source == 'IMAGE_FILE':
+ layout.template_ID(tex, "image", open="image.open")
+ layout.template_image(tex, "image", tex.image_user, compact=True)
+ else:
+ layout.prop(env, "mapping")
+ if env.mapping == 'PLANE':
+ layout.prop(env, "zoom")
+ layout.prop(env, "viewpoint_object")
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(env, "ignore_layers")
+ col.prop(env, "resolution")
+ col.prop(env, "depth")
+
+ if wide_ui:
+ col = split.column(align=True)
+
+ col.label(text="Clipping:")
+ col.prop(env, "clip_start", text="Start")
+ col.prop(env, "clip_end", text="End")
+
+
+class TEXTURE_PT_envmap_sampling(TextureTypePanel):
+ bl_label = "Environment Map Sampling"
+ bl_default_closed = True
+ tex_type = 'ENVIRONMENT_MAP'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ tex = context.texture
+
+ texture_filter_common(tex, layout)
class TEXTURE_PT_musgrave(TextureTypePanel):
bl_label = "Musgrave"
tex_type = 'MUSGRAVE'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -758,6 +867,7 @@ class TEXTURE_PT_musgrave(TextureTypePanel):
class TEXTURE_PT_voronoi(TextureTypePanel):
bl_label = "Voronoi"
tex_type = 'VORONOI'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -801,6 +911,7 @@ class TEXTURE_PT_voronoi(TextureTypePanel):
class TEXTURE_PT_distortednoise(TextureTypePanel):
bl_label = "Distorted Noise"
tex_type = 'DISTORTED_NOISE'
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -828,10 +939,12 @@ class TEXTURE_PT_distortednoise(TextureTypePanel):
class TEXTURE_PT_voxeldata(TextureButtonsPanel):
bl_label = "Voxel Data"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
tex = context.texture
- return (tex and tex.type == 'VOXEL_DATA')
+ engine = context.scene.render.engine
+ return (tex and tex.type == 'VOXEL_DATA' and (engine in self.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -848,7 +961,9 @@ class TEXTURE_PT_voxeldata(TextureButtonsPanel):
layout.prop(vd, "domain_object")
layout.prop(vd, "smoke_data_type")
elif vd.file_format == 'IMAGE_SEQUENCE':
- layout.template_image(tex, "image", tex.image_user)
+ layout.template_ID(tex, "image", open="image.open")
+ layout.template_image(tex, "image", tex.image_user, compact=True)
+ #layout.prop(vd, "frames")
layout.prop(vd, "still")
row = layout.row()
@@ -862,10 +977,12 @@ class TEXTURE_PT_voxeldata(TextureButtonsPanel):
class TEXTURE_PT_pointdensity(TextureButtonsPanel):
bl_label = "Point Density"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
tex = context.texture
- return (tex and tex.type == 'POINT_DENSITY')
+ engine = context.scene.render.engine
+ return (tex and tex.type == 'POINT_DENSITY' and (engine in self.COMPAT_ENGINES))
def draw(self, context):
layout = self.layout
@@ -920,10 +1037,12 @@ class TEXTURE_PT_pointdensity(TextureButtonsPanel):
class TEXTURE_PT_pointdensity_turbulence(TextureButtonsPanel):
bl_label = "Turbulence"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
def poll(self, context):
tex = context.texture
- return (tex and tex.type == 'POINT_DENSITY')
+ engine = context.scene.render.engine
+ return (tex and tex.type == 'POINT_DENSITY' and (engine in self.COMPAT_ENGINES))
def draw_header(self, context):
layout = self.layout
@@ -958,6 +1077,9 @@ class TEXTURE_PT_pointdensity_turbulence(TextureButtonsPanel):
classes = [
+ TEXTURE_MT_specials,
+ TEXTURE_MT_envmap_specials,
+
TEXTURE_PT_context_texture,
TEXTURE_PT_preview,
@@ -972,6 +1094,7 @@ classes = [
TEXTURE_PT_image_mapping,
TEXTURE_PT_plugin,
TEXTURE_PT_envmap,
+ TEXTURE_PT_envmap_sampling,
TEXTURE_PT_musgrave,
TEXTURE_PT_voronoi,
TEXTURE_PT_distortednoise,
diff --git a/release/scripts/ui/properties_world.py b/release/scripts/ui/properties_world.py
index 1ee47e942a0..e63d513a4b5 100644
--- a/release/scripts/ui/properties_world.py
+++ b/release/scripts/ui/properties_world.py
@@ -20,7 +20,7 @@
import bpy
from rna_prop_ui import PropertyPanel
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class WorldButtonsPanel(bpy.types.Panel):
@@ -111,14 +111,14 @@ class WORLD_PT_mist(WorldButtonsPanel):
def draw_header(self, context):
world = context.world
- self.layout.prop(world.mist, "enabled", text="")
+ self.layout.prop(world.mist, "use_mist", text="")
def draw(self, context):
layout = self.layout
wide_ui = context.region.width > narrowui
world = context.world
- layout.active = world.mist.enabled
+ layout.active = world.mist.use_mist
split = layout.split()
@@ -142,14 +142,14 @@ class WORLD_PT_stars(WorldButtonsPanel):
def draw_header(self, context):
world = context.world
- self.layout.prop(world.stars, "enabled", text="")
+ self.layout.prop(world.stars, "use_stars", text="")
def draw(self, context):
layout = self.layout
wide_ui = context.region.width > narrowui
world = context.world
- layout.active = world.stars.enabled
+ layout.active = world.stars.use_stars
split = layout.split()
diff --git a/release/scripts/ui/space_buttons.py b/release/scripts/ui/space_buttons.py
index 019f751449f..9fc30a8189b 100644
--- a/release/scripts/ui/space_buttons.py
+++ b/release/scripts/ui/space_buttons.py
@@ -38,7 +38,7 @@ class Buttons_HT_header(bpy.types.Header):
row = layout.row()
row.prop(so, "buttons_context", expand=True, text="")
- row.prop(scene, "current_frame")
+ row.prop(scene, "frame_current")
class Buttons_MT_view(bpy.types.Menu):
diff --git a/release/scripts/ui/space_dopesheet.py b/release/scripts/ui/space_dopesheet.py
index 1dc8ffd1af9..41917acd997 100644
--- a/release/scripts/ui/space_dopesheet.py
+++ b/release/scripts/ui/space_dopesheet.py
@@ -77,6 +77,7 @@ class DOPESHEET_MT_view(bpy.types.Menu):
layout.prop(st, "show_cframe_indicator")
layout.prop(st, "show_sliders")
layout.prop(st, "automerge_keyframes")
+ layout.prop(st, "use_marker_sync")
if st.show_seconds:
layout.operator("anim.time_toggle", text="Show Frames")
@@ -123,6 +124,9 @@ class DOPESHEET_MT_select(bpy.types.Menu):
layout.operator("action.select_more")
layout.operator("action.select_less")
+ layout.separator()
+ layout.operator("action.select_linked")
+
class DOPESHEET_MT_channel(bpy.types.Menu):
bl_label = "Channel"
@@ -154,8 +158,8 @@ class DOPESHEET_MT_key(bpy.types.Menu):
layout.column()
layout.menu("DOPESHEET_MT_key_transform", text="Transform")
- layout.operator_menu_enum("action.snap", property="type", text="Snap")
- layout.operator_menu_enum("action.mirror", property="type", text="Mirror")
+ layout.operator_menu_enum("action.snap", "type", text="Snap")
+ layout.operator_menu_enum("action.mirror", "type", text="Mirror")
layout.separator()
layout.operator("action.keyframe_insert")
@@ -165,10 +169,10 @@ class DOPESHEET_MT_key(bpy.types.Menu):
layout.operator("action.delete")
layout.separator()
- layout.operator_menu_enum("action.keyframe_type", property="type", text="Keyframe Type")
- layout.operator_menu_enum("action.handle_type", property="type", text="Handle Type")
- layout.operator_menu_enum("action.interpolation_type", property="type", text="Interpolation Mode")
- layout.operator_menu_enum("action.extrapolation_type", property="type", text="Extrapolation Mode")
+ layout.operator_menu_enum("action.keyframe_type", "type", text="Keyframe Type")
+ layout.operator_menu_enum("action.handle_type", "type", text="Handle Type")
+ layout.operator_menu_enum("action.interpolation_type", "type", text="Interpolation Mode")
+ layout.operator_menu_enum("action.extrapolation_type", "type", text="Extrapolation Mode")
layout.separator()
layout.operator("action.clean")
@@ -186,9 +190,10 @@ class DOPESHEET_MT_key_transform(bpy.types.Menu):
layout = self.layout
layout.column()
- layout.operator("transform.translate", text="Grab/Move")
+ layout.operator("transform.transform", text="Grab/Move").mode = 'TIME_TRANSLATE'
layout.operator("transform.transform", text="Extend").mode = 'TIME_EXTEND'
- layout.operator("transform.resize", text="Scale")
+ layout.operator("transform.transform", text="Slide").mode = 'TIME_SLIDE'
+ layout.operator("transform.transform", text="Scale").mode = 'TIME_SCALE'
classes = [
diff --git a/release/scripts/ui/space_graph.py b/release/scripts/ui/space_graph.py
index 64f6337177e..1533b891202 100644
--- a/release/scripts/ui/space_graph.py
+++ b/release/scripts/ui/space_graph.py
@@ -114,6 +114,7 @@ class GRAPH_MT_select(bpy.types.Menu):
layout.separator()
layout.operator("graph.select_border")
layout.operator("graph.select_border", text="Border Axis Range").axis_range = True
+ layout.operator("graph.select_border", text="Border (Include Handles)").include_handles = True
layout.separator()
layout.operator("graph.select_column", text="Columns on Selected Keys").mode = 'KEYS'
@@ -126,6 +127,9 @@ class GRAPH_MT_select(bpy.types.Menu):
layout.operator("graph.select_more")
layout.operator("graph.select_less")
+ layout.separator()
+ layout.operator("graph.select_linked")
+
class GRAPH_MT_channel(bpy.types.Menu):
bl_label = "Channel"
@@ -142,6 +146,7 @@ class GRAPH_MT_channel(bpy.types.Menu):
layout.separator()
layout.operator("anim.channels_editable_toggle")
+ layout.operator("anim.channels_visibility_set")
layout.separator()
layout.operator("anim.channels_expand")
@@ -160,8 +165,8 @@ class GRAPH_MT_key(bpy.types.Menu):
layout.column()
layout.menu("GRAPH_MT_key_transform", text="Transform")
- layout.operator_menu_enum("graph.snap", property="type", text="Snap")
- layout.operator_menu_enum("graph.mirror", property="type", text="Mirror")
+ layout.operator_menu_enum("graph.snap", "type", text="Snap")
+ layout.operator_menu_enum("graph.mirror", "type", text="Mirror")
layout.separator()
layout.operator("graph.keyframe_insert")
@@ -172,9 +177,9 @@ class GRAPH_MT_key(bpy.types.Menu):
layout.operator("graph.delete")
layout.separator()
- layout.operator_menu_enum("graph.handle_type", property="type", text="Handle Type")
- layout.operator_menu_enum("graph.interpolation_type", property="type", text="Interpolation Mode")
- layout.operator_menu_enum("graph.extrapolation_type", property="type", text="Extrapolation Mode")
+ layout.operator_menu_enum("graph.handle_type", "type", text="Handle Type")
+ layout.operator_menu_enum("graph.interpolation_type", "type", text="Interpolation Mode")
+ layout.operator_menu_enum("graph.extrapolation_type", "type", text="Extrapolation Mode")
layout.separator()
layout.operator("graph.clean")
diff --git a/release/scripts/ui/space_image.py b/release/scripts/ui/space_image.py
index 3fd7025a4f7..e9c963db7b3 100644
--- a/release/scripts/ui/space_image.py
+++ b/release/scripts/ui/space_image.py
@@ -19,7 +19,7 @@
# <pep8 compliant>
import bpy
-narrowui = 180
+narrowui = bpy.context.user_preferences.view.properties_width_check
class IMAGE_MT_view(bpy.types.Menu):
@@ -29,7 +29,7 @@ class IMAGE_MT_view(bpy.types.Menu):
layout = self.layout
sima = context.space_data
- # uv = sima.uv_editor
+ uv = sima.uv_editor
toolsettings = context.tool_settings
show_uvedit = sima.show_uvedit
@@ -42,6 +42,7 @@ class IMAGE_MT_view(bpy.types.Menu):
layout.prop(sima, "update_automatically")
if show_uvedit:
layout.prop(toolsettings, "uv_local_view") # Numpad /
+ layout.prop(uv, "draw_other_objects")
layout.separator()
@@ -111,10 +112,13 @@ class IMAGE_MT_image(bpy.types.Menu):
layout.operator("image.save")
layout.operator("image.save_as")
+ layout.operator("image.save_as", text="Save a Copy").copy = True
if ima.source == 'SEQUENCE':
layout.operator("image.save_sequence")
+ layout.operator("image.external_edit", "Edit Externally")
+
if not show_render:
layout.separator()
@@ -141,8 +145,8 @@ class IMAGE_MT_uvs_showhide(bpy.types.Menu):
layout = self.layout
layout.operator("uv.reveal")
- layout.operator("uv.hide")
- layout.operator("uv.hide").unselected = True
+ layout.operator("uv.hide", text="Hide Selected")
+ layout.operator("uv.hide", text="Hide Unselected").unselected = True
class IMAGE_MT_uvs_transform(bpy.types.Menu):
@@ -250,7 +254,7 @@ class IMAGE_HT_header(bpy.types.Header):
iuser = sima.image_user
toolsettings = context.tool_settings
- # show_render = sima.show_render
+ show_render = sima.show_render
# show_paint = sima.show_paint
show_uvedit = sima.show_uvedit
@@ -274,6 +278,8 @@ class IMAGE_HT_header(bpy.types.Header):
sub.menu("IMAGE_MT_uvs")
layout.template_ID(sima, "image", new="image.new")
+ if not show_render:
+ layout.prop(sima, "image_pin", text="")
# uv editing
if show_uvedit:
@@ -340,7 +346,7 @@ class IMAGE_PT_image_properties(bpy.types.Panel):
# ima = sima.image
iuser = sima.image_user
- layout.template_image(sima, "image", iuser, compact=True)
+ layout.template_image(sima, "image", iuser)
class IMAGE_PT_game_properties(bpy.types.Panel):
@@ -402,7 +408,81 @@ class IMAGE_PT_view_histogram(bpy.types.Panel):
sima = context.space_data
- layout.template_histogram(sima, "histogram")
+ layout.template_histogram(sima.scopes, "histogram")
+ layout.prop(sima.scopes.histogram, "mode", icon_only=True)
+
+
+class IMAGE_PT_view_waveform(bpy.types.Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'PREVIEW'
+ bl_label = "Waveform"
+
+ def poll(self, context):
+ sima = context.space_data
+ return (sima and sima.image)
+
+ def draw(self, context):
+ layout = self.layout
+
+ sima = context.space_data
+ layout.template_waveform(sima, "scopes")
+ sub = layout.row().split(percentage=0.75)
+ sub.prop(sima.scopes, "waveform_alpha")
+ sub.prop(sima.scopes, "waveform_mode", text="", icon_only=True)
+
+
+class IMAGE_PT_view_vectorscope(bpy.types.Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'PREVIEW'
+ bl_label = "Vectorscope"
+
+ def poll(self, context):
+ sima = context.space_data
+ return (sima and sima.image)
+
+ def draw(self, context):
+ layout = self.layout
+
+ sima = context.space_data
+ layout.template_vectorscope(sima, "scopes")
+ layout.prop(sima.scopes, "vectorscope_alpha")
+
+
+class IMAGE_PT_sample_line(bpy.types.Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'PREVIEW'
+ bl_label = "Sample Line"
+
+ def poll(self, context):
+ sima = context.space_data
+ return (sima and sima.image)
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator("image.sample_line")
+ sima = context.space_data
+ layout.template_histogram(sima, "sample_histogram")
+ layout.prop(sima.sample_histogram, "mode")
+
+
+class IMAGE_PT_scope_sample(bpy.types.Panel):
+ bl_space_type = 'IMAGE_EDITOR'
+ bl_region_type = 'PREVIEW'
+ bl_label = "Scope Samples"
+
+ def poll(self, context):
+ sima = context.space_data
+ return sima
+
+ def draw(self, context):
+ layout = self.layout
+ sima = context.space_data
+ split = layout.split()
+ row = split.row()
+ row.prop(sima.scopes, "use_full_resolution")
+ row = split.row()
+ row.active = not sima.scopes.use_full_resolution
+ row.prop(sima.scopes, "accuracy")
class IMAGE_PT_view_properties(bpy.types.Panel):
@@ -443,6 +523,9 @@ class IMAGE_PT_view_properties(bpy.types.Panel):
if show_uvedit:
col = layout.column()
+ col.prop(uvedit, "cursor_location")
+
+ col = layout.column()
col.label(text="UVs:")
row = col.row()
if wide_ui:
@@ -570,7 +653,7 @@ class IMAGE_PT_paint_curve(bpy.types.Panel):
brush = toolsettings.brush
layout.template_curve_mapping(brush, "curve")
- layout.operator_menu_enum("brush.curve_preset", property="shape")
+ layout.operator_menu_enum("brush.curve_preset", "shape")
classes = [
@@ -590,7 +673,11 @@ classes = [
IMAGE_PT_paint_curve,
IMAGE_PT_game_properties,
IMAGE_PT_view_properties,
- IMAGE_PT_view_histogram]
+ IMAGE_PT_view_histogram,
+ IMAGE_PT_view_waveform,
+ IMAGE_PT_view_vectorscope,
+ IMAGE_PT_sample_line,
+ IMAGE_PT_scope_sample]
def register():
diff --git a/release/scripts/ui/space_info.py b/release/scripts/ui/space_info.py
index e1bc8f2b226..ca8371b85fe 100644
--- a/release/scripts/ui/space_info.py
+++ b/release/scripts/ui/space_info.py
@@ -25,7 +25,7 @@ class INFO_HT_header(bpy.types.Header):
def draw(self, context):
layout = self.layout
-
+
wm = context.manager
if wm and len(wm.operators):
last_op = wm.operators[-1]
@@ -64,11 +64,10 @@ class INFO_HT_header(bpy.types.Header):
layout.separator()
layout.template_running_jobs()
-
- if last_op and last_op.has_reports:
- layout.template_reports_banner(last_op)
- else:
- layout.label(text=scene.statistics())
+
+ layout.template_reports_banner()
+
+ layout.label(text=scene.statistics())
# XXX: this should be right-aligned to the RHS of the region
layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER', text="")
@@ -85,7 +84,7 @@ class INFO_MT_file(bpy.types.Menu):
layout.operator_context = 'INVOKE_AREA'
layout.operator("wm.open_mainfile", text="Open...", icon='FILE_FOLDER')
layout.menu("INFO_MT_file_open_recent")
- layout.operator("wm.recover_last_session")
+ layout.operator("wm.recover_last_session", icon='RECOVER_LAST')
layout.operator("wm.recover_auto_save", text="Recover Auto Save...")
layout.separator()
@@ -106,7 +105,9 @@ class INFO_MT_file(bpy.types.Menu):
layout.operator_context = 'INVOKE_AREA'
layout.operator("wm.link_append", text="Link")
- layout.operator("wm.link_append", text="Append").link = False
+ props = layout.operator("wm.link_append", text="Append")
+ props.link = False
+ props.instance_groups = False
layout.separator()
@@ -123,27 +124,6 @@ class INFO_MT_file(bpy.types.Menu):
layout.operator("wm.exit_blender", text="Quit", icon='QUIT')
-class INFO_MT_file_open_recent(bpy.types.Menu):
- bl_idname = "INFO_MT_file_open_recent"
- bl_label = "Open Recent..."
-
- def draw(self, context):
- import os
- layout = self.layout
- layout.operator_context = 'EXEC_AREA'
-
- path = os.path.join(bpy.app.home, ".Blog")
-
- if os.path.isfile(path):
- file = open(path, "rU")
- for line in file:
- line = line.rstrip()
- layout.operator("wm.open_mainfile", text=line, icon='FILE_BLEND').path = line
- file.close()
- else:
- layout.label(text='No recent files')
-
-
class INFO_MT_file_import(bpy.types.Menu):
bl_idname = "INFO_MT_file_import"
bl_label = "Import"
@@ -198,6 +178,35 @@ class INFO_MT_mesh_add(bpy.types.Menu):
layout.operator("mesh.primitive_monkey_add", icon='MESH_MONKEY', text="Monkey")
+class INFO_MT_curve_add(bpy.types.Menu):
+ bl_idname = "INFO_MT_curve_add"
+ bl_label = "Curve"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("curve.primitive_bezier_curve_add", icon='CURVE_BEZCURVE', text="Bezier")
+ layout.operator("curve.primitive_bezier_circle_add", icon='CURVE_BEZCIRCLE', text="Circle")
+ layout.operator("curve.primitive_nurbs_curve_add", icon='CURVE_NCURVE', text="Nurbs Curve")
+ layout.operator("curve.primitive_nurbs_circle_add", icon='CURVE_NCIRCLE', text="Nurbs Circle")
+ layout.operator("curve.primitive_nurbs_path_add", icon='CURVE_PATH', text="Path")
+
+
+class INFO_MT_surface_add(bpy.types.Menu):
+ bl_idname = "INFO_MT_surface_add"
+ bl_label = "Surface"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("surface.primitive_nurbs_surface_curve_add", icon='SURFACE_NCURVE', text="NURBS Curve")
+ layout.operator("surface.primitive_nurbs_surface_circle_add", icon='SURFACE_NCIRCLE', text="NURBS Circle")
+ layout.operator("surface.primitive_nurbs_surface_surface_add", icon='SURFACE_NSURFACE', text="NURBS Surface")
+ layout.operator("surface.primitive_nurbs_surface_tube_add", icon='SURFACE_NTUBE', text="NURBS Tube")
+ layout.operator("surface.primitive_nurbs_surface_sphere_add", icon='SURFACE_NSPHERE', text="NURBS Sphere")
+ layout.operator("surface.primitive_nurbs_surface_donut_add", icon='SURFACE_NDONUT', text="NURBS Torus")
+
+
class INFO_MT_armature_add(bpy.types.Menu):
bl_idname = "INFO_MT_armature_add"
bl_label = "Armature"
@@ -219,9 +228,11 @@ class INFO_MT_add(bpy.types.Menu):
#layout.operator_menu_enum("object.mesh_add", "type", text="Mesh", icon='OUTLINER_OB_MESH')
layout.menu("INFO_MT_mesh_add", icon='OUTLINER_OB_MESH')
- layout.operator_menu_enum("object.curve_add", "type", text="Curve", icon='OUTLINER_OB_CURVE')
- layout.operator_menu_enum("object.surface_add", "type", text="Surface", icon='OUTLINER_OB_SURFACE')
- layout.operator_menu_enum("object.metaball_add", "type", 'META', text="Metaball", icon='OUTLINER_OB_META')
+ #layout.operator_menu_enum("object.curve_add", "type", text="Curve", icon='OUTLINER_OB_CURVE')
+ layout.menu("INFO_MT_curve_add", icon='OUTLINER_OB_CURVE')
+ #layout.operator_menu_enum("object.surface_add", "type", text="Surface", icon='OUTLINER_OB_SURFACE')
+ layout.menu("INFO_MT_surface_add", icon='OUTLINER_OB_SURFACE')
+ layout.operator_menu_enum("object.metaball_add", "type", text="Metaball", icon='OUTLINER_OB_META')
layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT')
layout.separator()
@@ -233,17 +244,17 @@ class INFO_MT_add(bpy.types.Menu):
layout.operator("object.camera_add", text="Camera", icon='OUTLINER_OB_CAMERA')
layout.operator_context = 'EXEC_SCREEN'
- layout.operator_menu_enum("object.lamp_add", "type", 'LAMP', text="Lamp", icon='OUTLINER_OB_LAMP')
+ layout.operator_menu_enum("object.lamp_add", "type", text="Lamp", icon='OUTLINER_OB_LAMP')
layout.separator()
- layout.operator_menu_enum("object.effector_add", "type", 'EMPTY', text="Force Field", icon='OUTLINER_OB_EMPTY')
+ layout.operator_menu_enum("object.effector_add", "type", text="Force Field", icon='OUTLINER_OB_EMPTY')
layout.separator()
if(len(bpy.data.groups) > 10):
layout.operator_context = 'INVOKE_DEFAULT'
- layout.operator("object.group_instance_add", "type", text="Group Instance...", icon='OUTLINER_OB_EMPTY')
+ layout.operator("object.group_instance_add", text="Group Instance...", icon='OUTLINER_OB_EMPTY')
else:
- layout.operator_menu_enum("object.group_instance_add", "type", text="Group Instance", icon='OUTLINER_OB_EMPTY')
+ layout.operator_menu_enum("object.group_instance_add", "group", text="Group Instance", icon='OUTLINER_OB_EMPTY')
class INFO_MT_game(bpy.types.Menu):
@@ -263,6 +274,8 @@ class INFO_MT_game(bpy.types.Menu):
layout.prop(gs, "show_physics_visualization")
layout.prop(gs, "use_deprecation_warnings")
layout.prop(gs, "use_animation_record")
+ layout.separator()
+ layout.prop(gs, "auto_start")
class INFO_MT_render(bpy.types.Menu):
@@ -273,18 +286,18 @@ class INFO_MT_render(bpy.types.Menu):
# rd = context.scene.render
- layout.operator("screen.render", text="Render Image", icon='RENDER_STILL')
- layout.operator("screen.render", text="Render Animation", icon='RENDER_ANIMATION').animation = True
+ layout.operator("render.render", text="Render Image", icon='RENDER_STILL')
+ layout.operator("render.render", text="Render Animation", icon='RENDER_ANIMATION').animation = True
layout.separator()
- layout.operator("screen.opengl_render", text="OpenGL Render Image")
- layout.operator("screen.opengl_render", text="OpenGL Render Animation").animation = True
+ layout.operator("render.opengl", text="OpenGL Render Image")
+ layout.operator("render.opengl", text="OpenGL Render Animation").animation = True
layout.separator()
- layout.operator("screen.render_view_show")
- layout.operator("screen.play_rendered_anim")
+ layout.operator("render.view_show")
+ layout.operator("render.play_rendered_anim")
class INFO_MT_help(bpy.types.Menu):
@@ -293,92 +306,30 @@ class INFO_MT_help(bpy.types.Menu):
def draw(self, context):
layout = self.layout
- layout.operator("help.manual", icon='HELP')
- layout.operator("help.release_logs", icon='URL')
+ 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-250/'
layout.separator()
- layout.operator("help.blender_website", icon='URL')
- layout.operator("help.blender_eshop", icon='URL')
- layout.operator("help.developer_community", icon='URL')
- layout.operator("help.user_community", icon='URL')
+ layout.operator("wm.url_open", text="Blender Website", icon='URL').url = 'http://www.blender.org/'
+ layout.operator("wm.url_open", text="Blender e-Shop", icon='URL').url = 'http://www.blender.org/e-shop'
+ layout.operator("wm.url_open", text="Developer Community", icon='URL').url = 'http://www.blender.org/community/get-involved/'
+ layout.operator("wm.url_open", text="User Community", icon='URL').url = 'http://www.blender.org/community/user-community/'
layout.separator()
- layout.operator("help.report_bug", icon='URL')
+ layout.operator("wm.url_open", text="Report a Bug", icon='URL').url = 'http://projects.blender.org/tracker/?atid=498&group_id=9&func=browse'
layout.separator()
- layout.operator("help.python_api", icon='URL')
+ layout.operator("wm.url_open", text="Python API Reference", icon='URL').url = 'http://www.blender.org/documentation/250PythonDoc/contents.html'
layout.operator("help.operator_cheat_sheet")
+ layout.separator()
+ layout.operator("wm.splash")
# Help operators
-class HelpOperator(bpy.types.Operator):
-
- def execute(self, context):
- import webbrowser
- webbrowser.open(self._url)
- return {'FINISHED'}
-
-
-class HELP_OT_manual(HelpOperator):
- '''The Blender Wiki manual'''
- bl_idname = "help.manual"
- bl_label = "Manual"
- _url = 'http://wiki.blender.org/index.php/Doc:Manual'
-
-
-class HELP_OT_release_logs(HelpOperator):
- '''Information about the changes in this version of Blender'''
- bl_idname = "help.release_logs"
- bl_label = "Release Log"
- _url = 'http://www.blender.org/development/release-logs/blender-250/'
-
-
-class HELP_OT_blender_website(HelpOperator):
- '''The official Blender website'''
- bl_idname = "help.blender_website"
- bl_label = "Blender Website"
- _url = 'http://www.blender.org/'
-
-
-class HELP_OT_blender_eshop(HelpOperator):
- '''Buy official Blender resources and merchandise online'''
- bl_idname = "help.blender_eshop"
- bl_label = "Blender e-Shop"
- _url = 'http://www.blender3d.org/e-shop'
-
-
-class HELP_OT_developer_community(HelpOperator):
- '''Get involved with Blender development'''
- bl_idname = "help.developer_community"
- bl_label = "Developer Community"
- _url = 'http://www.blender.org/community/get-involved/'
-
-
-class HELP_OT_user_community(HelpOperator):
- '''Get involved with other Blender users'''
- bl_idname = "help.user_community"
- bl_label = "User Community"
- _url = 'http://www.blender.org/community/user-community/'
-
-
-class HELP_OT_report_bug(HelpOperator):
- '''Report a bug in the Blender bug tracker'''
- bl_idname = "help.report_bug"
- bl_label = "Report a Bug"
- _url = 'http://projects.blender.org/tracker/?atid=498&group_id=9&func=browse'
-
-
-class HELP_OT_python_api(HelpOperator):
- '''Reference for operator and data Python API'''
- bl_idname = "help.python_api"
- bl_label = "Python API Reference"
- _url = 'http://www.blender.org/documentation/250PythonDoc/contents.html'
-
-
class HELP_OT_operator_cheat_sheet(bpy.types.Operator):
bl_idname = "help.operator_cheat_sheet"
- bl_label = "Operator Cheat Sheet (new textblock)"
+ bl_label = "Operator Cheat Sheet"
def execute(self, context):
op_strings = []
@@ -404,25 +355,18 @@ class HELP_OT_operator_cheat_sheet(bpy.types.Operator):
classes = [
INFO_HT_header,
INFO_MT_file,
- INFO_MT_file_open_recent,
INFO_MT_file_import,
INFO_MT_file_export,
INFO_MT_file_external_data,
INFO_MT_add,
INFO_MT_mesh_add,
+ INFO_MT_curve_add,
+ INFO_MT_surface_add,
INFO_MT_armature_add,
INFO_MT_game,
INFO_MT_render,
INFO_MT_help,
- HELP_OT_manual,
- HELP_OT_release_logs,
- HELP_OT_blender_website,
- HELP_OT_blender_eshop,
- HELP_OT_developer_community,
- HELP_OT_user_community,
- HELP_OT_report_bug,
- HELP_OT_python_api,
HELP_OT_operator_cheat_sheet]
diff --git a/release/scripts/ui/space_logic.py b/release/scripts/ui/space_logic.py
index 07b26fdc862..a01a5ce6305 100644
--- a/release/scripts/ui/space_logic.py
+++ b/release/scripts/ui/space_logic.py
@@ -35,20 +35,31 @@ class LOGIC_PT_properties(bpy.types.Panel):
ob = context.active_object
game = ob.game
- layout.operator("object.game_property_new", text="Add Game Property")
+ layout.operator("object.game_property_new", text="Add Game Property", icon='ZOOMIN')
for i, prop in enumerate(game.properties):
- row = layout.row(align=True)
+ box = layout.box()
+ row = box.row()
row.prop(prop, "name", text="")
row.prop(prop, "type", text="")
row.prop(prop, "value", text="", toggle=True) # we dont care about the type. rna will display correctly
row.prop(prop, "debug", text="", toggle=True, icon='INFO')
- row.operator("object.game_property_remove", text="", icon='X').index = i
+ row.operator("object.game_property_remove", text="", icon='X', emboss=False).index = i
+class LOGIC_MT_logicbricks_add(bpy.types.Menu):
+ bl_label = "Add"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_menu_enum("logic.sensor_add", "type", text="Sensor")
+ layout.operator_menu_enum("logic.controller_add", "type", text="Controller")
+ layout.operator_menu_enum("logic.actuator_add", "type", text="Actuator")
+
classes = [
- LOGIC_PT_properties]
+ LOGIC_PT_properties, LOGIC_MT_logicbricks_add]
def register():
diff --git a/release/scripts/ui/space_nla.py b/release/scripts/ui/space_nla.py
index 12ed8aa7740..0eb342d4b15 100644
--- a/release/scripts/ui/space_nla.py
+++ b/release/scripts/ui/space_nla.py
@@ -102,7 +102,7 @@ class NLA_MT_edit(bpy.types.Menu):
layout.column()
layout.menu("NLA_MT_edit_transform", text="Transform")
- layout.operator_menu_enum("nla.snap", property="type", text="Snap")
+ layout.operator_menu_enum("nla.snap", "type", text="Snap")
layout.separator()
layout.operator("nla.duplicate")
diff --git a/release/scripts/ui/space_node.py b/release/scripts/ui/space_node.py
index f510235a39d..365835009ba 100644
--- a/release/scripts/ui/space_node.py
+++ b/release/scripts/ui/space_node.py
@@ -55,7 +55,10 @@ class NODE_HT_header(bpy.types.Header):
snode_id = snode.id
id_from = snode.id_from
if id_from:
- layout.template_ID(id_from, "active_texture", new="texture.new")
+ if snode.texture_type == 'BRUSH':
+ layout.template_ID(id_from, "texture", new="texture.new")
+ else:
+ layout.template_ID(id_from, "active_texture", new="texture.new")
if snode_id:
layout.prop(snode_id, "use_nodes")
@@ -66,6 +69,10 @@ class NODE_HT_header(bpy.types.Header):
layout.prop(scene.render, "free_unused_nodes", text="Free Unused")
layout.prop(snode, "backdrop")
+ layout.separator()
+
+ layout.template_running_jobs()
+
class NODE_MT_view(bpy.types.Menu):
bl_label = "View"
@@ -101,6 +108,9 @@ class NODE_MT_select(bpy.types.Menu):
layout.operator("node.select_all")
layout.operator("node.select_linked_from")
layout.operator("node.select_linked_to")
+ layout.operator("node.select_same_type")
+ layout.operator("node.select_same_type_next")
+ layout.operator("node.select_same_type_prev")
class NODE_MT_node(bpy.types.Menu):
@@ -129,8 +139,10 @@ class NODE_MT_node(bpy.types.Menu):
layout.separator()
- layout.operator("node.hide")
- layout.operator("node.mute")
+ layout.operator("node.hide_toggle")
+ layout.operator("node.mute_toggle")
+ layout.operator("node.preview_toggle")
+ layout.operator("node.hide_socket_toggle")
# XXX
# layout.operator("node.rename")
diff --git a/release/scripts/ui/space_outliner.py b/release/scripts/ui/space_outliner.py
index d5bb35baa6c..ec3c430feaa 100644
--- a/release/scripts/ui/space_outliner.py
+++ b/release/scripts/ui/space_outliner.py
@@ -36,11 +36,14 @@ class OUTLINER_HT_header(bpy.types.Header):
if context.area.show_menus:
sub = row.row(align=True)
sub.menu("OUTLINER_MT_view")
+ sub.menu("OUTLINER_MT_search")
if space.display_mode == 'DATABLOCKS':
sub.menu("OUTLINER_MT_edit_datablocks")
layout.prop(space, "display_mode", text="")
+ layout.prop(space, "display_filter", icon='VIEWZOOM', text="")
+
layout.separator()
if space.display_mode == 'DATABLOCKS':
@@ -83,6 +86,20 @@ class OUTLINER_MT_view(bpy.types.Menu):
layout.operator("screen.screen_full_area")
+class OUTLINER_MT_search(bpy.types.Menu):
+ bl_label = "Search"
+
+ def draw(self, context):
+ layout = self.layout
+
+ space = context.space_data
+
+ col = layout.column()
+
+ col.prop(space, "match_case_sensitive")
+ col.prop(space, "match_complete")
+
+
class OUTLINER_MT_edit_datablocks(bpy.types.Menu):
bl_label = "Edit"
@@ -103,6 +120,7 @@ class OUTLINER_MT_edit_datablocks(bpy.types.Menu):
classes = [
OUTLINER_HT_header,
OUTLINER_MT_view,
+ OUTLINER_MT_search,
OUTLINER_MT_edit_datablocks]
diff --git a/release/scripts/ui/space_sequencer.py b/release/scripts/ui/space_sequencer.py
index 8930a04e11c..97d84b77e18 100644
--- a/release/scripts/ui/space_sequencer.py
+++ b/release/scripts/ui/space_sequencer.py
@@ -50,10 +50,10 @@ class SEQUENCER_HT_header(bpy.types.Header):
sub.menu("SEQUENCER_MT_add")
sub.menu("SEQUENCER_MT_strip")
- layout.prop(st, "view_type", text="")
+ layout.prop(st, "view_type", expand=True, text="")
if (st.view_type == 'PREVIEW') or (st.view_type == 'SEQUENCER_PREVIEW'):
- layout.prop(st, "display_mode", text="")
+ layout.prop(st, "display_mode", expand=True, text="")
if (st.view_type == 'SEQUENCER'):
row = layout.row(align=True)
@@ -69,6 +69,14 @@ class SEQUENCER_HT_header(bpy.types.Header):
else:
layout.prop(st, "display_channel", text="Channel")
+ ed = context.scene.sequence_editor
+ if ed:
+ row = layout.row(align=True)
+ row.prop(ed, "show_overlay", text="", icon='GHOST_ENABLED')
+ if ed.show_overlay:
+ row.prop(ed, "overlay_frame", text="")
+ row.prop(ed, "overlay_lock", text="", icon='LOCKED')
+
class SEQUENCER_MT_view_toggle(bpy.types.Menu):
bl_label = "View Type"
@@ -126,6 +134,10 @@ class SEQUENCER_MT_view(bpy.types.Menu):
layout.operator_context = 'INVOKE_REGION_PREVIEW'
layout.operator("sequencer.view_all_preview", text='Fit preview in window')
layout.operator_context = 'INVOKE_DEFAULT'
+
+ # # XXX, invokes in the header view
+ # layout.operator("sequencer.view_ghost_border", text='Overlay Border')
+
layout.operator("sequencer.view_selected")
layout.prop(st, "draw_frames")
@@ -136,6 +148,8 @@ class SEQUENCER_MT_view(bpy.types.Menu):
layout.prop(st, "separate_color_preview")
layout.separator()
+ layout.prop(st, "use_marker_sync")
+ layout.separator()
layout.operator("screen.area_dupli")
layout.operator("screen.screen_full_area")
@@ -185,7 +199,7 @@ class SEQUENCER_MT_add(bpy.types.Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
layout.column()
- layout.operator("sequencer.scene_strip_add", text="Scene")
+ layout.operator_menu_enum("sequencer.scene_strip_add", "scene", text="Scene...")
layout.operator("sequencer.movie_strip_add", text="Movie")
layout.operator("sequencer.image_strip_add", text="Image")
layout.operator("sequencer.sound_strip_add", text="Sound")
@@ -215,6 +229,7 @@ class SEQUENCER_MT_add_effect(bpy.types.Menu):
layout.operator("sequencer.effect_strip_add", text="Transform").type = 'TRANSFORM'
layout.operator("sequencer.effect_strip_add", text="Color").type = 'COLOR'
layout.operator("sequencer.effect_strip_add", text="Speed Control").type = 'SPEED'
+ layout.operator("sequencer.effect_strip_add", text="Multicam Selector").type = 'MULTICAM'
class SEQUENCER_MT_strip(bpy.types.Menu):
@@ -234,6 +249,7 @@ class SEQUENCER_MT_strip(bpy.types.Menu):
layout.operator("sequencer.cut", text="Cut (hard) at frame").type = 'HARD'
layout.operator("sequencer.cut", text="Cut (soft) at frame").type = 'SOFT'
layout.operator("sequencer.images_separate")
+ layout.operator("sequencer.deinterlace_selected_movies")
layout.separator()
layout.operator("sequencer.duplicate")
@@ -244,20 +260,23 @@ class SEQUENCER_MT_strip(bpy.types.Menu):
if strip:
stype = strip.type
- if stype == 'EFFECT':
- layout.separator()
- layout.operator("sequencer.effect_change")
- layout.operator("sequencer.effect_reassign_inputs")
+ # XXX note strip.type is never equal to 'EFFECT', look at seq_type_items within rna_sequencer.c
+ if stype == 'EFFECT':
+ pass
+ # layout.separator()
+ # layout.operator("sequencer.effect_change")
+ # layout.operator("sequencer.effect_reassign_inputs")
elif stype == 'IMAGE':
layout.separator()
# layout.operator("sequencer.image_change")
layout.operator("sequencer.rendersize")
elif stype == 'SCENE':
- layout.separator()
- layout.operator("sequencer.scene_change", text="Change Scene")
+ pass
+ # layout.separator()
+ # layout.operator("sequencer.scene_change", text="Change Scene")
elif stype == 'MOVIE':
layout.separator()
- layout.operator("sequencer.movie_change")
+ # layout.operator("sequencer.movie_change")
layout.operator("sequencer.rendersize")
layout.separator()
@@ -272,6 +291,7 @@ class SEQUENCER_MT_strip(bpy.types.Menu):
layout.separator()
layout.operator("sequencer.reload")
+ layout.operator("sequencer.reassign_inputs")
layout.separator()
layout.operator("sequencer.lock")
layout.operator("sequencer.unlock")
@@ -284,6 +304,10 @@ class SEQUENCER_MT_strip(bpy.types.Menu):
layout.operator_menu_enum("sequencer.swap", "side")
+ layout.separator()
+
+ layout.operator("sequencer.swap_data")
+
class SequencerButtonsPanel(bpy.types.Panel):
bl_space_type = 'SEQUENCE_EDITOR'
@@ -312,7 +336,9 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel):
def draw(self, context):
layout = self.layout
+ scene = context.scene
render = context.scene.render
+ frame_current = scene.frame_current
strip = act_strip(context)
split = layout.split(percentage=0.3)
@@ -327,38 +353,54 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel):
split.label(text="Blend:")
split.prop(strip, "blend_mode", text="")
- row = layout.row()
- if strip.mute == True:
- row.prop(strip, "mute", toggle=True, icon='RESTRICT_VIEW_ON', text="")
- elif strip.mute is False:
- row.prop(strip, "mute", toggle=True, icon='RESTRICT_VIEW_OFF', text="")
-
+ row = layout.row(align=True)
sub = row.row()
sub.active = (not strip.mute)
-
sub.prop(strip, "blend_opacity", text="Opacity", slider=True)
-
- row = layout.row()
- row.prop(strip, "lock")
- row.prop(strip, "frame_locked", text="Frame Lock")
+ sub = row.row()
+ row.prop(strip, "mute", toggle=True, icon='RESTRICT_VIEW_ON' if strip.mute else 'RESTRICT_VIEW_OFF', text="")
+ row.prop(strip, "lock", toggle=True, icon='LOCKED' if strip.lock else 'UNLOCKED', text="")
col = layout.column()
- col.enabled = not strip.lock
- col.prop(strip, "channel")
- col.prop(strip, "start_frame")
- subrow = col.split(percentage=0.66)
- subrow.prop(strip, "length")
- subrow.label(text="%.2f sec" % (strip.length / (render.fps / render.fps_base)))
+ sub = col.column()
+ sub.enabled = not strip.lock
+ sub.prop(strip, "channel")
+ sub.prop(strip, "frame_start")
+ sub.prop(strip, "frame_final_length")
col = layout.column(align=True)
- col.label(text="Offset:")
- col.prop(strip, "start_offset", text="Start")
- col.prop(strip, "end_offset", text="End")
+ row = col.row()
+ row.label(text="Final Length: %s" % bpy.utils.smpte_from_frame(strip.frame_final_length))
+ row = col.row()
+ row.active = (frame_current >= strip.frame_start and frame_current <= strip.frame_start + strip.frame_length)
+ row.label(text="Playhead: %d" % (frame_current - strip.frame_start))
+
+ col.label(text="Frame Offset %d:%d" % (strip.frame_offset_start, strip.frame_offset_end))
+ col.label(text="Frame Still %d:%d" % (strip.frame_still_start, strip.frame_still_end))
- col = layout.column(align=True)
- col.label(text="Still:")
- col.prop(strip, "start_still", text="Start")
- col.prop(strip, "end_still", text="End")
+
+class SEQUENCER_PT_preview(bpy.types.Panel):
+ bl_label = "Scene Preview/Render"
+ bl_space_type = 'SEQUENCE_EDITOR'
+ bl_region_type = 'UI'
+
+ def draw(self, context):
+ layout = self.layout
+ render = context.scene.render
+
+ col = layout.column()
+ col.prop(render, "use_sequencer_gl_preview", text="Open GL Preview")
+ col = layout.column()
+ col.active = render.use_sequencer_gl_preview
+ col.prop(render, "sequencer_gl_preview", text="")
+
+ '''
+ col = layout.column()
+ col.prop(render, "use_sequencer_gl_render", text="Open GL Render")
+ col = layout.column()
+ col.active = render.use_sequencer_gl_render
+ col.prop(render, "sequencer_gl_render", text="")
+ '''
class SEQUENCER_PT_effect(SequencerButtonsPanel):
@@ -375,7 +417,8 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel):
return strip.type in ('ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
'PLUGIN',
- 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED')
+ 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR', 'SPEED',
+ 'MULTICAM')
def draw(self, context):
layout = self.layout
@@ -419,6 +462,22 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel):
elif strip.type == 'TRANSFORM':
self.draw_panel_transform(strip)
+ elif strip.type == "MULTICAM":
+ layout.prop(strip, "multicam_source")
+
+ row = layout.row(align=True)
+ sub = row.row()
+ sub.scale_x = 2.0
+
+ if not context.screen.animation_playing:
+ sub.operator("screen.animation_play", text="", icon='PLAY')
+ else:
+ sub.operator("screen.animation_play", text="", icon='PAUSE')
+
+ row.label("Cut To")
+ for i in range(1, strip.channel):
+ row.operator("sequencer.cut_multicam", text=str(i)).camera = i
+
col = layout.column(align=True)
if strip.type == 'SPEED':
@@ -470,11 +529,16 @@ class SEQUENCER_PT_input(SequencerButtonsPanel):
if not strip:
return False
- return strip.type in ('MOVIE', 'IMAGE')
-
+ return strip.type in ('MOVIE', 'IMAGE', 'SCENE', 'META',
+ 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
+ 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
+ 'PLUGIN',
+ 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
+ 'MULTICAM', 'SPEED')
+
def draw_filename(self, context):
pass
-
+
def draw(self, context):
layout = self.layout
@@ -483,16 +547,14 @@ class SEQUENCER_PT_input(SequencerButtonsPanel):
self.draw_filename(context)
layout.prop(strip, "use_translation", text="Image Offset:")
- if strip.transform:
+ if strip.use_translation:
col = layout.column(align=True)
- col.active = strip.use_translation
col.prop(strip.transform, "offset_x", text="X")
col.prop(strip.transform, "offset_y", text="Y")
layout.prop(strip, "use_crop", text="Image Crop:")
- if strip.crop:
+ if strip.use_crop:
col = layout.column(align=True)
- col.active = strip.use_crop
col.prop(strip.crop, "top")
col.prop(strip.crop, "left")
col.prop(strip.crop, "bottom")
@@ -502,7 +564,8 @@ class SEQUENCER_PT_input(SequencerButtonsPanel):
col.label(text="Trim Duration:")
col.prop(strip, "animation_start_offset", text="Start")
col.prop(strip, "animation_end_offset", text="End")
-
+
+
class SEQUENCER_PT_input_movie(SEQUENCER_PT_input):
bl_label = "Strip Input"
@@ -527,6 +590,7 @@ class SEQUENCER_PT_input_movie(SEQUENCER_PT_input):
col = split.column()
col.prop(strip, "filepath", text="")
+
class SEQUENCER_PT_input_image(SEQUENCER_PT_input):
bl_label = "Strip Input"
@@ -553,7 +617,7 @@ class SEQUENCER_PT_input_image(SEQUENCER_PT_input):
# Current element for the filename
- elem = strip.getStripElem(context.scene.current_frame)
+ elem = strip.getStripElem(context.scene.frame_current)
if elem:
split = layout.split(percentage=0.2)
col = split.column()
@@ -562,6 +626,23 @@ class SEQUENCER_PT_input_image(SEQUENCER_PT_input):
col.prop(elem, "filename", text="") # strip.elements[0] could be a fallback
+class SEQUENCER_PT_input_secondary(SEQUENCER_PT_input):
+ bl_label = "Strip Input"
+
+ def poll(self, context):
+ if not self.has_sequencer(context):
+ return False
+
+ strip = act_strip(context)
+ if not strip:
+ return False
+
+ return strip.type in ('SCENE', 'META')
+
+ def draw_filename(self, context):
+ pass
+
+
class SEQUENCER_PT_sound(SequencerButtonsPanel):
bl_label = "Sound"
@@ -583,7 +664,7 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel):
layout.template_ID(strip, "sound", open="sound.open")
layout.separator()
- layout.prop(strip.sound, "filepath", text="")
+ layout.prop(strip, "filepath", text="")
row = layout.row()
if strip.sound.packed_file:
@@ -594,6 +675,12 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel):
row.prop(strip.sound, "caching")
layout.prop(strip, "volume")
+ layout.prop(strip, "attenuation")
+
+ col = layout.column(align=True)
+ col.label(text="Trim Duration:")
+ col.prop(strip, "animation_start_offset", text="Start")
+ col.prop(strip, "animation_end_offset", text="End")
class SEQUENCER_PT_scene(SequencerButtonsPanel):
@@ -616,6 +703,9 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel):
layout.template_ID(strip, "scene")
+ layout.label(text="Camera Override")
+ layout.template_ID(strip, "scene_camera")
+
class SEQUENCER_PT_filter(SequencerButtonsPanel):
bl_label = "Filter"
@@ -628,7 +718,12 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel):
if not strip:
return False
- return strip.type in ('MOVIE', 'IMAGE', 'SCENE', 'META')
+ return strip.type in ('MOVIE', 'IMAGE', 'SCENE', 'META',
+ 'ADD', 'SUBTRACT', 'ALPHA_OVER', 'ALPHA_UNDER',
+ 'CROSS', 'GAMMA_CROSS', 'MULTIPLY', 'OVER_DROP',
+ 'PLUGIN',
+ 'WIPE', 'GLOW', 'TRANSFORM', 'COLOR',
+ 'MULTICAM', 'SPEED')
def draw(self, context):
layout = self.layout
@@ -638,34 +733,37 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel):
col = layout.column()
col.label(text="Video:")
col.prop(strip, "strobe")
+
+ row = layout.row()
+ row.label(text="Flip:")
+ row.prop(strip, "flip_x", text="X")
+ row.prop(strip, "flip_y", text="Y")
+
+ col = layout.column()
+ col.prop(strip, "reverse_frames", text="Backwards")
col.prop(strip, "de_interlace")
col = layout.column()
col.label(text="Colors:")
+ col.prop(strip, "color_saturation", text="Saturation")
col.prop(strip, "multiply_colors", text="Multiply")
col.prop(strip, "premultiply")
col.prop(strip, "convert_float")
- col = layout.column()
- col.label(text="Flip:")
- col.prop(strip, "flip_x", text="X")
- col.prop(strip, "flip_y", text="Y")
- col.prop(strip, "reverse_frames", text="Backwards")
-
layout.prop(strip, "use_color_balance")
- if strip.color_balance: # TODO - need to add this somehow
+ if strip.use_color_balance and strip.color_balance: # TODO - need to add this somehow
row = layout.row()
row.active = strip.use_color_balance
col = row.column()
- col.template_color_wheel(strip.color_balance, "lift", value_slider=False)
+ col.template_color_wheel(strip.color_balance, "lift", value_slider=False, cubic=True)
col.row().prop(strip.color_balance, "lift")
col.prop(strip.color_balance, "inverse_lift", text="Inverse")
col = row.column()
- col.template_color_wheel(strip.color_balance, "gamma", value_slider=False)
+ col.template_color_wheel(strip.color_balance, "gamma", value_slider=False, lock_luminosity=True, cubic=True)
col.row().prop(strip.color_balance, "gamma")
col.prop(strip.color_balance, "inverse_gamma", text="Inverse")
col = row.column()
- col.template_color_wheel(strip.color_balance, "gain", value_slider=False)
+ col.template_color_wheel(strip.color_balance, "gain", value_slider=False, lock_luminosity=True, cubic=True)
col.row().prop(strip.color_balance, "gain")
col.prop(strip.color_balance, "inverse_gain", text="Inverse")
@@ -681,7 +779,7 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel):
if not strip:
return False
- return strip.type in ('MOVIE', 'IMAGE', 'SCENE', 'META')
+ return strip.type in ('MOVIE', 'IMAGE', 'SCENE', 'META', 'MULTICAM')
def draw_header(self, context):
strip = act_strip(context)
@@ -695,9 +793,12 @@ class SEQUENCER_PT_proxy(SequencerButtonsPanel):
flow = layout.column_flow()
flow.prop(strip, "proxy_custom_directory")
+ flow.prop(strip, "proxy_custom_file")
if strip.proxy: # TODO - need to add this somehow
- flow.prop(strip.proxy, "directory")
- flow.prop(strip.proxy, "file")
+ if strip.proxy_custom_directory and not strip.proxy_custom_file:
+ flow.prop(strip.proxy, "directory")
+ if strip.proxy_custom_file:
+ flow.prop(strip.proxy, "filepath")
class SEQUENCER_PT_view(SequencerButtonsPanel_Output):
@@ -709,9 +810,12 @@ class SEQUENCER_PT_view(SequencerButtonsPanel_Output):
st = context.space_data
col = layout.column()
- col.prop(st, "draw_overexposed") # text="Zebra"
- col.prop(st, "draw_safe_margin")
-
+ if st.display_mode == 'IMAGE':
+ col.prop(st, "draw_overexposed") # text="Zebra"
+ col.prop(st, "draw_safe_margin")
+ if st.display_mode == 'WAVEFORM':
+ col.prop(st, "separate_color_preview")
+ col.prop(st, "proxy_render_size")
classes = [
SEQUENCER_HT_header, # header/menu classes
@@ -724,9 +828,11 @@ classes = [
SEQUENCER_MT_strip,
SEQUENCER_PT_edit, # sequencer panels
+ SEQUENCER_PT_preview,
SEQUENCER_PT_effect,
SEQUENCER_PT_input_movie,
SEQUENCER_PT_input_image,
+ SEQUENCER_PT_input_secondary,
SEQUENCER_PT_sound,
SEQUENCER_PT_scene,
SEQUENCER_PT_filter,
diff --git a/release/scripts/ui/space_text.py b/release/scripts/ui/space_text.py
index 3a789566a61..692f1581bd6 100644
--- a/release/scripts/ui/space_text.py
+++ b/release/scripts/ui/space_text.py
@@ -54,19 +54,19 @@ class TEXT_HT_header(bpy.types.Header):
if text:
row = layout.row()
row.operator("text.run_script")
+
+ row = layout.row()
+ row.active = text.name.endswith(".py")
row.prop(text, "use_module")
row = layout.row()
- if text.filename != "":
+ if text.filepath:
if text.dirty:
- row.label(text="File: *%s (unsaved)" % text.filename)
+ row.label(text="File: *%s (unsaved)" % text.filepath)
else:
- row.label(text="File: %s" % text.filename)
+ row.label(text="File: %s" % text.filepath)
else:
- if text.library:
- row.label(text="Text: External")
- else:
- row.label(text="Text: Internal")
+ row.label(text="Text: External" if text.library else "Text: Internal")
class TEXT_PT_properties(bpy.types.Panel):
@@ -147,7 +147,7 @@ class TEXT_MT_text(bpy.types.Menu):
layout.operator("text.save")
layout.operator("text.save_as")
- if text.filename != "":
+ if text.filepath:
layout.operator("text.make_internal")
layout.column()
@@ -177,7 +177,7 @@ class TEXT_MT_templates(bpy.types.Menu):
bl_label = "Script Templates"
def draw(self, context):
- self.path_menu(bpy.utils.script_paths("templates"), "text.open")
+ self.path_menu(bpy.utils.script_paths("templates"), "text.open", {"internal": True})
class TEXT_MT_edit_view(bpy.types.Menu):
@@ -274,6 +274,22 @@ class TEXT_MT_edit(bpy.types.Menu):
layout.menu("TEXT_MT_edit_to3d")
+class TEXT_MT_toolbox(bpy.types.Menu):
+ bl_label = ""
+
+ def draw(self, context):
+ layout = self.layout
+ layout.operator_context = 'INVOKE_DEFAULT'
+
+ layout.operator("text.cut")
+ layout.operator("text.copy")
+ layout.operator("text.paste")
+
+ layout.separator()
+
+ layout.operator("text.run_script")
+
+
classes = [
TEXT_HT_header,
TEXT_PT_properties,
@@ -285,7 +301,8 @@ classes = [
TEXT_MT_edit_view,
TEXT_MT_edit_select,
TEXT_MT_edit_markers,
- TEXT_MT_edit_to3d]
+ TEXT_MT_edit_to3d,
+ TEXT_MT_toolbox]
def register():
diff --git a/release/scripts/ui/space_time.py b/release/scripts/ui/space_time.py
index 2f2fad59e9f..042e4dbc015 100644
--- a/release/scripts/ui/space_time.py
+++ b/release/scripts/ui/space_time.py
@@ -39,17 +39,17 @@ class TIME_HT_header(bpy.types.Header):
sub.menu("TIME_MT_frame")
sub.menu("TIME_MT_playback")
- layout.prop(scene, "use_preview_range", text="PR")
+ layout.prop(scene, "use_preview_range", text="", toggle=True)
row = layout.row(align=True)
if not scene.use_preview_range:
- row.prop(scene, "start_frame", text="Start")
- row.prop(scene, "end_frame", text="End")
+ row.prop(scene, "frame_start", text="Start")
+ row.prop(scene, "frame_end", text="End")
else:
- row.prop(scene, "preview_range_start_frame", text="Start")
- row.prop(scene, "preview_range_end_frame", text="End")
+ row.prop(scene, "preview_range_frame_start", text="Start")
+ row.prop(scene, "preview_range_frame_end", text="End")
- layout.prop(scene, "current_frame", text="")
+ layout.prop(scene, "frame_current", text="")
layout.separator()
@@ -67,7 +67,7 @@ class TIME_HT_header(bpy.types.Header):
row.operator("screen.frame_jump", text="", icon='FF').end = True
row = layout.row(align=True)
- row.prop(tools, "use_auto_keying", text="", toggle=True, icon='REC')
+ row.prop(tools, "use_auto_keying", text="", toggle=True)
if screen.animation_playing and tools.use_auto_keying:
subsub = row.row()
subsub.prop(tools, "record_with_nla", toggle=True)
@@ -77,7 +77,7 @@ class TIME_HT_header(bpy.types.Header):
layout.separator()
row = layout.row(align=True)
- row.prop_object(scene, "active_keying_set", scene, "keying_sets", text="")
+ row.prop_object(scene, "active_keying_set", scene, "all_keying_sets", text="")
row.operator("anim.keyframe_insert", text="", icon='KEY_HLT')
row.operator("anim.keyframe_delete", text="", icon='KEY_DEHLT')
@@ -100,9 +100,33 @@ class TIME_MT_view(bpy.types.Menu):
layout.separator()
+ layout.menu("TIME_MT_cache")
+
+ layout.separator()
+
layout.operator("marker.camera_bind")
+class TIME_MT_cache(bpy.types.Menu):
+ bl_label = "Cache"
+
+ def draw(self, context):
+ layout = self.layout
+
+ st = context.space_data
+
+ layout.prop(st, "show_cache")
+
+ layout.separator()
+
+ col = layout.column()
+ col.enabled = st.show_cache
+ col.prop(st, "cache_softbody")
+ col.prop(st, "cache_particles")
+ col.prop(st, "cache_cloth")
+ col.prop(st, "cache_smoke")
+
+
class TIME_MT_frame(bpy.types.Menu):
bl_label = "Frame"
@@ -171,6 +195,7 @@ class TIME_MT_autokey(bpy.types.Menu):
classes = [
TIME_HT_header,
TIME_MT_view,
+ TIME_MT_cache,
TIME_MT_frame,
TIME_MT_autokey,
TIME_MT_playback]
diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py
index bea9f80edec..61f759a1d83 100644
--- a/release/scripts/ui/space_userpref.py
+++ b/release/scripts/ui/space_userpref.py
@@ -19,26 +19,34 @@
# <pep8 compliant>
import bpy
import os
-import re
import shutil
def ui_items_general(col, context):
""" General UI Theme Settings (User Interface)
"""
+
row = col.row()
- sub = row.column()
- sub.prop(context, "outline")
- sub.prop(context, "item", slider=True)
- sub = row.column()
- sub.prop(context, "inner", slider=True)
- sub.prop(context, "inner_sel", slider=True)
- sub = row.column()
- sub.prop(context, "text")
- sub.prop(context, "text_sel")
- sub = row.column()
- sub.prop(context, "shaded")
- subsub = sub.column(align=True)
+
+ subsplit = row.split(percentage=0.95)
+
+ padding = subsplit.split(percentage=0.15)
+ colsub = padding.column()
+ colsub = padding.column()
+ colsub.row().prop(context, "outline")
+ colsub.row().prop(context, "item", slider=True)
+ colsub.row().prop(context, "inner", slider=True)
+ colsub.row().prop(context, "inner_sel", slider=True)
+
+ subsplit = row.split(percentage=0.85)
+
+ padding = subsplit.split(percentage=0.15)
+ colsub = padding.column()
+ colsub = padding.column()
+ colsub.row().prop(context, "text")
+ colsub.row().prop(context, "text_sel")
+ colsub.prop(context, "shaded")
+ subsub = colsub.column(align=True)
subsub.active = context.shaded
subsub.prop(context, "shadetop")
subsub.prop(context, "shadedown")
@@ -67,91 +75,6 @@ def opengl_lamp_buttons(column, lamp):
col.active = lamp.enabled
col.prop(lamp, "direction", text="")
-KM_HIERARCHY = [
- ('Window', 'EMPTY', 'WINDOW', []), # file save, window change, exit
- ('Screen', 'EMPTY', 'WINDOW', [ # full screen, undo, screenshot
- ('Screen Editing', 'EMPTY', 'WINDOW', []), # resizing, action corners
- ]),
-
- ('View2D', 'EMPTY', 'WINDOW', []), # view 2d navigation (per region)
- ('View2D Buttons List', 'EMPTY', 'WINDOW', []), # view 2d with buttons navigation
- ('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region)
- ('Grease Pencil', 'EMPTY', 'WINDOW', []), # grease pencil stuff (per region)
-
- ('3D View', 'VIEW_3D', 'WINDOW', [ # view 3d navigation and generic stuff (select, transform)
- ('Object Mode', 'EMPTY', 'WINDOW', []),
- ('Mesh', 'EMPTY', 'WINDOW', []),
- ('Curve', 'EMPTY', 'WINDOW', []),
- ('Armature', 'EMPTY', 'WINDOW', []),
- ('Metaball', 'EMPTY', 'WINDOW', []),
- ('Lattice', 'EMPTY', 'WINDOW', []),
- ('Font', 'EMPTY', 'WINDOW', []),
-
- ('Pose', 'EMPTY', 'WINDOW', []),
-
- ('Vertex Paint', 'EMPTY', 'WINDOW', []),
- ('Weight Paint', 'EMPTY', 'WINDOW', []),
- ('Face Mask', 'EMPTY', 'WINDOW', []),
- ('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
- ('Sculpt', 'EMPTY', 'WINDOW', []),
-
- ('Armature Sketch', 'EMPTY', 'WINDOW', []),
- ('Particle', 'EMPTY', 'WINDOW', []),
-
- ('Object Non-modal', 'EMPTY', 'WINDOW', []), # mode change
-
- ('3D View Generic', 'VIEW_3D', 'WINDOW', []) # toolbar and properties
- ]),
-
- ('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region)
- ('Markers', 'EMPTY', 'WINDOW', []), # markers (per region)
- ('Animation', 'EMPTY', 'WINDOW', []), # frame change on click, preview range (per region)
- ('Animation Channels', 'EMPTY', 'WINDOW', []),
- ('Graph Editor', 'GRAPH_EDITOR', 'WINDOW', [
- ('Graph Editor Generic', 'GRAPH_EDITOR', 'WINDOW', [])
- ]),
- ('Dopesheet', 'DOPESHEET_EDITOR', 'WINDOW', []),
- ('NLA Editor', 'NLA_EDITOR', 'WINDOW', [
- ('NLA Channels', 'NLA_EDITOR', 'WINDOW', []),
- ('NLA Generic', 'NLA_EDITOR', 'WINDOW', [])
- ]),
-
- ('Image', 'IMAGE_EDITOR', 'WINDOW', [
- ('UV Editor', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image
- ('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
- ('Image Generic', 'IMAGE_EDITOR', 'WINDOW', [])
- ]),
-
- ('Timeline', 'TIMELINE', 'WINDOW', []),
- ('Outliner', 'OUTLINER', 'WINDOW', []),
-
- ('Node Editor', 'NODE_EDITOR', 'WINDOW', [
- ('Node Generic', 'NODE_EDITOR', 'WINDOW', [])
- ]),
- ('Sequencer', 'SEQUENCE_EDITOR', 'WINDOW', []),
- ('Logic Editor', 'LOGIC_EDITOR', 'WINDOW', []),
-
- ('File Browser', 'FILE_BROWSER', 'WINDOW', [
- ('File Browser Main', 'FILE_BROWSER', 'WINDOW', []),
- ('File Browser Buttons', 'FILE_BROWSER', 'WINDOW', [])
- ]),
-
- ('Property Editor', 'PROPERTIES', 'WINDOW', []), # align context menu
-
- ('Script', 'SCRIPTS_WINDOW', 'WINDOW', []),
- ('Text', 'TEXT_EDITOR', 'WINDOW', []),
- ('Console', 'CONSOLE', 'WINDOW', []),
-
- ('View3D Gesture Circle', 'EMPTY', 'WINDOW', []),
- ('Gesture Border', 'EMPTY', 'WINDOW', []),
- ('Standard Modal Map', 'EMPTY', 'WINDOW', []),
- ('Transform Modal Map', 'EMPTY', 'WINDOW', []),
- ('View3D Fly Modal', 'EMPTY', 'WINDOW', []),
- ('View3D Rotate Modal', 'EMPTY', 'WINDOW', []),
- ('View3D Move Modal', 'EMPTY', 'WINDOW', []),
- ('View3D Zoom Modal', 'EMPTY', 'WINDOW', []),
- ]
-
class USERPREF_HT_header(bpy.types.Header):
bl_space_type = 'USER_PREFERENCES'
@@ -165,16 +88,18 @@ class USERPREF_HT_header(bpy.types.Header):
layout.operator_context = 'EXEC_AREA'
layout.operator("wm.save_homefile", text="Save As Default")
+ layout.operator_context = 'INVOKE_DEFAULT'
+
if userpref.active_section == 'INPUT':
- layout.operator_context = 'INVOKE_DEFAULT'
- op = layout.operator("wm.keyconfig_export", "Export Key Configuration...")
- op.path = "keymap.py"
- op = layout.operator("wm.keyconfig_import", "Import Key Configuration...")
- op.path = "keymap.py"
+ op = layout.operator("wm.keyconfig_export")
+ op.filepath = "keymap.py"
+ op = layout.operator("wm.keyconfig_import")
+ op.filepath = "keymap.py"
elif userpref.active_section == 'ADDONS':
- layout.operator_context = 'INVOKE_DEFAULT'
- op = layout.operator("wm.addon_install", "Install Add-On...")
- op.path = "*.py"
+ op = layout.operator("wm.addon_install")
+ op.filepath = "*.py"
+ elif userpref.active_section == 'THEMES':
+ op = layout.operator("ui.reset_default_theme")
class USERPREF_PT_tabs(bpy.types.Panel):
@@ -191,6 +116,26 @@ class USERPREF_PT_tabs(bpy.types.Panel):
layout.prop(userpref, "active_section", expand=True)
+class USERPREF_MT_interaction_presets(bpy.types.Menu):
+ bl_label = "Presets"
+ preset_subdir = "interaction"
+ preset_operator = "script.execute_preset"
+ draw = bpy.types.Menu.draw_preset
+
+
+class USERPREF_MT_splash(bpy.types.Menu):
+ bl_label = "Splash"
+
+ def draw(self, context):
+ layout = self.layout
+ split = layout.split()
+ row = split.row()
+ row.label("")
+ row = split.row()
+ row.label("Interaction:")
+ row.menu("USERPREF_MT_interaction_presets", text=bpy.types.USERPREF_MT_interaction_presets.bl_label)
+
+
class USERPREF_PT_interface(bpy.types.Panel):
bl_space_type = 'USER_PREFERENCES'
bl_label = "Interface"
@@ -217,7 +162,6 @@ class USERPREF_PT_interface(bpy.types.Panel):
col.prop(view, "show_view_name", text="View Name")
col.prop(view, "show_playback_fps", text="Playback FPS")
col.prop(view, "global_scene")
- col.prop(view, "pin_floating_panels")
col.prop(view, "object_origin_size")
col.separator()
@@ -230,6 +174,13 @@ class USERPREF_PT_interface(bpy.types.Panel):
sub.prop(view, "mini_axis_size", text="Size")
sub.prop(view, "mini_axis_brightness", text="Brightness")
+ col.separator()
+ col.separator()
+ col.separator()
+
+ col.label(text="Properties Window:")
+ col.prop(view, "properties_width_check")
+
row.separator()
row.separator()
@@ -280,6 +231,10 @@ class USERPREF_PT_interface(bpy.types.Panel):
col.prop(view, "open_toplevel_delay", text="Top Level")
col.prop(view, "open_sublevel_delay", text="Sub Level")
+ col.separator()
+
+ col.prop(view, "show_splash")
+
class USERPREF_PT_edit(bpy.types.Panel):
bl_space_type = 'USER_PREFERENCES'
@@ -325,13 +280,6 @@ class USERPREF_PT_edit(bpy.types.Panel):
row.separator()
col = row.column()
- col.label(text="Snap:")
- col.prop(edit, "snap_translate", text="Translate")
- col.prop(edit, "snap_rotate", text="Rotate")
- col.prop(edit, "snap_scale", text="Scale")
- col.separator()
- col.separator()
- col.separator()
col.label(text="Grease Pencil:")
col.prop(edit, "grease_pencil_manhattan_distance", text="Manhattan Distance")
col.prop(edit, "grease_pencil_euclidean_distance", text="Euclidean Distance")
@@ -365,7 +313,8 @@ class USERPREF_PT_edit(bpy.types.Panel):
col.separator()
col.label(text="New F-Curve Defaults:")
- col.prop(edit, "new_interpolation_type", text="Interpolation")
+ col.prop(edit, "keyframe_new_interpolation_type", text="Interpolation")
+ col.prop(edit, "keyframe_new_handle_type", text="Handles")
col.prop(edit, "insertkey_xyz_to_rgb", text="XYZ to RGB")
col.separator()
@@ -378,7 +327,21 @@ class USERPREF_PT_edit(bpy.types.Panel):
row.separator()
row.separator()
+ sculpt = context.tool_settings.sculpt
col = row.column()
+ col.label(text="Paint and Sculpt:")
+ col.prop(edit, "sculpt_paint_use_unified_size", text="Unify Size")
+ col.prop(edit, "sculpt_paint_use_unified_strength", text="Unify Strength")
+ row = col.row(align=True)
+ row.label("Overlay Color:")
+ row.prop(edit, "sculpt_paint_overlay_col", text="")
+ col.prop(sculpt, "use_openmp", text="Threaded Sculpt")
+ col.prop(sculpt, "show_brush")
+
+ col.separator()
+ col.separator()
+ col.separator()
+
col.label(text="Duplicate Data:")
col.prop(edit, "duplicate_mesh", text="Mesh")
col.prop(edit, "duplicate_surface", text="Surface")
@@ -423,6 +386,7 @@ class USERPREF_PT_system(bpy.types.Panel):
col.prop(system, "frame_server_port")
col.prop(system, "scrollback", text="Console Scrollback")
col.prop(system, "auto_execute_scripts")
+ col.prop(system, "tabs_as_spaces")
col.separator()
col.separator()
@@ -533,6 +497,36 @@ class USERPREF_PT_theme(bpy.types.Panel):
bl_region_type = 'WINDOW'
bl_show_header = False
+ @staticmethod
+ def _theme_generic(split, themedata):
+
+ row = split.row()
+
+ subsplit = row.split(percentage=0.95)
+
+ padding1 = subsplit.split(percentage=0.15)
+ padding1.column()
+
+ subsplit = row.split(percentage=0.85)
+
+ padding2 = subsplit.split(percentage=0.15)
+ padding2.column()
+
+ colsub_pair = padding1.column(), padding2.column()
+
+ props_type = {}
+
+ for i, prop in enumerate(themedata.rna_type.properties):
+ attr = prop.identifier
+ if attr == "rna_type":
+ continue
+
+ props_type.setdefault((prop.type, prop.subtype), []).append(prop.identifier)
+
+ for props_type, props_ls in sorted(props_type.items()):
+ for i, attr in enumerate(props_ls):
+ colsub_pair[i % 2].row().prop(themedata, attr)
+
def poll(self, context):
userpref = context.user_preferences
return (userpref.active_section == 'THEMES')
@@ -545,6 +539,12 @@ class USERPREF_PT_theme(bpy.types.Panel):
split_themes = layout.split(percentage=0.2)
split_themes.prop(theme, "theme_area", expand=True)
+ split = layout.split(percentage=0.4)
+
+
+ layout.separator()
+ layout.separator()
+
split = split_themes.split()
if theme.theme_area == 'USER_INTERFACE':
@@ -606,6 +606,10 @@ class USERPREF_PT_theme(bpy.types.Panel):
col.label(text="Scroll Bar:")
ui_items_general(col, ui)
+ ui = theme.user_interface.wcol_progress
+ col.label(text="Progress Bar:")
+ ui_items_general(col, ui)
+
ui = theme.user_interface.wcol_list_item
col.label(text="List Item:")
ui_items_general(col, ui)
@@ -614,360 +618,39 @@ class USERPREF_PT_theme(bpy.types.Panel):
col.label(text="State:")
row = col.row()
- sub = row.column()
- sub.prop(ui, "inner_anim")
- sub.prop(ui, "inner_anim_sel")
- sub = row.column()
- sub.prop(ui, "inner_driven")
- sub.prop(ui, "inner_driven_sel")
- sub = row.column()
- sub.prop(ui, "inner_key")
- sub.prop(ui, "inner_key_sel")
- sub = row.column()
- sub.prop(ui, "blend")
- ui = theme.user_interface
- col.separator()
- col.separator()
- col.prop(ui, "icon_file")
+ subsplit = row.split(percentage=0.95)
- layout.separator()
- layout.separator()
+ padding = subsplit.split(percentage=0.15)
+ colsub = padding.column()
+ colsub = padding.column()
+ colsub.row().prop(ui, "inner_anim")
+ colsub.row().prop(ui, "inner_anim_sel")
+ colsub.row().prop(ui, "inner_driven")
+ colsub.row().prop(ui, "inner_driven_sel")
+ subsplit = row.split(percentage=0.85)
- elif theme.theme_area == 'VIEW_3D':
- v3d = theme.view_3d
+ padding = subsplit.split(percentage=0.15)
+ colsub = padding.column()
+ colsub = padding.column()
+ colsub.row().prop(ui, "inner_key")
+ colsub.row().prop(ui, "inner_key_sel")
+ colsub.row().prop(ui, "blend")
- col = split.column()
- col.prop(v3d, "back")
- col.prop(v3d, "button")
- col.prop(v3d, "button_title")
- col.prop(v3d, "button_text")
- col.prop(v3d, "header")
- col = split.column()
- col.prop(v3d, "grid")
- col.prop(v3d, "wire")
- col.prop(v3d, "lamp", slider=True)
- col.prop(v3d, "editmesh_active", slider=True)
-
- col = split.column()
- col.prop(v3d, "object_selected")
- col.prop(v3d, "object_active")
- col.prop(v3d, "object_grouped")
- col.prop(v3d, "object_grouped_active")
- col.prop(v3d, "transform")
-
- col = split.column()
- col.prop(v3d, "vertex")
- col.prop(v3d, "face", slider=True)
- col.prop(v3d, "normal")
- col.prop(v3d, "vertex_normal")
- col.prop(v3d, "bone_solid")
- col.prop(v3d, "bone_pose")
- #col.prop(v3d, "edge") Doesn't seem to work
-
- elif theme.theme_area == 'GRAPH_EDITOR':
- graph = theme.graph_editor
-
- col = split.column()
- col.prop(graph, "back")
- col.prop(graph, "button")
- col.prop(graph, "button_title")
- col.prop(graph, "button_text")
-
- col = split.column()
- col.prop(graph, "header")
- col.prop(graph, "grid")
- col.prop(graph, "list")
- col.prop(graph, "channel_group")
-
- col = split.column()
- col.prop(graph, "active_channels_group")
- col.prop(graph, "dopesheet_channel")
- col.prop(graph, "dopesheet_subchannel")
- col.prop(graph, "vertex")
-
- col = split.column()
- col.prop(graph, "current_frame")
- col.prop(graph, "handle_vertex")
- col.prop(graph, "handle_vertex_select")
+ ui = theme.user_interface
+ col.separator()
col.separator()
- col.prop(graph, "handle_vertex_size")
-
- elif theme.theme_area == 'FILE_BROWSER':
- file_browse = theme.file_browser
-
- col = split.column()
- col.prop(file_browse, "back")
- col.prop(file_browse, "text")
- col.prop(file_browse, "text_hi")
-
- col = split.column()
- col.prop(file_browse, "header")
- col.prop(file_browse, "list")
-
- col = split.column()
- col.prop(file_browse, "selected_file")
- col.prop(file_browse, "tiles")
-
- col = split.column()
- col.prop(file_browse, "active_file")
- col.prop(file_browse, "active_file_text")
-
- elif theme.theme_area == 'NLA_EDITOR':
- nla = theme.nla_editor
-
- col = split.column()
- col.prop(nla, "back")
- col.prop(nla, "button")
- col.prop(nla, "button_title")
-
- col = split.column()
- col.prop(nla, "button_text")
- col.prop(nla, "text")
- col.prop(nla, "header")
-
- col = split.column()
- col.prop(nla, "grid")
- col.prop(nla, "bars")
- col.prop(nla, "bars_selected")
-
- col = split.column()
- col.prop(nla, "strips")
- col.prop(nla, "strips_selected")
- col.prop(nla, "current_frame")
-
- elif theme.theme_area == 'DOPESHEET_EDITOR':
- dope = theme.dopesheet_editor
-
- col = split.column()
- col.prop(dope, "back")
- col.prop(dope, "list")
- col.prop(dope, "text")
- col.prop(dope, "header")
-
- col = split.column()
- col.prop(dope, "grid")
- col.prop(dope, "channels")
- col.prop(dope, "channels_selected")
- col.prop(dope, "channel_group")
-
- col = split.column()
- col.prop(dope, "active_channels_group")
- col.prop(dope, "long_key")
- col.prop(dope, "long_key_selected")
-
- col = split.column()
- col.prop(dope, "current_frame")
- col.prop(dope, "dopesheet_channel")
- col.prop(dope, "dopesheet_subchannel")
-
- elif theme.theme_area == 'IMAGE_EDITOR':
- image = theme.image_editor
-
- col = split.column()
- col.prop(image, "back")
- col.prop(image, "scope_back")
- col.prop(image, "button")
-
- col = split.column()
- col.prop(image, "button_title")
- col.prop(image, "button_text")
-
- col = split.column()
- col.prop(image, "header")
-
- col = split.column()
- col.prop(image, "editmesh_active", slider=True)
-
- elif theme.theme_area == 'SEQUENCE_EDITOR':
- seq = theme.sequence_editor
-
- col = split.column()
- col.prop(seq, "back")
- col.prop(seq, "button")
- col.prop(seq, "button_title")
- col.prop(seq, "button_text")
- col.prop(seq, "text")
-
- col = split.column()
- col.prop(seq, "header")
- col.prop(seq, "grid")
- col.prop(seq, "movie_strip")
- col.prop(seq, "image_strip")
- col.prop(seq, "scene_strip")
-
- col = split.column()
- col.prop(seq, "audio_strip")
- col.prop(seq, "effect_strip")
- col.prop(seq, "plugin_strip")
- col.prop(seq, "transition_strip")
-
- col = split.column()
- col.prop(seq, "meta_strip")
- col.prop(seq, "current_frame")
- col.prop(seq, "keyframe")
- col.prop(seq, "draw_action")
-
- elif theme.theme_area == 'PROPERTIES':
- prop = theme.properties
-
- col = split.column()
- col.prop(prop, "back")
-
- col = split.column()
- col.prop(prop, "title")
-
- col = split.column()
- col.prop(prop, "text")
-
- col = split.column()
- col.prop(prop, "header")
-
- elif theme.theme_area == 'TEXT_EDITOR':
- text = theme.text_editor
-
- col = split.column()
- col.prop(text, "back")
- col.prop(text, "button")
- col.prop(text, "button_title")
- col.prop(text, "button_text")
-
- col = split.column()
- col.prop(text, "text")
- col.prop(text, "text_hi")
- col.prop(text, "header")
- col.prop(text, "line_numbers_background")
-
- col = split.column()
- col.prop(text, "selected_text")
- col.prop(text, "cursor")
- col.prop(text, "syntax_builtin")
- col.prop(text, "syntax_special")
-
- col = split.column()
- col.prop(text, "syntax_comment")
- col.prop(text, "syntax_string")
- col.prop(text, "syntax_numbers")
-
- elif theme.theme_area == 'TIMELINE':
- time = theme.timeline
-
- col = split.column()
- col.prop(time, "back")
- col.prop(time, "text")
-
- col = split.column()
- col.prop(time, "header")
-
- col = split.column()
- col.prop(time, "grid")
-
- col = split.column()
- col.prop(time, "current_frame")
-
- elif theme.theme_area == 'NODE_EDITOR':
- node = theme.node_editor
-
- col = split.column()
- col.prop(node, "back")
- col.prop(node, "button")
- col.prop(node, "button_title")
- col.prop(node, "button_text")
-
- col = split.column()
- col.prop(node, "text")
- col.prop(node, "text_hi")
- col.prop(node, "header")
- col.prop(node, "wires")
-
- col = split.column()
- col.prop(node, "wire_select")
- col.prop(node, "selected_text")
- col.prop(node, "node_backdrop", slider=True)
- col.prop(node, "in_out_node")
-
- col = split.column()
- col.prop(node, "converter_node")
- col.prop(node, "operator_node")
- col.prop(node, "group_node")
-
- elif theme.theme_area == 'LOGIC_EDITOR':
- logic = theme.logic_editor
-
- col = split.column()
- col.prop(logic, "back")
- col.prop(logic, "button")
-
- col = split.column()
- col.prop(logic, "button_title")
- col.prop(logic, "button_text")
-
- col = split.column()
- col.prop(logic, "text")
- col.prop(logic, "header")
-
- col = split.column()
- col.prop(logic, "panel")
-
- elif theme.theme_area == 'OUTLINER':
- out = theme.outliner
-
- col = split.column()
- col.prop(out, "back")
-
- col = split.column()
- col.prop(out, "text")
-
- col = split.column()
- col.prop(out, "text_hi")
-
- col = split.column()
- col.prop(out, "header")
-
- elif theme.theme_area == 'INFO':
- info = theme.info
-
- col = split.column()
- col.prop(info, "back")
-
- col = split.column()
- col.prop(info, "header")
-
- col = split.column()
- col.prop(info, "header_text")
-
- col = split.column()
-
- elif theme.theme_area == 'USER_PREFERENCES':
- prefs = theme.user_preferences
-
- col = split.column()
- col.prop(prefs, "back")
-
- col = split.column()
- col.prop(prefs, "text")
-
- col = split.column()
- col.prop(prefs, "header")
-
- col = split.column()
- col.prop(prefs, "header_text")
- elif theme.theme_area == 'CONSOLE':
- prefs = theme.console
+ split = col.split(percentage=0.93)
+ split.prop(ui, "icon_file")
- col = split.column()
- col.prop(prefs, "back")
- col.prop(prefs, "header")
+ layout.separator()
+ layout.separator()
- col = split.column()
- col.prop(prefs, "line_output")
- col.prop(prefs, "line_input")
- col.prop(prefs, "line_info")
- col.prop(prefs, "line_error")
- col.prop(prefs, "cursor")
+ else:
+ self._theme_generic(split, getattr(theme, theme.theme_area.lower()))
class USERPREF_PT_file(bpy.types.Panel):
@@ -1003,6 +686,7 @@ class USERPREF_PT_file(bpy.types.Panel):
sub.label(text="Scripts:")
sub.label(text="Sounds:")
sub.label(text="Temp:")
+ sub.label(text="Image Editor:")
sub.label(text="Animation Player:")
sub = col1.column()
@@ -1014,6 +698,7 @@ class USERPREF_PT_file(bpy.types.Panel):
sub.prop(paths, "python_scripts_directory", text="")
sub.prop(paths, "sounds_directory", text="")
sub.prop(paths, "temporary_directory", text="")
+ sub.prop(paths, "image_editor", text="")
subsplit = sub.split(percentage=0.3)
subsplit.prop(paths, "animation_player_preset", text="")
subsplit.prop(paths, "animation_player", text="")
@@ -1038,202 +723,29 @@ class USERPREF_PT_file(bpy.types.Panel):
sub.enabled = paths.auto_save_temporary_files
sub.prop(paths, "auto_save_time", text="Timer (mins)")
+from space_userpref_keymap import InputKeyMapPanel
+
-class USERPREF_PT_input(bpy.types.Panel):
+class USERPREF_PT_input(InputKeyMapPanel):
bl_space_type = 'USER_PREFERENCES'
bl_label = "Input"
- bl_region_type = 'WINDOW'
- bl_show_header = False
def poll(self, context):
userpref = context.user_preferences
return (userpref.active_section == 'INPUT')
- def draw_entry(self, kc, entry, col, level=0):
- idname, spaceid, regionid, children = entry
-
- km = kc.find_keymap(idname, space_type=spaceid, region_type=regionid)
-
- if km:
- self.draw_km(kc, km, children, col, level)
-
- def indented_layout(self, layout, level):
- indentpx = 16
- if level == 0:
- level = 0.0001 # Tweak so that a percentage of 0 won't split by half
- indent = level * indentpx / bpy.context.region.width
-
- split = layout.split(percentage=indent)
- col = split.column()
- col = split.column()
- return col
-
- def draw_km(self, kc, km, children, layout, level):
- km = km.active()
-
- layout.set_context_pointer("keymap", km)
-
- col = self.indented_layout(layout, level)
-
- row = col.row()
- row.prop(km, "children_expanded", text="", no_bg=True)
- row.label(text=km.name)
-
- row.label()
- row.label()
-
- if km.modal:
- row.label(text="", icon='LINKED')
- if km.user_defined:
- op = row.operator("wm.keymap_restore", text="Restore")
- else:
- op = row.operator("wm.keymap_edit", text="Edit")
-
- if km.children_expanded:
- if children:
- # Put the Parent key map's entries in a 'global' sub-category
- # equal in hierarchy to the other children categories
- subcol = self.indented_layout(col, level + 1)
- subrow = subcol.row()
- subrow.prop(km, "items_expanded", text="", no_bg=True)
- subrow.label(text="%s (Global)" % km.name)
- else:
- km.items_expanded = True
-
- # Key Map items
- if km.items_expanded:
- for kmi in km.items:
- self.draw_kmi(kc, km, kmi, col, level + 1)
-
- # "Add New" at end of keymap item list
- col = self.indented_layout(col, level + 1)
- subcol = col.split(percentage=0.2).column()
- subcol.active = km.user_defined
- op = subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
-
- col.separator()
-
- # Child key maps
- if children:
- subcol = col.column()
- row = subcol.row()
-
- for entry in children:
- self.draw_entry(kc, entry, col, level + 1)
-
- def draw_kmi(self, kc, km, kmi, layout, level):
- map_type = kmi.map_type
-
- col = self.indented_layout(layout, level)
-
- if km.user_defined:
- col = col.column(align=True)
- box = col.box()
- else:
- box = col.column()
-
- split = box.split(percentage=0.05)
-
- # header bar
- row = split.row()
- row.prop(kmi, "expanded", text="", no_bg=True)
-
- row = split.row()
- row.enabled = km.user_defined
- row.prop(kmi, "active", text="", no_bg=True)
-
- if km.modal:
- row.prop(kmi, "propvalue", text="")
- else:
- row.label(text=kmi.name)
-
- row = split.row()
- row.enabled = km.user_defined
- row.prop(kmi, "map_type", text="")
- if map_type == 'KEYBOARD':
- row.prop(kmi, "type", text="", full_event=True)
- elif map_type == 'MOUSE':
- row.prop(kmi, "type", text="", full_event=True)
- elif map_type == 'TWEAK':
- subrow = row.row()
- subrow.prop(kmi, "type", text="")
- subrow.prop(kmi, "value", text="")
- elif map_type == 'TIMER':
- row.prop(kmi, "type", text="")
- else:
- row.label()
-
- if kmi.id:
- op = row.operator("wm.keyitem_restore", text="", icon='BACK')
- op.item_id = kmi.id
- op = row.operator("wm.keyitem_remove", text="", icon='X')
- op.item_id = kmi.id
-
- # Expanded, additional event settings
- if kmi.expanded:
- box = col.box()
-
- box.enabled = km.user_defined
-
- if map_type not in ('TEXTINPUT', 'TIMER'):
- split = box.split(percentage=0.4)
- sub = split.row()
-
- if km.modal:
- sub.prop(kmi, "propvalue", text="")
- else:
- sub.prop(kmi, "idname", text="")
-
- sub = split.column()
- subrow = sub.row(align=True)
-
- if map_type == 'KEYBOARD':
- subrow.prop(kmi, "type", text="", event=True)
- subrow.prop(kmi, "value", text="")
- elif map_type == 'MOUSE':
- subrow.prop(kmi, "type", text="")
- subrow.prop(kmi, "value", text="")
-
- subrow = sub.row()
- subrow.scale_x = 0.75
- subrow.prop(kmi, "any")
- subrow.prop(kmi, "shift")
- subrow.prop(kmi, "ctrl")
- subrow.prop(kmi, "alt")
- subrow.prop(kmi, "oskey", text="Cmd")
- subrow.prop(kmi, "key_modifier", text="", event=True)
-
- def display_properties(properties, title=None):
- box.separator()
- if title:
- box.label(text=title)
- flow = box.column_flow(columns=2)
- for pname in dir(properties):
- if not properties.is_property_hidden(pname):
- value = eval("properties." + pname)
- if isinstance(value, bpy.types.OperatorProperties):
- display_properties(value, title=pname)
- else:
- flow.prop(properties, pname)
-
- # Operator properties
- props = kmi.properties
- if props is not None:
- display_properties(props)
-
- # Modal key maps attached to this operator
- if not km.modal:
- kmm = kc.find_keymap_modal(kmi.idname)
- if kmm:
- self.draw_km(kc, kmm, None, layout, level + 1)
- layout.set_context_pointer("keymap", km)
-
def draw_input_prefs(self, inputs, layout):
# General settings
row = layout.row()
col = row.column()
sub = col.column()
+ sub.label(text="Presets:")
+ subrow = sub.row(align=True)
+ subrow.menu("USERPREF_MT_interaction_presets", text=bpy.types.USERPREF_MT_interaction_presets.bl_label)
+ subrow.operator("wm.interaction_preset_add", text="", icon='ZOOMIN')
+ sub.separator()
+
sub.label(text="Mouse:")
sub1 = sub.column()
sub1.enabled = (inputs.select_mouse == 'RIGHT')
@@ -1257,8 +769,8 @@ class USERPREF_PT_input(bpy.types.Panel):
sub.row().prop(inputs, "view_rotation", expand=True)
sub.label(text="Zoom Style:")
- sub.row().prop(inputs, "viewport_zoom_style", expand=True)
- if inputs.viewport_zoom_style == 'DOLLY':
+ sub.row().prop(inputs, "zoom_style", text="")
+ if inputs.zoom_style == 'DOLLY':
sub.row().prop(inputs, "zoom_axis", expand=True)
sub.prop(inputs, "invert_zoom_direction")
@@ -1271,50 +783,15 @@ class USERPREF_PT_input(bpy.types.Panel):
#sub.prop(view, "wheel_scroll_lines", text="Scroll Lines")
col.separator()
-
+ ''' not implemented yet
sub = col.column()
sub.label(text="NDOF Device:")
sub.prop(inputs, "ndof_pan_speed", text="Pan Speed")
sub.prop(inputs, "ndof_rotate_speed", text="Orbit Speed")
+ '''
row.separator()
- def draw_filtered(self, kc, layout):
- filter = kc.filter.lower()
-
- for km in kc.keymaps:
- km = km.active()
- layout.set_context_pointer("keymap", km)
-
- filtered_items = [kmi for kmi in km.items if filter in kmi.name.lower()]
-
- if len(filtered_items) != 0:
- col = layout.column()
-
- row = col.row()
- row.label(text=km.name, icon="DOT")
-
- row.label()
- row.label()
-
- if km.user_defined:
- op = row.operator("wm.keymap_restore", text="Restore")
- else:
- op = row.operator("wm.keymap_edit", text="Edit")
-
- for kmi in filtered_items:
- self.draw_kmi(kc, km, kmi, col, 1)
-
- # "Add New" at end of keymap item list
- col = self.indented_layout(layout, 1)
- subcol = col.split(percentage=0.2).column()
- subcol.active = km.user_defined
- op = subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
-
- def draw_hierarchy(self, defkc, layout):
- for entry in KM_HIERARCHY:
- self.draw_entry(defkc, entry, layout)
-
def draw(self, context):
layout = self.layout
@@ -1333,28 +810,7 @@ class USERPREF_PT_input(bpy.types.Panel):
self.draw_input_prefs(inputs, split)
# Keymap Settings
- col = split.column()
- # kc = wm.active_keyconfig
- kc = wm.default_keyconfig
-
- sub = col.column()
-
- subsplit = sub.split()
- subcol = subsplit.column()
- row = subcol.row()
- row.prop_object(wm, "active_keyconfig", wm, "keyconfigs", text="Configuration:")
-
- layout.set_context_pointer("keyconfig", wm.active_keyconfig)
- row.operator("wm.keyconfig_remove", text="", icon='X')
-
- row.prop(kc, "filter", icon="VIEWZOOM")
-
- col.separator()
-
- if kc.filter != "":
- self.draw_filtered(kc, col)
- else:
- self.draw_hierarchy(kc, col)
+ self.draw_keymaps(context, split)
#print("runtime", time.time() - start)
@@ -1369,7 +825,8 @@ class USERPREF_PT_addons(bpy.types.Panel):
userpref = context.user_preferences
return (userpref.active_section == 'ADDONS')
- def _addon_list(self):
+ @staticmethod
+ def _addon_list():
import sys
modules = []
loaded_modules = set()
@@ -1388,22 +845,142 @@ class USERPREF_PT_addons(bpy.types.Panel):
userpref = context.user_preferences
used_ext = {ext.module for ext in userpref.addons}
- col = layout.column()
+ # collect the categories that can be filtered on
+ addons = [(mod, addon_info_get(mod)) for mod in self._addon_list()]
+
+ cats = {info["category"] for mod, info in addons}
+ cats.discard("")
+
+ cats = ["All", "Enabled", "Disabled"] + sorted(cats)
+
+ bpy.types.Scene.EnumProperty(items=[(cat, cat, cat + " addons") for cat in cats],
+ name="Category", attr="addon_filter", description="Filter add-ons by category")
+ bpy.types.Scene.StringProperty(name="Search", attr="addon_search",
+ description="Search within the selected filter")
- for mod in self._addon_list():
- box = col.box()
- row = box.row()
- text = mod.__doc__
- if not text:
- text = mod.__name__
- row.label(text=text)
+ split = layout.split(percentage=0.2)
+ col = split.column()
+ col.prop(context.scene, "addon_filter", text="Filter", expand=True)
+ col.prop(context.scene, "addon_search", text="", icon='VIEWZOOM')
+
+ col = split.column()
+
+ filter = context.scene.addon_filter
+ search = context.scene.addon_search.lower()
+
+ for mod, info in addons:
module_name = mod.__name__
- row.operator("wm.addon_disable" if module_name in used_ext else "wm.addon_enable").module = module_name
+ is_enabled = module_name in used_ext
+
+ # check if add-on should be visible with current filters
+ if (filter == "All") or \
+ (filter == info["category"]) or \
+ (filter == "Enabled" and is_enabled) or \
+ (filter == "Disabled" and not is_enabled):
+
+
+ if search and search not in info["name"].lower():
+ if info["author"]:
+ if search not in info["author"].lower():
+ continue
+ else:
+ continue
+
+ # Addon UI Code
+ box = col.column().box()
+ colsub = box.column()
+ row = colsub.row()
+
+ row.operator("wm.addon_expand", icon='TRIA_DOWN' if info["expanded"] else 'TRIA_RIGHT', emboss=False).module = module_name
+
+ rowsub = row.row()
+ rowsub.active = is_enabled
+ rowsub.label(text=info["name"], icon='ERROR' if info["warning"] else 'BLENDER')
+
+ if is_enabled:
+ row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name
+ else:
+ row.operator("wm.addon_enable", icon='CHECKBOX_DEHLT', text="", emboss=False).module = module_name
+
+ # Expanded UI (only if additional infos are available)
+ if info["expanded"]:
+ if info["description"]:
+ split = colsub.row().split(percentage=0.15)
+ split.label(text='Description:')
+ split.label(text=info["description"])
+ if info["location"]:
+ split = colsub.row().split(percentage=0.15)
+ split.label(text='Location:')
+ split.label(text=info["location"])
+ if info["author"]:
+ split = colsub.row().split(percentage=0.15)
+ split.label(text='Author:')
+ split.label(text=info["author"])
+ if info["version"]:
+ split = colsub.row().split(percentage=0.15)
+ split.label(text='Version:')
+ split.label(text=info["version"])
+ if info["warning"]:
+ split = colsub.row().split(percentage=0.15)
+ split.label(text="Warning:")
+ split.label(text=' ' + info["warning"], icon='ERROR')
+ if info["wiki_url"] or info["tracker_url"]:
+ split = colsub.row().split(percentage=0.15)
+ split.label(text="Internet:")
+ if info["wiki_url"]:
+ split.operator("wm.url_open", text="Link to the Wiki", icon='HELP').url = info["wiki_url"]
+ if info["tracker_url"]:
+ split.operator("wm.url_open", text="Report a Bug", icon='URL').url = info["tracker_url"]
+
+ if info["wiki_url"] and info["tracker_url"]:
+ split.separator()
+ else:
+ split.separator()
+ split.separator()
+
+ # Append missing scripts
+ # First collect scripts that are used but have no script file.
+ module_names = {mod.__name__ for mod, info in addons}
+ missing_modules = {ext for ext in used_ext if ext not in module_names}
+
+ if missing_modules and filter in ("All", "Enabled"):
+ col.column().separator()
+ col.column().label(text="Missing script files")
+
+ module_names = {mod.__name__ for mod, info in addons}
+ for ext in sorted(missing_modules):
+ # Addon UI Code
+ box = col.column().box()
+ colsub = box.column()
+ row = colsub.row()
+
+ row.label(text=ext, icon='ERROR')
+ row.operator("wm.addon_disable").module = ext
from bpy.props import *
+def addon_info_get(mod, info_basis={"name": "", "author": "", "version": "", "blender": "", "location": "", "description": "", "wiki_url": "", "tracker_url": "", "category": "", "warning": "", "expanded": False}):
+ addon_info = getattr(mod, "bl_addon_info", {})
+
+ # avoid re-initializing
+ if "_init" in addon_info:
+ return addon_info
+
+ if not addon_info:
+ mod.bl_addon_info = addon_info
+
+ for key, value in info_basis.items():
+ addon_info.setdefault(key, value)
+
+ if not addon_info["name"]:
+ addon_info["name"] = mod.__name__
+
+ addon_info["_init"] = None
+ return addon_info
+
+
class WM_OT_addon_enable(bpy.types.Operator):
"Enable an addon"
bl_idname = "wm.addon_enable"
@@ -1412,16 +989,24 @@ class WM_OT_addon_enable(bpy.types.Operator):
module = StringProperty(name="Module", description="Module name of the addon to enable")
def execute(self, context):
- import traceback
- ext = context.user_preferences.addons.new()
module_name = self.properties.module
- ext.module = module_name
try:
mod = __import__(module_name)
mod.register()
except:
+ import traceback
traceback.print_exc()
+ return {'CANCELLED'}
+
+ ext = context.user_preferences.addons.new()
+ ext.module = module_name
+
+ # check if add-on is written for current blender version, or raise a warning
+ info = addon_info_get(mod)
+
+ if info.get("blender", (0, 0, 0)) > bpy.app.version:
+ self.report("WARNING','This script was written for a newer version of Blender and might not function (correctly).\nThe script is enabled though.")
return {'FINISHED'}
@@ -1459,20 +1044,18 @@ class WM_OT_addon_disable(bpy.types.Operator):
class WM_OT_addon_install(bpy.types.Operator):
"Install an addon"
bl_idname = "wm.addon_install"
- bl_label = "Install Add-On"
+ bl_label = "Install Add-On..."
module = StringProperty(name="Module", description="Module name of the addon to disable")
- path = StringProperty(name="File Path", description="File path to write file to")
- filename = StringProperty(name="File Name", description="Name of the file")
- directory = StringProperty(name="Directory", description="Directory of the file")
+ filepath = StringProperty(name="File Path", description="File path to write file to")
filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'})
filter_python = BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'})
def execute(self, context):
import traceback
import zipfile
- pyfile = self.properties.path
+ pyfile = self.properties.filepath
path_addons = bpy.utils.script_paths("addons")[-1]
@@ -1483,7 +1066,7 @@ class WM_OT_addon_install(bpy.types.Operator):
#extract the file to "addons"
file_to_extract.extractall(path_addons)
-
+
except:
traceback.print_exc()
return {'CANCELLED'}
@@ -1518,382 +1101,26 @@ class WM_OT_addon_install(bpy.types.Operator):
return {'RUNNING_MODAL'}
-class WM_OT_keyconfig_test(bpy.types.Operator):
- "Test keyconfig for conflicts"
- bl_idname = "wm.keyconfig_test"
- bl_label = "Test Key Configuration for Conflicts"
-
- def testEntry(self, kc, entry, src=None, parent=None):
- result = False
-
- def kmistr(kmi):
- if km.modal:
- s = ["kmi = km.add_modal_item(\'%s\', \'%s\', \'%s\'" % (kmi.propvalue, kmi.type, kmi.value)]
- else:
- s = ["kmi = km.add_item(\'%s\', \'%s\', \'%s\'" % (kmi.idname, kmi.type, kmi.value)]
-
- if kmi.any:
- s.append(", any=True")
- else:
- if kmi.shift:
- s.append(", shift=True")
- if kmi.ctrl:
- s.append(", ctrl=True")
- if kmi.alt:
- s.append(", alt=True")
- if kmi.oskey:
- s.append(", oskey=True")
- if kmi.key_modifier and kmi.key_modifier != 'NONE':
- s.append(", key_modifier=\'%s\'" % kmi.key_modifier)
-
- s.append(")\n")
-
- def export_properties(prefix, properties):
- for pname in dir(properties):
- if not properties.is_property_hidden(pname):
- value = eval("properties.%s" % pname)
- if isinstance(value, bpy.types.OperatorProperties):
- export_properties(prefix + "." + pname, value)
- elif properties.is_property_set(pname):
- value = _string_value(value)
- if value != "":
- s.append(prefix + ".%s = %s\n" % (pname, value))
-
- props = kmi.properties
-
- if props is not None:
- export_properties("kmi.properties", props)
-
- return "".join(s).strip()
-
- idname, spaceid, regionid, children = entry
-
- km = kc.find_keymap(idname, space_type=spaceid, region_type=regionid)
-
- if km:
- km = km.active()
-
- if src:
- for item in km.items:
- if src.compare(item):
- print("===========")
- print(parent.name)
- print(kmistr(src))
- print(km.name)
- print(kmistr(item))
- result = True
-
- for child in children:
- if self.testEntry(kc, child, src, parent):
- result = True
- else:
- for i in range(len(km.items)):
- src = km.items[i]
-
- for child in children:
- if self.testEntry(kc, child, src, km):
- result = True
-
- for j in range(len(km.items) - i - 1):
- item = km.items[j + i + 1]
- if src.compare(item):
- print("===========")
- print(km.name)
- print(kmistr(src))
- print(kmistr(item))
- result = True
-
- for child in children:
- if self.testEntry(kc, child):
- result = True
-
- return result
-
- def testConfig(self, kc):
- result = False
- for entry in KM_HIERARCHY:
- if self.testEntry(kc, entry):
- result = True
- return result
-
- def execute(self, context):
- wm = context.manager
- kc = wm.default_keyconfig
-
- if self.testConfig(kc):
- print("CONFLICT")
-
- return {'FINISHED'}
-
-
-def _string_value(value):
- if isinstance(value, str) or isinstance(value, bool) or isinstance(value, float) or isinstance(value, int):
- result = repr(value)
- elif getattr(value, '__len__', False):
- repr(list(value))
- else:
- print("Export key configuration: can't write ", value)
-
- return result
-
-
-class WM_OT_keyconfig_import(bpy.types.Operator):
- "Import key configuration from a python script"
- bl_idname = "wm.keyconfig_import"
- bl_label = "Import Key Configuration..."
-
- path = StringProperty(name="File Path", description="File path to write file to")
- filename = StringProperty(name="File Name", description="Name of the file")
- directory = StringProperty(name="Directory", description="Directory of the file")
- filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'})
- filter_text = BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'})
- filter_python = BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'})
-
- keep_original = BoolProperty(name="Keep original", description="Keep original file after copying to configuration folder", default=True)
-
- def execute(self, context):
- if not self.properties.path:
- raise Exception("File path not set")
-
- f = open(self.properties.path, "r")
- if not f:
- raise Exception("Could not open file")
-
- name_pattern = re.compile("^kc = wm.add_keyconfig\('(.*)'\)$")
-
- for line in f.readlines():
- match = name_pattern.match(line)
-
- if match:
- config_name = match.groups()[0]
-
- f.close()
-
- path = os.path.split(os.path.split(__file__)[0])[0] # remove ui/space_userpref.py
- path = os.path.join(path, "cfg")
-
- # create config folder if needed
- if not os.path.exists(path):
- os.mkdir(path)
-
- path = os.path.join(path, config_name + ".py")
-
- if self.properties.keep_original:
- shutil.copy(self.properties.path, path)
- else:
- shutil.move(self.properties.path, path)
-
- __import__(config_name)
-
- wm = bpy.context.manager
- wm.active_keyconfig = wm.keyconfigs[config_name]
-
- return {'FINISHED'}
-
- def invoke(self, context, event):
- wm = context.manager
- wm.add_fileselect(self)
- return {'RUNNING_MODAL'}
-
-
-class WM_OT_keyconfig_export(bpy.types.Operator):
- "Export key configuration to a python script"
- bl_idname = "wm.keyconfig_export"
- bl_label = "Export Key Configuration..."
-
- path = StringProperty(name="File Path", description="File path to write file to")
- filename = StringProperty(name="File Name", description="Name of the file")
- directory = StringProperty(name="Directory", description="Directory of the file")
- filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'})
- filter_text = BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'})
- filter_python = BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'})
-
- def execute(self, context):
- if not self.properties.path:
- raise Exception("File path not set")
-
- f = open(self.properties.path, "w")
- if not f:
- raise Exception("Could not open file")
-
- wm = context.manager
- kc = wm.active_keyconfig
-
- if kc.name == 'Blender':
- name = os.path.splitext(os.path.basename(self.properties.path))[0]
- else:
- name = kc.name
-
- f.write("# Configuration %s\n" % name)
-
- f.write("import bpy\n\n")
- f.write("wm = bpy.context.manager\n")
- f.write("kc = wm.add_keyconfig('%s')\n\n" % name)
-
- for km in kc.keymaps:
- km = km.active()
- f.write("# Map %s\n" % km.name)
- f.write("km = kc.add_keymap('%s', space_type='%s', region_type='%s', modal=%s)\n\n" % (km.name, km.space_type, km.region_type, km.modal))
- for kmi in km.items:
- if km.modal:
- f.write("kmi = km.add_modal_item('%s', '%s', '%s'" % (kmi.propvalue, kmi.type, kmi.value))
- else:
- f.write("kmi = km.add_item('%s', '%s', '%s'" % (kmi.idname, kmi.type, kmi.value))
- if kmi.any:
- f.write(", any=True")
- else:
- if kmi.shift:
- f.write(", shift=True")
- if kmi.ctrl:
- f.write(", ctrl=True")
- if kmi.alt:
- f.write(", alt=True")
- if kmi.oskey:
- f.write(", oskey=True")
- if kmi.key_modifier and kmi.key_modifier != 'NONE':
- f.write(", key_modifier='%s'" % kmi.key_modifier)
- f.write(")\n")
-
- def export_properties(prefix, properties):
- for pname in dir(properties):
- if not properties.is_property_hidden(pname):
- value = eval("properties.%s" % pname)
- if isinstance(value, bpy.types.OperatorProperties):
- export_properties(prefix + "." + pname, value)
- elif properties.is_property_set(pname):
- value = _string_value(value)
- if value != "":
- f.write(prefix + ".%s = %s\n" % (pname, value))
-
- props = kmi.properties
-
- if props is not None:
- export_properties("kmi.properties", props)
-
- f.write("\n")
-
- f.close()
-
- return {'FINISHED'}
-
- def invoke(self, context, event):
- wm = context.manager
- wm.add_fileselect(self)
- return {'RUNNING_MODAL'}
-
-
-class WM_OT_keymap_edit(bpy.types.Operator):
- "Edit key map"
- bl_idname = "wm.keymap_edit"
- bl_label = "Edit Key Map"
-
- def execute(self, context):
- wm = context.manager
- km = context.keymap
- km.copy_to_user()
- return {'FINISHED'}
-
-
-class WM_OT_keymap_restore(bpy.types.Operator):
- "Restore key map(s)"
- bl_idname = "wm.keymap_restore"
- bl_label = "Restore Key Map(s)"
-
- all = BoolProperty(attr="all", name="All Keymaps", description="Restore all keymaps to default")
-
- def execute(self, context):
- wm = context.manager
-
- if self.properties.all:
- for km in wm.default_keyconfig.keymaps:
- km.restore_to_default()
- else:
- km = context.keymap
- km.restore_to_default()
-
- return {'FINISHED'}
-
-
-class WM_OT_keyitem_restore(bpy.types.Operator):
- "Restore key map item"
- bl_idname = "wm.keyitem_restore"
- bl_label = "Restore Key Map Item"
-
- item_id = IntProperty(attr="item_id", name="Item Identifier", description="Identifier of the item to remove")
-
- def execute(self, context):
- wm = context.manager
- km = context.keymap
- kmi = km.item_from_id(self.properties.item_id)
-
- km.restore_item_to_default(kmi)
-
- return {'FINISHED'}
-
-
-class WM_OT_keyitem_add(bpy.types.Operator):
- "Add key map item"
- bl_idname = "wm.keyitem_add"
- bl_label = "Add Key Map Item"
-
- def execute(self, context):
- wm = context.manager
- km = context.keymap
- kc = wm.default_keyconfig
-
- if km.modal:
- km.add_modal_item("", 'A', 'PRESS') # kmi
- else:
- km.add_item("none", 'A', 'PRESS') # kmi
-
- # clear filter and expand keymap so we can see the newly added item
- if kc.filter != '':
- kc.filter = ''
- km.items_expanded = True
- km.children_expanded = True
-
- return {'FINISHED'}
-
-
-class WM_OT_keyitem_remove(bpy.types.Operator):
- "Remove key map item"
- bl_idname = "wm.keyitem_remove"
- bl_label = "Remove Key Map Item"
-
- item_id = IntProperty(attr="item_id", name="Item Identifier", description="Identifier of the item to remove")
-
- def execute(self, context):
- wm = context.manager
- km = context.keymap
- kmi = km.item_from_id(self.properties.item_id)
- km.remove_item(kmi)
- return {'FINISHED'}
-
-
-class WM_OT_keyconfig_remove(bpy.types.Operator):
- "Remove key config"
- bl_idname = "wm.keyconfig_remove"
- bl_label = "Remove Key Config"
+class WM_OT_addon_expand(bpy.types.Operator):
+ "Display more information on this add-on"
+ bl_idname = "wm.addon_expand"
+ bl_label = ""
- def poll(self, context):
- wm = context.manager
- return wm.active_keyconfig.user_defined
+ module = StringProperty(name="Module", description="Module name of the addon to expand")
def execute(self, context):
- wm = context.manager
-
- keyconfig = wm.active_keyconfig
-
- module = __import__(keyconfig.name)
-
- os.remove(module.__file__)
-
- compiled_path = module.__file__ + "c" # for .pyc
+ module_name = self.properties.module
- if os.path.exists(compiled_path):
- os.remove(compiled_path)
+ # unlikely to fail, module should have alredy been imported
+ try:
+ mod = __import__(module_name)
+ except:
+ import traceback
+ traceback.print_exc()
+ return {'CANCELLED'}
- wm.remove_keyconfig(keyconfig)
+ info = addon_info_get(mod)
+ info["expanded"] = not info["expanded"]
return {'FINISHED'}
@@ -1908,19 +1135,13 @@ classes = [
USERPREF_PT_input,
USERPREF_PT_addons,
+ USERPREF_MT_interaction_presets,
+ USERPREF_MT_splash,
+
WM_OT_addon_enable,
WM_OT_addon_disable,
WM_OT_addon_install,
-
- WM_OT_keyconfig_export,
- WM_OT_keyconfig_import,
- WM_OT_keyconfig_test,
- WM_OT_keyconfig_remove,
- WM_OT_keymap_edit,
- WM_OT_keymap_restore,
- WM_OT_keyitem_add,
- WM_OT_keyitem_remove,
- WM_OT_keyitem_restore]
+ WM_OT_addon_expand]
def register():
diff --git a/release/scripts/ui/space_userpref_keymap.py b/release/scripts/ui/space_userpref_keymap.py
new file mode 100644
index 00000000000..c93b24d5cb2
--- /dev/null
+++ b/release/scripts/ui/space_userpref_keymap.py
@@ -0,0 +1,812 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+import bpy
+import os
+import re
+import shutil
+
+KM_HIERARCHY = [
+ ('Window', 'EMPTY', 'WINDOW', []), # file save, window change, exit
+ ('Screen', 'EMPTY', 'WINDOW', [ # full screen, undo, screenshot
+ ('Screen Editing', 'EMPTY', 'WINDOW', []), # resizing, action corners
+ ]),
+
+ ('View2D', 'EMPTY', 'WINDOW', []), # view 2d navigation (per region)
+ ('View2D Buttons List', 'EMPTY', 'WINDOW', []), # view 2d with buttons navigation
+ ('Header', 'EMPTY', 'WINDOW', []), # header stuff (per region)
+ ('Grease Pencil', 'EMPTY', 'WINDOW', []), # grease pencil stuff (per region)
+
+ ('3D View', 'VIEW_3D', 'WINDOW', [ # view 3d navigation and generic stuff (select, transform)
+ ('Object Mode', 'EMPTY', 'WINDOW', []),
+ ('Mesh', 'EMPTY', 'WINDOW', []),
+ ('Curve', 'EMPTY', 'WINDOW', []),
+ ('Armature', 'EMPTY', 'WINDOW', []),
+ ('Metaball', 'EMPTY', 'WINDOW', []),
+ ('Lattice', 'EMPTY', 'WINDOW', []),
+ ('Font', 'EMPTY', 'WINDOW', []),
+
+ ('Pose', 'EMPTY', 'WINDOW', []),
+
+ ('Vertex Paint', 'EMPTY', 'WINDOW', []),
+ ('Weight Paint', 'EMPTY', 'WINDOW', []),
+ ('Face Mask', 'EMPTY', 'WINDOW', []),
+ ('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
+ ('Sculpt', 'EMPTY', 'WINDOW', []),
+
+ ('Armature Sketch', 'EMPTY', 'WINDOW', []),
+ ('Particle', 'EMPTY', 'WINDOW', []),
+
+ ('Object Non-modal', 'EMPTY', 'WINDOW', []), # mode change
+
+ ('3D View Generic', 'VIEW_3D', 'WINDOW', []) # toolbar and properties
+ ]),
+
+ ('Frames', 'EMPTY', 'WINDOW', []), # frame navigation (per region)
+ ('Markers', 'EMPTY', 'WINDOW', []), # markers (per region)
+ ('Animation', 'EMPTY', 'WINDOW', []), # frame change on click, preview range (per region)
+ ('Animation Channels', 'EMPTY', 'WINDOW', []),
+ ('Graph Editor', 'GRAPH_EDITOR', 'WINDOW', [
+ ('Graph Editor Generic', 'GRAPH_EDITOR', 'WINDOW', [])
+ ]),
+ ('Dopesheet', 'DOPESHEET_EDITOR', 'WINDOW', []),
+ ('NLA Editor', 'NLA_EDITOR', 'WINDOW', [
+ ('NLA Channels', 'NLA_EDITOR', 'WINDOW', []),
+ ('NLA Generic', 'NLA_EDITOR', 'WINDOW', [])
+ ]),
+
+ ('Image', 'IMAGE_EDITOR', 'WINDOW', [
+ ('UV Editor', 'EMPTY', 'WINDOW', []), # image (reverse order, UVEdit before Image
+ ('Image Paint', 'EMPTY', 'WINDOW', []), # image and view3d
+ ('Image Generic', 'IMAGE_EDITOR', 'WINDOW', [])
+ ]),
+
+ ('Timeline', 'TIMELINE', 'WINDOW', []),
+ ('Outliner', 'OUTLINER', 'WINDOW', []),
+
+ ('Node Editor', 'NODE_EDITOR', 'WINDOW', [
+ ('Node Generic', 'NODE_EDITOR', 'WINDOW', [])
+ ]),
+ ('Sequencer', 'SEQUENCE_EDITOR', 'WINDOW', []),
+ ('Logic Editor', 'LOGIC_EDITOR', 'WINDOW', []),
+
+ ('File Browser', 'FILE_BROWSER', 'WINDOW', [
+ ('File Browser Main', 'FILE_BROWSER', 'WINDOW', []),
+ ('File Browser Buttons', 'FILE_BROWSER', 'WINDOW', [])
+ ]),
+
+ ('Property Editor', 'PROPERTIES', 'WINDOW', []), # align context menu
+
+ ('Script', 'SCRIPTS_WINDOW', 'WINDOW', []),
+ ('Text', 'TEXT_EDITOR', 'WINDOW', []),
+ ('Console', 'CONSOLE', 'WINDOW', []),
+
+ ('View3D Gesture Circle', 'EMPTY', 'WINDOW', []),
+ ('Gesture Border', 'EMPTY', 'WINDOW', []),
+ ('Standard Modal Map', 'EMPTY', 'WINDOW', []),
+ ('Transform Modal Map', 'EMPTY', 'WINDOW', []),
+ ('View3D Fly Modal', 'EMPTY', 'WINDOW', []),
+ ('View3D Rotate Modal', 'EMPTY', 'WINDOW', []),
+ ('View3D Move Modal', 'EMPTY', 'WINDOW', []),
+ ('View3D Zoom Modal', 'EMPTY', 'WINDOW', []),
+ ]
+
+
+def _km_exists_in(km, export_keymaps):
+ for km2, kc in export_keymaps:
+ if km2.name == km.name:
+ return True
+ return False
+
+
+def _merge_keymaps(kc1, kc2):
+ """ note: kc1 takes priority over kc2
+ """
+ merged_keymaps = [(km, kc1) for km in kc1.keymaps]
+ if kc1 != kc2:
+ merged_keymaps.extend([(km, kc2) for km in kc2.keymaps if not _km_exists_in(km, merged_keymaps)])
+
+ return merged_keymaps
+
+
+class InputKeyMapPanel(bpy.types.Panel):
+ bl_space_type = 'USER_PREFERENCES'
+ bl_label = "Input"
+ bl_region_type = 'WINDOW'
+ bl_show_header = False
+
+ def draw_entry(self, display_keymaps, entry, col, level=0):
+ idname, spaceid, regionid, children = entry
+
+ for km, kc in display_keymaps:
+ if km.name == idname and km.space_type == spaceid and km.region_type == regionid:
+ self.draw_km(display_keymaps, kc, km, children, col, level)
+
+ '''
+ km = kc.find_keymap(idname, space_type=spaceid, region_type=regionid)
+ if not km:
+ kc = defkc
+ km = kc.find_keymap(idname, space_type=spaceid, region_type=regionid)
+
+ if km:
+ self.draw_km(kc, km, children, col, level)
+ '''
+
+ def indented_layout(self, layout, level):
+ indentpx = 16
+ if level == 0:
+ level = 0.0001 # Tweak so that a percentage of 0 won't split by half
+ indent = level * indentpx / bpy.context.region.width
+
+ split = layout.split(percentage=indent)
+ col = split.column()
+ col = split.column()
+ return col
+
+ def draw_km(self, display_keymaps, kc, km, children, layout, level):
+ km = km.active()
+
+ layout.set_context_pointer("keymap", km)
+
+ col = self.indented_layout(layout, level)
+
+ row = col.row()
+ row.prop(km, "children_expanded", text="", emboss=False)
+ row.label(text=km.name)
+
+ row.label()
+ row.label()
+
+ if km.modal:
+ row.label(text="", icon='LINKED')
+ if km.user_defined:
+ op = row.operator("wm.keymap_restore", text="Restore")
+ else:
+ op = row.operator("wm.keymap_edit", text="Edit")
+
+ if km.children_expanded:
+ if children:
+ # Put the Parent key map's entries in a 'global' sub-category
+ # equal in hierarchy to the other children categories
+ subcol = self.indented_layout(col, level + 1)
+ subrow = subcol.row()
+ subrow.prop(km, "items_expanded", text="", emboss=False)
+ subrow.label(text="%s (Global)" % km.name)
+ else:
+ km.items_expanded = True
+
+ # Key Map items
+ if km.items_expanded:
+ for kmi in km.items:
+ self.draw_kmi(display_keymaps, kc, km, kmi, col, level + 1)
+
+ # "Add New" at end of keymap item list
+ col = self.indented_layout(col, level + 1)
+ subcol = col.split(percentage=0.2).column()
+ subcol.enabled = km.user_defined
+ op = subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
+
+ col.separator()
+
+ # Child key maps
+ if children:
+ subcol = col.column()
+ row = subcol.row()
+
+ for entry in children:
+ self.draw_entry(display_keymaps, entry, col, level + 1)
+
+ def draw_kmi(self, display_keymaps, kc, km, kmi, layout, level):
+ map_type = kmi.map_type
+
+ col = self.indented_layout(layout, level)
+
+ if km.user_defined:
+ col = col.column(align=True)
+ box = col.box()
+ else:
+ box = col.column()
+
+ split = box.split(percentage=0.05)
+
+ # header bar
+ row = split.row()
+ row.prop(kmi, "expanded", text="", emboss=False)
+
+ row = split.row()
+ row.enabled = km.user_defined
+ row.prop(kmi, "active", text="", emboss=False)
+
+ if km.modal:
+ row.prop(kmi, "propvalue", text="")
+ else:
+ row.label(text=kmi.name)
+
+ row = split.row()
+ row.enabled = km.user_defined
+ row.prop(kmi, "map_type", text="")
+ if map_type == 'KEYBOARD':
+ row.prop(kmi, "type", text="", full_event=True)
+ elif map_type == 'MOUSE':
+ row.prop(kmi, "type", text="", full_event=True)
+ elif map_type == 'TWEAK':
+ subrow = row.row()
+ subrow.prop(kmi, "type", text="")
+ subrow.prop(kmi, "value", text="")
+ elif map_type == 'TIMER':
+ row.prop(kmi, "type", text="")
+ else:
+ row.label()
+
+ if kmi.id:
+ op = row.operator("wm.keyitem_restore", text="", icon='BACK')
+ op.item_id = kmi.id
+ op = row.operator("wm.keyitem_remove", text="", icon='X')
+ op.item_id = kmi.id
+
+ # Expanded, additional event settings
+ if kmi.expanded:
+ box = col.box()
+
+ box.enabled = km.user_defined
+
+ if map_type not in ('TEXTINPUT', 'TIMER'):
+ split = box.split(percentage=0.4)
+ sub = split.row()
+
+ if km.modal:
+ sub.prop(kmi, "propvalue", text="")
+ else:
+ sub.prop(kmi, "idname", text="")
+
+ sub = split.column()
+ subrow = sub.row(align=True)
+
+ if map_type == 'KEYBOARD':
+ subrow.prop(kmi, "type", text="", event=True)
+ subrow.prop(kmi, "value", text="")
+ elif map_type == 'MOUSE':
+ subrow.prop(kmi, "type", text="")
+ subrow.prop(kmi, "value", text="")
+
+ subrow = sub.row()
+ subrow.scale_x = 0.75
+ subrow.prop(kmi, "any")
+ subrow.prop(kmi, "shift")
+ subrow.prop(kmi, "ctrl")
+ subrow.prop(kmi, "alt")
+ subrow.prop(kmi, "oskey", text="Cmd")
+ subrow.prop(kmi, "key_modifier", text="", event=True)
+
+ def display_properties(properties, title=None):
+ box.separator()
+ if title:
+ box.label(text=title)
+ flow = box.column_flow(columns=2)
+ for pname in dir(properties):
+ if not properties.is_property_hidden(pname):
+ value = eval("properties." + pname)
+ if isinstance(value, bpy.types.OperatorProperties):
+ display_properties(value, title=pname)
+ else:
+ flow.prop(properties, pname)
+
+ # Operator properties
+ props = kmi.properties
+ if props is not None:
+ display_properties(props)
+
+ # Modal key maps attached to this operator
+ if not km.modal:
+ kmm = kc.find_keymap_modal(kmi.idname)
+ if kmm:
+ self.draw_km(display_keymaps, kc, kmm, None, layout, level + 1)
+ layout.set_context_pointer("keymap", km)
+
+ def draw_filtered(self, display_keymaps, filter, layout):
+ for km, kc in display_keymaps:
+ km = km.active()
+ layout.set_context_pointer("keymap", km)
+
+ filtered_items = [kmi for kmi in km.items if filter in kmi.name.lower()]
+
+ if len(filtered_items) != 0:
+ col = layout.column()
+
+ row = col.row()
+ row.label(text=km.name, icon="DOT")
+
+ row.label()
+ row.label()
+
+ if km.user_defined:
+ op = row.operator("wm.keymap_restore", text="Restore")
+ else:
+ op = row.operator("wm.keymap_edit", text="Edit")
+
+ for kmi in filtered_items:
+ self.draw_kmi(display_keymaps, kc, km, kmi, col, 1)
+
+ # "Add New" at end of keymap item list
+ col = self.indented_layout(layout, 1)
+ subcol = col.split(percentage=0.2).column()
+ subcol.enabled = km.user_defined
+ op = subcol.operator("wm.keyitem_add", text="Add New", icon='ZOOMIN')
+
+ def draw_hierarchy(self, display_keymaps, layout):
+ for entry in KM_HIERARCHY:
+ self.draw_entry(display_keymaps, entry, layout)
+
+ def draw_keymaps(self, context, layout):
+ wm = context.manager
+ kc = wm.active_keyconfig
+ defkc = wm.default_keyconfig
+
+ col = layout.column()
+ sub = col.column()
+
+ subsplit = sub.split()
+ subcol = subsplit.column()
+
+ row = subcol.row()
+ row.prop_object(wm, "active_keyconfig", wm, "keyconfigs", text="Key Config:")
+ layout.set_context_pointer("keyconfig", wm.active_keyconfig)
+ row.operator("wm.keyconfig_remove", text="", icon='X')
+
+ row.prop(context.space_data, "filter", icon="VIEWZOOM")
+
+ col.separator()
+
+ display_keymaps = _merge_keymaps(kc, defkc)
+ if context.space_data.filter != "":
+ filter = context.space_data.filter.lower()
+ self.draw_filtered(display_keymaps, filter, col)
+ else:
+ self.draw_hierarchy(display_keymaps, col)
+
+
+from bpy.props import *
+
+
+class WM_OT_keyconfig_test(bpy.types.Operator):
+ "Test keyconfig for conflicts"
+ bl_idname = "wm.keyconfig_test"
+ bl_label = "Test Key Configuration for Conflicts"
+
+ def testEntry(self, kc, entry, src=None, parent=None):
+ result = False
+
+ def kmistr(kmi):
+ if km.modal:
+ s = ["kmi = km.items.add_modal(\'%s\', \'%s\', \'%s\'" % (kmi.propvalue, kmi.type, kmi.value)]
+ else:
+ s = ["kmi = km.items.add(\'%s\', \'%s\', \'%s\'" % (kmi.idname, kmi.type, kmi.value)]
+
+ if kmi.any:
+ s.append(", any=True")
+ else:
+ if kmi.shift:
+ s.append(", shift=True")
+ if kmi.ctrl:
+ s.append(", ctrl=True")
+ if kmi.alt:
+ s.append(", alt=True")
+ if kmi.oskey:
+ s.append(", oskey=True")
+ if kmi.key_modifier and kmi.key_modifier != 'NONE':
+ s.append(", key_modifier=\'%s\'" % kmi.key_modifier)
+
+ s.append(")\n")
+
+ def export_properties(prefix, properties):
+ for pname in dir(properties):
+ if not properties.is_property_hidden(pname):
+ value = eval("properties.%s" % pname)
+ if isinstance(value, bpy.types.OperatorProperties):
+ export_properties(prefix + "." + pname, value)
+ elif properties.is_property_set(pname):
+ value = _string_value(value)
+ if value != "":
+ s.append(prefix + ".%s = %s\n" % (pname, value))
+
+ props = kmi.properties
+
+ if props is not None:
+ export_properties("kmi.properties", props)
+
+ return "".join(s).strip()
+
+ idname, spaceid, regionid, children = entry
+
+ km = kc.find_keymap(idname, space_type=spaceid, region_type=regionid)
+
+ if km:
+ km = km.active()
+
+ if src:
+ for item in km.items:
+ if src.compare(item):
+ print("===========")
+ print(parent.name)
+ print(kmistr(src))
+ print(km.name)
+ print(kmistr(item))
+ result = True
+
+ for child in children:
+ if self.testEntry(kc, child, src, parent):
+ result = True
+ else:
+ for i in range(len(km.items)):
+ src = km.items[i]
+
+ for child in children:
+ if self.testEntry(kc, child, src, km):
+ result = True
+
+ for j in range(len(km.items) - i - 1):
+ item = km.items[j + i + 1]
+ if src.compare(item):
+ print("===========")
+ print(km.name)
+ print(kmistr(src))
+ print(kmistr(item))
+ result = True
+
+ for child in children:
+ if self.testEntry(kc, child):
+ result = True
+
+ return result
+
+ def testConfig(self, kc):
+ result = False
+ for entry in KM_HIERARCHY:
+ if self.testEntry(kc, entry):
+ result = True
+ return result
+
+ def execute(self, context):
+ wm = context.manager
+ kc = wm.default_keyconfig
+
+ if self.testConfig(kc):
+ print("CONFLICT")
+
+ return {'FINISHED'}
+
+
+def _string_value(value):
+ if isinstance(value, str) or isinstance(value, bool) or isinstance(value, float) or isinstance(value, int):
+ result = repr(value)
+ elif getattr(value, '__len__', False):
+ repr(list(value))
+ else:
+ print("Export key configuration: can't write ", value)
+
+ return result
+
+
+class WM_OT_keyconfig_import(bpy.types.Operator):
+ "Import key configuration from a python script"
+ bl_idname = "wm.keyconfig_import"
+ bl_label = "Import Key Configuration..."
+
+ filepath = StringProperty(name="File Path", description="Filepath to write file to")
+ filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'})
+ filter_text = BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'})
+ filter_python = BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'})
+
+ keep_original = BoolProperty(name="Keep original", description="Keep original file after copying to configuration folder", default=True)
+
+ def execute(self, context):
+ if not self.properties.filepath:
+ raise Exception("Filepath not set")
+
+ f = open(self.properties.filepath, "r")
+ if not f:
+ raise Exception("Could not open file")
+
+ name_pattern = re.compile("^kc = wm.add_keyconfig\('(.*)'\)$")
+
+ for line in f.readlines():
+ match = name_pattern.match(line)
+
+ if match:
+ config_name = match.groups()[0]
+
+ f.close()
+
+ path = os.path.split(os.path.split(__file__)[0])[0] # remove ui/space_userpref.py
+ path = os.path.join(path, "cfg")
+
+ # create config folder if needed
+ if not os.path.exists(path):
+ os.mkdir(path)
+
+ path = os.path.join(path, config_name + ".py")
+
+ if self.properties.keep_original:
+ shutil.copy(self.properties.filepath, path)
+ else:
+ shutil.move(self.properties.filepath, path)
+
+ exec("import " + config_name)
+
+ wm = bpy.context.manager
+ wm.active_keyconfig = wm.keyconfigs[config_name]
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ wm = context.manager
+ wm.add_fileselect(self)
+ return {'RUNNING_MODAL'}
+
+# This operator is also used by interaction presets saving - AddPresetBase
+
+
+class WM_OT_keyconfig_export(bpy.types.Operator):
+ "Export key configuration to a python script"
+ bl_idname = "wm.keyconfig_export"
+ bl_label = "Export Key Configuration..."
+
+ filepath = StringProperty(name="File Path", description="Filepath to write file to")
+ filter_folder = BoolProperty(name="Filter folders", description="", default=True, options={'HIDDEN'})
+ filter_text = BoolProperty(name="Filter text", description="", default=True, options={'HIDDEN'})
+ filter_python = BoolProperty(name="Filter python", description="", default=True, options={'HIDDEN'})
+ kc_name = StringProperty(name="KeyConfig Name", description="Name to save the key config as")
+
+ def execute(self, context):
+ if not self.properties.filepath:
+ raise Exception("Filepath not set")
+
+ f = open(self.properties.filepath, "w")
+ if not f:
+ raise Exception("Could not open file")
+
+ wm = context.manager
+ kc = wm.active_keyconfig
+
+ if self.properties.kc_name != '':
+ name = self.properties.kc_name
+ elif kc.name == 'Blender':
+ name = os.path.splitext(os.path.basename(self.properties.filepath))[0]
+ else:
+ name = kc.name
+
+ f.write("# Configuration %s\n" % name)
+
+ f.write("import bpy\n\n")
+ f.write("wm = bpy.context.manager\n")
+ f.write("kc = wm.add_keyconfig('%s')\n\n" % name)
+
+ # Generate a list of keymaps to export:
+ #
+ # First add all user_defined keymaps (found in inputs.edited_keymaps list),
+ # then add all remaining keymaps from the currently active custom keyconfig.
+ #
+ # This will create a final list of keymaps that can be used as a 'diff' against
+ # the default blender keyconfig, recreating the current setup from a fresh blender
+ # without needing to export keymaps which haven't been edited.
+
+ class FakeKeyConfig():
+ keymaps = []
+ edited_kc = FakeKeyConfig()
+ edited_kc.keymaps.extend(context.user_preferences.inputs.edited_keymaps)
+ # merge edited keymaps with non-default keyconfig, if it exists
+ if kc != wm.default_keyconfig:
+ export_keymaps = _merge_keymaps(edited_kc, kc)
+ else:
+ export_keymaps = _merge_keymaps(edited_kc, edited_kc)
+
+ for km, kc_x in export_keymaps:
+
+ km = km.active()
+
+ f.write("# Map %s\n" % km.name)
+ f.write("km = kc.add_keymap('%s', space_type='%s', region_type='%s', modal=%s)\n\n" % (km.name, km.space_type, km.region_type, km.modal))
+ for kmi in km.items:
+ if km.modal:
+ f.write("kmi = km.items.add_modal('%s', '%s', '%s'" % (kmi.propvalue, kmi.type, kmi.value))
+ else:
+ f.write("kmi = km.items.add('%s', '%s', '%s'" % (kmi.idname, kmi.type, kmi.value))
+ if kmi.any:
+ f.write(", any=True")
+ else:
+ if kmi.shift:
+ f.write(", shift=True")
+ if kmi.ctrl:
+ f.write(", ctrl=True")
+ if kmi.alt:
+ f.write(", alt=True")
+ if kmi.oskey:
+ f.write(", oskey=True")
+ if kmi.key_modifier and kmi.key_modifier != 'NONE':
+ f.write(", key_modifier='%s'" % kmi.key_modifier)
+ f.write(")\n")
+
+ def export_properties(prefix, properties):
+ for pname in dir(properties):
+ if not properties.is_property_hidden(pname):
+ value = eval("properties.%s" % pname)
+ if isinstance(value, bpy.types.OperatorProperties):
+ export_properties(prefix + "." + pname, value)
+ elif properties.is_property_set(pname):
+ value = _string_value(value)
+ if value != "":
+ f.write(prefix + ".%s = %s\n" % (pname, value))
+
+ props = kmi.properties
+
+ if props is not None:
+ export_properties("kmi.properties", props)
+
+ f.write("\n")
+
+ f.close()
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ wm = context.manager
+ wm.add_fileselect(self)
+ return {'RUNNING_MODAL'}
+
+
+class WM_OT_keymap_edit(bpy.types.Operator):
+ "Edit stored key map"
+ bl_idname = "wm.keymap_edit"
+ bl_label = "Edit Key Map"
+
+ def execute(self, context):
+ wm = context.manager
+ km = context.keymap
+ km.copy_to_user()
+ return {'FINISHED'}
+
+
+class WM_OT_keymap_restore(bpy.types.Operator):
+ "Restore key map(s)"
+ bl_idname = "wm.keymap_restore"
+ bl_label = "Restore Key Map(s)"
+
+ all = BoolProperty(attr="all", name="All Keymaps", description="Restore all keymaps to default")
+
+ def execute(self, context):
+ wm = context.manager
+
+ if self.properties.all:
+ for km in wm.default_keyconfig.keymaps:
+ km.restore_to_default()
+ else:
+ km = context.keymap
+ km.restore_to_default()
+
+ return {'FINISHED'}
+
+
+class WM_OT_keyitem_restore(bpy.types.Operator):
+ "Restore key map item"
+ bl_idname = "wm.keyitem_restore"
+ bl_label = "Restore Key Map Item"
+
+ item_id = IntProperty(attr="item_id", name="Item Identifier", description="Identifier of the item to remove")
+
+ def execute(self, context):
+ wm = context.manager
+ km = context.keymap
+ kmi = km.item_from_id(self.properties.item_id)
+
+ km.restore_item_to_default(kmi)
+
+ return {'FINISHED'}
+
+
+class WM_OT_keyitem_add(bpy.types.Operator):
+ "Add key map item"
+ bl_idname = "wm.keyitem_add"
+ bl_label = "Add Key Map Item"
+
+ def execute(self, context):
+ wm = context.manager
+ km = context.keymap
+ kc = wm.default_keyconfig
+
+ if km.modal:
+ km.items.add_modal("", 'A', 'PRESS') # kmi
+ else:
+ km.items.add("none", 'A', 'PRESS') # kmi
+
+ # clear filter and expand keymap so we can see the newly added item
+ if context.space_data.filter != '':
+ context.space_data.filter = ''
+ km.items_expanded = True
+ km.children_expanded = True
+
+ return {'FINISHED'}
+
+
+class WM_OT_keyitem_remove(bpy.types.Operator):
+ "Remove key map item"
+ bl_idname = "wm.keyitem_remove"
+ bl_label = "Remove Key Map Item"
+
+ item_id = IntProperty(attr="item_id", name="Item Identifier", description="Identifier of the item to remove")
+
+ def execute(self, context):
+ wm = context.manager
+ km = context.keymap
+ kmi = km.item_from_id(self.properties.item_id)
+ km.remove_item(kmi)
+ return {'FINISHED'}
+
+
+class WM_OT_keyconfig_remove(bpy.types.Operator):
+ "Remove key config"
+ bl_idname = "wm.keyconfig_remove"
+ bl_label = "Remove Key Config"
+
+ def poll(self, context):
+ wm = context.manager
+ return wm.active_keyconfig.user_defined
+
+ def execute(self, context):
+ wm = context.manager
+
+ keyconfig = wm.active_keyconfig
+
+ module = __import__(keyconfig.name)
+
+ os.remove(module.__file__)
+
+ compiled_path = module.__file__ + "c" # for .pyc
+
+ if os.path.exists(compiled_path):
+ os.remove(compiled_path)
+
+ wm.remove_keyconfig(keyconfig)
+ return {'FINISHED'}
+
+
+classes = [
+ WM_OT_keyconfig_export,
+ WM_OT_keyconfig_import,
+ WM_OT_keyconfig_test,
+ WM_OT_keyconfig_remove,
+ WM_OT_keymap_edit,
+ WM_OT_keymap_restore,
+ WM_OT_keyitem_add,
+ WM_OT_keyitem_remove,
+ WM_OT_keyitem_restore]
+
+
+def register():
+ register = bpy.types.register
+ for cls in classes:
+ register(cls)
+
+
+def unregister():
+ unregister = bpy.types.unregister
+ for cls in classes:
+ unregister(cls)
+
+if __name__ == "__main__":
+ register()
diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py
index 865e132745b..bab3695a0b6 100644
--- a/release/scripts/ui/space_view3d.py
+++ b/release/scripts/ui/space_view3d.py
@@ -32,13 +32,12 @@ class VIEW3D_HT_header(bpy.types.Header):
obj = context.active_object
toolsettings = context.tool_settings
- row = layout.row()
+ row = layout.row(align=True)
row.template_header()
- sub = row.row(align=True)
-
# Menus
if context.area.show_menus:
+ sub = row.row(align=True)
sub.menu("VIEW3D_MT_view")
@@ -54,6 +53,7 @@ class VIEW3D_HT_header(bpy.types.Header):
else:
sub.menu("VIEW3D_MT_object")
+ row = layout.row()
row.template_header_3D()
# do in C for now since these buttons cant be both toggle AND exclusive.
@@ -81,10 +81,6 @@ class VIEW3D_HT_header(bpy.types.Header):
if toolsettings.proportional_editing != 'DISABLED':
row.prop(toolsettings, "proportional_editing_falloff", text="", icon_only=True)
- # paint save
- if mode_string == 'PAINT_TEXTURE':
- row.operator("image.save_dirty", text="Save Edited")
-
# Snap
row = layout.row(align=True)
row.prop(toolsettings, "snap", text="")
@@ -100,8 +96,8 @@ class VIEW3D_HT_header(bpy.types.Header):
# OpenGL render
row = layout.row(align=True)
- row.operator("screen.opengl_render", text="", icon='RENDER_STILL')
- props = row.operator("screen.opengl_render", text="", icon='RENDER_ANIMATION')
+ row.operator("render.opengl", text="", icon='RENDER_STILL')
+ props = row.operator("render.opengl", text="", icon='RENDER_ANIMATION')
props.animation = True
# Pose
@@ -149,7 +145,7 @@ class VIEW3D_MT_transform(bpy.types.Menu):
layout.operator("transform.tosphere", text="To Sphere")
layout.operator("transform.shear", text="Shear")
layout.operator("transform.warp", text="Warp")
- layout.operator("transform.transform", text="Push/Pull").mode = 'PUSHPULL'
+ layout.operator("transform.push_pull", text="Push/Pull")
if context.edit_object and context.edit_object.type == 'ARMATURE':
layout.operator("armature.align")
else:
@@ -211,7 +207,6 @@ class VIEW3D_MT_snap(bpy.types.Menu):
layout.operator("view3d.snap_selected_to_grid", text="Selection to Grid")
layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor")
- layout.operator("view3d.snap_selected_to_center", text="Selection to Origin")
layout.separator()
@@ -254,8 +249,11 @@ class VIEW3D_MT_view(bpy.types.Menu):
layout.operator("view3d.viewnumpad", text="Camera").type = 'CAMERA'
layout.operator("view3d.viewnumpad", text="Top").type = 'TOP'
+ layout.operator("view3d.viewnumpad", text="Bottom").type = 'BOTTOM'
layout.operator("view3d.viewnumpad", text="Front").type = 'FRONT'
+ layout.operator("view3d.viewnumpad", text="Back").type = 'BACK'
layout.operator("view3d.viewnumpad", text="Right").type = 'RIGHT'
+ layout.operator("view3d.viewnumpad", text="Left").type = 'LEFT'
layout.menu("VIEW3D_MT_view_cameras", text="Cameras")
@@ -388,7 +386,7 @@ class VIEW3D_MT_select_object(bpy.types.Menu):
layout.operator("object.select_random", text="Random")
layout.operator("object.select_mirror", text="Mirror")
layout.operator("object.select_by_layer", text="Select All by Layer")
- layout.operator_menu_enum("object.select_by_type", "type", "", text="Select All by Type...")
+ layout.operator_menu_enum("object.select_by_type", "type", text="Select All by Type...")
layout.operator("object.select_camera", text="Select Camera")
layout.separator()
@@ -455,8 +453,8 @@ class VIEW3D_MT_select_particle(bpy.types.Menu):
layout.separator()
- layout.operator("particle.select_first", text="Roots")
- layout.operator("particle.select_last", text="Tips")
+ layout.operator("particle.select_roots", text="Roots")
+ layout.operator("particle.select_tips", text="Tips")
class VIEW3D_MT_select_edit_mesh(bpy.types.Menu):
@@ -475,8 +473,8 @@ class VIEW3D_MT_select_edit_mesh(bpy.types.Menu):
layout.separator()
- layout.operator("mesh.select_random", text="Random...")
- layout.operator("mesh.select_nth", text="Select Nth...")
+ layout.operator("mesh.select_random", text="Random")
+ layout.operator("mesh.select_nth", text="Every N Number of Verts")
layout.operator("mesh.edges_select_sharp", text="Sharp Edges")
layout.operator("mesh.faces_select_linked_flat", text="Linked Flat Faces")
layout.operator("mesh.faces_select_interior", text="Interior Faces")
@@ -486,8 +484,10 @@ class VIEW3D_MT_select_edit_mesh(bpy.types.Menu):
layout.operator("mesh.select_by_number_vertices", text="Triangles").type = 'TRIANGLES'
layout.operator("mesh.select_by_number_vertices", text="Quads").type = 'QUADS'
+ if context.scene.tool_settings.mesh_selection_mode[2] == False:
+ layout.operator("mesh.select_non_manifold", text="Non Manifold")
layout.operator("mesh.select_by_number_vertices", text="Loose Verts/Edges").type = 'OTHER'
- layout.operator("mesh.select_similar", text="Similar...")
+ layout.operator("mesh.select_similar", text="Similar")
layout.separator()
@@ -523,7 +523,7 @@ class VIEW3D_MT_select_edit_curve(bpy.types.Menu):
layout.operator("curve.select_all", text="Select/Deselect All")
layout.operator("curve.select_inverse")
layout.operator("curve.select_random")
- layout.operator("curve.select_every_nth")
+ layout.operator("curve.select_nth", text="Every Nth Number of Points")
layout.separator()
@@ -552,7 +552,7 @@ class VIEW3D_MT_select_edit_surface(bpy.types.Menu):
layout.operator("curve.select_all", text="Select/Deselect All")
layout.operator("curve.select_inverse")
layout.operator("curve.select_random")
- layout.operator("curve.select_every_nth")
+ layout.operator("curve.select_nth", text="Every Nth Number of Points")
layout.separator()
@@ -656,6 +656,7 @@ class VIEW3D_MT_object(bpy.types.Menu):
layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...")
layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframe...")
+ layout.operator("anim.keying_set_active_set", text="Change Keying Set...")
layout.separator()
@@ -677,6 +678,11 @@ class VIEW3D_MT_object(bpy.types.Menu):
layout.separator()
+ layout.menu("VIEW3D_MT_object_game_properties")
+ layout.menu("VIEW3D_MT_object_game_logicbricks")
+
+ layout.separator()
+
layout.operator("object.join_uvs")
layout.operator("object.join")
@@ -705,35 +711,86 @@ class VIEW3D_MT_object_specials(bpy.types.Menu):
def poll(self, context):
# add more special types
- obj = context.object
- return bool(obj and obj.type == 'LAMP')
+ return context.object
def draw(self, context):
layout = self.layout
obj = context.object
- if obj and obj.type == 'LAMP':
+ if obj.type == 'CAMERA':
layout.operator_context = 'INVOKE_REGION_WIN'
- props = layout.operator("wm.context_modal_mouse", text="Spot Size")
- props.path_iter = "selected_editable_objects"
- props.path_item = "data.spot_size"
+ props = layout.operator("wm.context_modal_mouse", text="Camera Lens Angle")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.lens"
+ props.input_scale = 0.1
+
+ if not obj.data.dof_object:
+ #layout.label(text="Test Has DOF obj");
+ props = layout.operator("wm.context_modal_mouse", text="DOF Distance")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.dof_distance"
+ props.input_scale = 0.02
+
+ if obj.type in ('CURVE','TEXT'):
+ layout.operator_context = 'INVOKE_REGION_WIN'
+
+ props = layout.operator("wm.context_modal_mouse", text="Extrude Size")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.extrude"
props.input_scale = 0.01
- props = layout.operator("wm.context_modal_mouse", text="Distance")
- props.path_iter = "selected_editable_objects"
- props.path_item = "data.distance"
- props.input_scale = 0.1
+ props = layout.operator("wm.context_modal_mouse", text="Width Size")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.width"
+ props.input_scale = 0.01
+
+ if obj.type == 'EMPTY':
+ layout.operator_context = 'INVOKE_REGION_WIN'
+
+ props = layout.operator("wm.context_modal_mouse", text="Empty Draw Size")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "empty_draw_size"
+ props.input_scale = 0.01
+
+ if obj.type == 'LAMP':
+ layout.operator_context = 'INVOKE_REGION_WIN'
+
+ props = layout.operator("wm.context_modal_mouse", text="Energy")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.energy"
+
+ if obj.data.type in ('SPOT', 'AREA', 'POINT'):
+ props = layout.operator("wm.context_modal_mouse", text="Falloff Distance")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.distance"
+ props.input_scale = 0.1
+
+ if obj.data.type == 'SPOT':
+ layout.separator()
+ props = layout.operator("wm.context_modal_mouse", text="Spot Size")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.spot_size"
+ props.input_scale = 0.01
+
+ props = layout.operator("wm.context_modal_mouse", text="Spot Blend")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.spot_blend"
+ props.input_scale = -0.01
- props = layout.operator("wm.context_modal_mouse", text="Clip Start")
- props.path_iter = "selected_editable_objects"
- props.path_item = "data.shadow_buffer_clip_start"
- props.input_scale = 0.05
+ props = layout.operator("wm.context_modal_mouse", text="Clip Start")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.shadow_buffer_clip_start"
+ props.input_scale = 0.05
- props = layout.operator("wm.context_modal_mouse", text="Clip End")
- props.path_iter = "selected_editable_objects"
- props.path_item = "data.shadow_buffer_clip_end"
- props.input_scale = 0.05
+ props = layout.operator("wm.context_modal_mouse", text="Clip End")
+ props.data_path_iter = "selected_editable_objects"
+ props.data_path_item = "data.shadow_buffer_clip_end"
+ props.input_scale = 0.05
+
+ layout.separator()
+
+ props = layout.operator("object.isolate_type_render")
class VIEW3D_MT_object_apply(bpy.types.Menu):
@@ -792,6 +849,7 @@ class VIEW3D_MT_object_constraints(bpy.types.Menu):
layout = self.layout
layout.operator("object.constraint_add_with_targets")
+ layout.operator("object.constraints_copy")
layout.operator("object.constraints_clear")
@@ -834,10 +892,31 @@ class VIEW3D_MT_make_links(bpy.types.Menu):
def draw(self, context):
layout = self.layout
- layout.operator_menu_enum("object.make_links_scene", "type", text="Objects to Scene...")
- layout.operator_menu_enum("marker.make_links_scene", "type", text="Markers to Scene...")
- layout.operator_enums("object.make_links_data", property="type") # inline
+ layout.operator_menu_enum("object.make_links_scene", "scene", text="Objects to Scene...")
+ layout.operator_menu_enum("marker.make_links_scene", "scene", text="Markers to Scene...")
+ layout.operator_enums("object.make_links_data", "type") # inline
+
+
+class VIEW3D_MT_object_game_properties(bpy.types.Menu):
+ bl_label = "Game Properties"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("object.game_property_copy", text="Replace").operation = 'REPLACE'
+ layout.operator("object.game_property_copy", text="Merge").operation = 'MERGE'
+ layout.operator_menu_enum("object.game_property_copy", "property", text="Copy...")
+ layout.separator()
+ layout.operator("object.game_property_clear")
+
+class VIEW3D_MT_object_game_logicbricks(bpy.types.Menu):
+ bl_label = "Logic Bricks"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator("object.logic_bricks_copy", text="Copy")
# ********** Vertex paint menu **********
@@ -849,6 +928,7 @@ class VIEW3D_MT_paint_vertex(bpy.types.Menu):
layout = self.layout
layout.operator("paint.vertex_color_set")
+ layout.operator("paint.vertex_color_dirt")
class VIEW3D_MT_hook(bpy.types.Menu):
@@ -932,7 +1012,7 @@ class VIEW3D_MT_sculpt(bpy.types.Menu):
layout.prop(sculpt, "lock_y")
layout.prop(sculpt, "lock_z")
layout.separator()
- layout.operator_menu_enum("brush.curve_preset", property="shape")
+ layout.operator_menu_enum("brush.curve_preset", "shape")
layout.separator()
sculpt_tool = brush.sculpt_tool
@@ -991,8 +1071,8 @@ class VIEW3D_MT_particle_specials(bpy.types.Menu):
layout.separator()
if particle_edit.selection_mode == 'POINT':
layout.operator("particle.subdivide")
- layout.operator("particle.select_first")
- layout.operator("particle.select_last")
+ layout.operator("particle.select_roots")
+ layout.operator("particle.select_tips")
layout.operator("particle.remove_doubles")
@@ -1022,6 +1102,7 @@ class VIEW3D_MT_pose(bpy.types.Menu):
layout.operator("anim.keyframe_insert_menu", text="Insert Keyframe...")
layout.operator("anim.keyframe_delete_v3d", text="Delete Keyframe...")
+ layout.operator("anim.keying_set_active_set", text="Change Keying Set...")
layout.separator()
@@ -1142,6 +1223,7 @@ class VIEW3D_MT_pose_constraints(bpy.types.Menu):
layout = self.layout
layout.operator("pose.constraint_add_with_targets", text="Add (With Targets)...")
+ layout.operator("pose.constraints_copy")
layout.operator("pose.constraints_clear")
@@ -1243,15 +1325,15 @@ class VIEW3D_MT_edit_mesh_selection_mode(bpy.types.Menu):
prop = layout.operator("wm.context_set_value", text="Vertex", icon='VERTEXSEL')
prop.value = "(True, False, False)"
- prop.path = "tool_settings.mesh_selection_mode"
+ prop.data_path = "tool_settings.mesh_selection_mode"
prop = layout.operator("wm.context_set_value", text="Edge", icon='EDGESEL')
prop.value = "(False, True, False)"
- prop.path = "tool_settings.mesh_selection_mode"
+ prop.data_path = "tool_settings.mesh_selection_mode"
prop = layout.operator("wm.context_set_value", text="Face", icon='FACESEL')
prop.value = "(False, False, True)"
- prop.path = "tool_settings.mesh_selection_mode"
+ prop.data_path = "tool_settings.mesh_selection_mode"
class VIEW3D_MT_edit_mesh_extrude(bpy.types.Menu):
@@ -1373,7 +1455,7 @@ class VIEW3D_OT_edit_mesh_extrude_move(bpy.types.Operator):
totedge = mesh.total_edge_sel
totvert = mesh.total_vert_sel
- if totface >= 1 or totvert == 1:
+ if totface >= 1:
return bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": "NORMAL", "constraint_axis": [False, False, True]})
elif totedge == 1:
return bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": "NORMAL", "constraint_axis": [True, True, False]})
@@ -1462,12 +1544,14 @@ class VIEW3D_MT_edit_mesh_faces(bpy.types.Menu):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
+ layout.operator("mesh.flip_normals")
# layout.operator("mesh.bevel")
# layout.operator("mesh.bevel")
layout.operator("mesh.edge_face_add")
layout.operator("mesh.fill")
layout.operator("mesh.beautify_fill")
layout.operator("mesh.solidify")
+ layout.operator("mesh.sort_faces")
layout.separator()
@@ -1623,6 +1707,13 @@ class VIEW3D_MT_edit_text(bpy.types.Menu):
layout.menu("VIEW3D_MT_edit_text_chars")
+ layout.separator()
+
+ layout.operator("font.style_toggle", text="Toggle Bold").style = 'BOLD'
+ layout.operator("font.style_toggle", text="Toggle Italic").style = 'ITALIC'
+ layout.operator("font.style_toggle", text="Toggle Underline").style = 'UNDERLINE'
+ layout.operator("font.style_toggle", text="Toggle Small Caps").style = 'SMALL_CAPS'
+
class VIEW3D_MT_edit_text_chars(bpy.types.Menu):
bl_label = "Special Characters"
@@ -1829,7 +1920,7 @@ class VIEW3D_MT_edit_armature_roll(bpy.types.Menu):
# ********** Panel **********
-class VIEW3D_PT_3dview_properties(bpy.types.Panel):
+class VIEW3D_PT_view3d_properties(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "View"
@@ -1845,8 +1936,7 @@ class VIEW3D_PT_3dview_properties(bpy.types.Panel):
scene = context.scene
col = layout.column()
- col.label(text="Camera:")
- col.prop(view, "camera", text="")
+ col.active = view.region_3d.view_perspective != 'CAMERA'
col.prop(view, "lens")
col.label(text="Lock to Object:")
col.prop(view, "lock_object", text="")
@@ -1858,10 +1948,15 @@ class VIEW3D_PT_3dview_properties(bpy.types.Panel):
col.prop(view, "clip_start", text="Start")
col.prop(view, "clip_end", text="End")
- layout.column().prop(scene, "cursor_location", text="3D Cursor:")
+ subcol = col.column()
+ subcol.enabled = not view.lock_camera_and_layers
+ subcol.label(text="Local Camera:")
+ subcol.prop(view, "camera", text="")
+
+ layout.column().prop(view, "cursor_location")
-class VIEW3D_PT_3dview_name(bpy.types.Panel):
+class VIEW3D_PT_view3d_name(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Item"
@@ -1885,7 +1980,7 @@ class VIEW3D_PT_3dview_name(bpy.types.Panel):
row.prop(bone, "name", text="")
-class VIEW3D_PT_3dview_display(bpy.types.Panel):
+class VIEW3D_PT_view3d_display(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Display"
@@ -1903,9 +1998,11 @@ class VIEW3D_PT_3dview_display(bpy.types.Panel):
ob = context.object
col = layout.column()
- col.prop(view, "display_x_axis", text="X Axis")
- col.prop(view, "display_y_axis", text="Y Axis")
- col.prop(view, "display_z_axis", text="Z Axis")
+ col.prop(view, "display_render_override")
+
+ col = layout.column()
+ display_all = not view.display_render_override
+ col.active = display_all
col.prop(view, "outline_selected")
col.prop(view, "all_object_origins")
col.prop(view, "relationship_lines")
@@ -1914,9 +2011,17 @@ class VIEW3D_PT_3dview_display(bpy.types.Panel):
col.prop(mesh, "all_edges")
col = layout.column()
- col.prop(view, "display_floor", text="Grid Floor")
+ col.active = display_all
+ split = col.split(percentage=0.55)
+ split.prop(view, "display_floor", text="Grid Floor")
+
+ row = split.row(align=True)
+ row.prop(view, "display_x_axis", text="X", toggle=True)
+ row.prop(view, "display_y_axis", text="Y", toggle=True)
+ row.prop(view, "display_z_axis", text="Z", toggle=True)
+
sub = col.column(align=True)
- sub.active = view.display_floor
+ sub.active = (display_all and view.display_floor)
sub.prop(view, "grid_lines", text="Lines")
sub.prop(view, "grid_spacing", text="Spacing")
sub.prop(view, "grid_subdivisions", text="Subdivisions")
@@ -1943,7 +2048,7 @@ class VIEW3D_PT_3dview_display(bpy.types.Panel):
row.prop(region, "box_clip")
-class VIEW3D_PT_3dview_meshdisplay(bpy.types.Panel):
+class VIEW3D_PT_view3d_meshdisplay(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Mesh Display"
@@ -1979,7 +2084,7 @@ class VIEW3D_PT_3dview_meshdisplay(bpy.types.Panel):
col.prop(mesh, "draw_face_area")
-class VIEW3D_PT_3dview_curvedisplay(bpy.types.Panel):
+class VIEW3D_PT_view3d_curvedisplay(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Curve Display"
@@ -2029,7 +2134,7 @@ class VIEW3D_PT_background_image(bpy.types.Panel):
layout.active = view.display_background_images
box = layout.box()
row = box.row(align=True)
- row.prop(bg, "show_expanded", text="", no_bg=True)
+ row.prop(bg, "show_expanded", text="", emboss=False)
row.label(text=getattr(bg.image, "name", "Not Set"))
row.operator("view3d.remove_background_image", text="", icon='X').index = i
@@ -2115,6 +2220,7 @@ class VIEW3D_PT_etch_a_ton(bpy.types.Panel):
col.prop(toolsettings, "etch_autoname")
col.prop(toolsettings, "etch_number")
col.prop(toolsettings, "etch_side")
+ col.operator("sketch.convert", text="Convert")
class VIEW3D_PT_context_properties(bpy.types.Panel):
@@ -2192,6 +2298,8 @@ classes = [
VIEW3D_MT_object_showhide,
VIEW3D_MT_make_single_user,
VIEW3D_MT_make_links,
+ VIEW3D_MT_object_game_properties,
+ VIEW3D_MT_object_game_logicbricks,
VIEW3D_MT_hook,
VIEW3D_MT_vertex_group,
@@ -2247,11 +2355,11 @@ classes = [
VIEW3D_MT_armature_specials, # Only as a menu for keybindings
# Panels
- VIEW3D_PT_3dview_properties,
- VIEW3D_PT_3dview_display,
- VIEW3D_PT_3dview_name,
- VIEW3D_PT_3dview_meshdisplay,
- VIEW3D_PT_3dview_curvedisplay,
+ VIEW3D_PT_view3d_properties,
+ VIEW3D_PT_view3d_display,
+ VIEW3D_PT_view3d_name,
+ VIEW3D_PT_view3d_meshdisplay,
+ VIEW3D_PT_view3d_curvedisplay,
VIEW3D_PT_background_image,
VIEW3D_PT_transform_orientations,
VIEW3D_PT_etch_a_ton,
diff --git a/release/scripts/ui/space_view3d_toolbar.py b/release/scripts/ui/space_view3d_toolbar.py
index 6de4ba6ce34..515fa236fc0 100644
--- a/release/scripts/ui/space_view3d_toolbar.py
+++ b/release/scripts/ui/space_view3d_toolbar.py
@@ -19,6 +19,7 @@
# <pep8 compliant>
import bpy
+narrowui = bpy.context.user_preferences.view.properties_width_check
class View3DPanel(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
@@ -42,6 +43,9 @@ class VIEW3D_PT_tools_objectmode(View3DPanel):
col.operator("transform.resize", text="Scale")
col = layout.column(align=True)
+ col.operator("object.origin_set", text="Origin")
+
+ col = layout.column(align=True)
col.label(text="Object:")
col.operator("object.duplicate_move")
col.operator("object.delete")
@@ -500,18 +504,26 @@ class VIEW3D_PT_tools_brush(PaintPanel):
if not context.particle_edit_object:
col = layout.split().column()
- row = col.row()
- if context.sculpt_object and brush:
- defaultbrushes = 8
- elif context.texture_paint_object and brush:
- defaultbrushes = 4
+ if context.sculpt_object and context.tool_settings.sculpt:
+ col.template_ID_preview(settings, "brush", new="brush.add", filter="is_sculpt_brush", rows=3, cols=8)
+ elif context.texture_paint_object and context.tool_settings.image_paint:
+ col.template_ID_preview(settings, "brush", new="brush.add", filter="is_imapaint_brush", rows=3, cols=8)
+ elif context.vertex_paint_object and context.tool_settings.vertex_paint:
+ col.template_ID_preview(settings, "brush", new="brush.add", filter="is_vpaint_brush", rows=3, cols=8)
+ elif context.weight_paint_object and context.tool_settings.weight_paint:
+ col.template_ID_preview(settings, "brush", new="brush.add", filter="is_wpaint_brush", rows=3, cols=8)
else:
- defaultbrushes = 7
+ row = col.row()
- row.template_list(settings, "brushes", settings, "active_brush_index", rows=2, maxrows=defaultbrushes)
+ if context.sculpt_object and brush:
+ defaultbrushes = 8
+ elif context.texture_paint_object and brush:
+ defaultbrushes = 4
+ else:
+ defaultbrushes = 7
- col.template_ID(settings, "brush", new="brush.add")
+ row.template_list(settings, "brushes", settings, "active_brush_index", rows=2, maxrows=defaultbrushes)
# Particle Mode #
@@ -523,9 +535,11 @@ class VIEW3D_PT_tools_brush(PaintPanel):
if settings.tool != 'NONE':
col = layout.column()
col.prop(brush, "size", slider=True)
- col.prop(brush, "strength", slider=True)
+ if settings.tool != 'ADD':
+ col.prop(brush, "strength", slider=True)
if settings.tool == 'ADD':
+ col.prop(brush, "count")
col = layout.column()
col.prop(settings, "add_interpolate")
sub = col.column(align=True)
@@ -541,33 +555,150 @@ class VIEW3D_PT_tools_brush(PaintPanel):
# Sculpt Mode #
elif context.sculpt_object and brush:
+ edit = context.user_preferences.edit
+
col = layout.column()
+
+
col.separator()
row = col.row(align=True)
- row.prop(brush, "size", slider=True)
- if brush.sculpt_tool != 'GRAB':
- row.prop(brush, "use_size_pressure", toggle=True, text="")
+ if edit.sculpt_paint_use_unified_size:
+ if edit.sculpt_paint_unified_lock_brush_size:
+ row.prop(edit, "sculpt_paint_unified_lock_brush_size", toggle=True, text="", icon='LOCKED')
+ row.prop(edit, "sculpt_paint_unified_unprojected_radius", text="Unified Radius", slider=True)
+ else:
+ row.prop(edit, "sculpt_paint_unified_lock_brush_size", toggle=True, text="", icon='UNLOCKED')
+ row.prop(edit, "sculpt_paint_unified_size", text="Unified Radius", slider=True)
+
+ else:
+ if brush.lock_brush_size:
+ row.prop(brush, "lock_brush_size", toggle=True, text="", icon='LOCKED')
+ row.prop(brush, "unprojected_radius", text="Radius", slider=True)
+ else:
+ row.prop(brush, "lock_brush_size", toggle=True, text="", icon='UNLOCKED')
+ row.prop(brush, "size", text="Radius", slider=True)
+
+ row.prop(brush, "use_size_pressure", toggle=True, text="")
+
+
+ if brush.sculpt_tool not in ('SNAKE_HOOK', 'GRAB', 'ROTATE'):
+ col.separator()
row = col.row(align=True)
- row.prop(brush, "strength", slider=True)
+
+ if brush.use_space and brush.sculpt_tool not in ('SMOOTH'):
+ if brush.use_space_atten:
+ row.prop(brush, "use_space_atten", toggle=True, text="", icon='LOCKED')
+ else:
+ row.prop(brush, "use_space_atten", toggle=True, text="", icon='UNLOCKED')
+
+ if edit.sculpt_paint_use_unified_strength:
+ row.prop(edit, "sculpt_paint_unified_strength", text="Unified Strength", slider=True)
+ else:
+ row.prop(brush, "strength", text="Strength", slider=True)
+
row.prop(brush, "use_strength_pressure", text="")
- # XXX - TODO
- #row = col.row(align=True)
- #row.prop(brush, "jitter", slider=True)
- #row.prop(brush, "use_jitter_pressure", toggle=True, text="")
- col = layout.column()
- if brush.sculpt_tool in ('DRAW', 'PINCH', 'INFLATE', 'LAYER', 'CLAY'):
- col.row().prop(brush, "direction", expand=True)
+ if brush.sculpt_tool not in ('SMOOTH'):
+ col.separator()
+
+ row = col.row(align=True)
+ row.prop(brush, "autosmooth_factor", slider=True)
+ row.prop(brush, "use_inverse_smooth_pressure", toggle=True, text="")
+
+
+
+ if brush.sculpt_tool in ('GRAB', 'SNAKE_HOOK'):
+ col.separator()
+
+ row = col.row(align=True)
+ row.prop(brush, "normal_weight", slider=True)
+
+
+
+ if brush.sculpt_tool in ('CREASE', 'BLOB'):
+ col.separator()
+
+ row = col.row(align=True)
+ row.prop(brush, "crease_pinch_factor", slider=True, text="Pinch")
+
+ if brush.sculpt_tool not in ('PINCH', 'INFLATE', 'SMOOTH'):
+ row = col.row(align=True)
+
+ col.separator()
+
+ if brush.use_original_normal:
+ row.prop(brush, "use_original_normal", toggle=True, text="", icon='LOCKED')
+ else:
+ row.prop(brush, "use_original_normal", toggle=True, text="", icon='UNLOCKED')
+
+ row.prop(brush, "sculpt_plane", text="")
+
+ #if brush.sculpt_tool in ('CLAY', 'CLAY_TUBES', 'FLATTEN', 'FILL', 'SCRAPE'):
+ if brush.sculpt_tool in ('CLAY', 'FLATTEN', 'FILL', 'SCRAPE'):
+ row = col.row(align=True)
+ row.prop(brush, "plane_offset", slider=True)
+ row.prop(brush, "use_offset_pressure", text="")
+
+ col.separator()
+
+ row= col.row()
+ row.prop(brush, "use_plane_trim", text="Trim")
+ row= col.row()
+ row.active=brush.use_plane_trim
+ row.prop(brush, "plane_trim", slider=True, text="Distance")
+
+ col.separator()
+
+ row= col.row()
+ row.prop(brush, "use_frontface", text="Front Faces Only")
+
+ #if brush.sculpt_tool in ('DRAW', 'CREASE', 'BLOB', 'LAYER', 'CLAY', 'CLAY_TUBES'):
+ if brush.sculpt_tool in ('DRAW', 'CREASE', 'BLOB', 'LAYER', 'CLAY'):
+ col.separator()
+ col.row().prop(brush, "direction", expand=True)
+ elif brush.sculpt_tool in ('FLATTEN'):
+ col.separator()
+ col.row().prop(brush, "flatten_contrast", expand=True)
+ elif brush.sculpt_tool in ('FILL'):
+ col.separator()
+ col.row().prop(brush, "fill_deepen", expand=True)
+ elif brush.sculpt_tool in ('SCRAPE'):
+ col.separator()
+ col.row().prop(brush, "scrape_peaks", expand=True)
+ elif brush.sculpt_tool in ('INFLATE'):
+ col.separator()
+ col.row().prop(brush, "inflate_deflate", expand=True)
+ elif brush.sculpt_tool in ('PINCH'):
+ col.separator()
+ col.row().prop(brush, "pinch_magnify", expand=True)
+
+
+
+ #if brush.sculpt_tool in ('DRAW', 'CREASE', 'BLOB', 'INFLATE', 'LAYER', 'CLAY', 'CLAY_TUBES'):
+ if brush.sculpt_tool in ('DRAW', 'CREASE', 'BLOB', 'INFLATE', 'LAYER', 'CLAY'):
+ col.separator()
+
+ col.prop(brush, "use_accumulate")
+
- if brush.sculpt_tool in ('DRAW', 'INFLATE', 'LAYER'):
- col.prop(brush, "use_accumulate")
- if brush.sculpt_tool == 'LAYER':
+ if brush.sculpt_tool == 'LAYER':
+ col.separator()
+
+ ob = context.sculpt_object
+ do_persistent = True
+
+ # not supported yet for this case
+ for md in ob.modifiers:
+ if md.type == 'MULTIRES':
+ do_persistent = False
+
+ if do_persistent:
col.prop(brush, "use_persistent")
col.operator("sculpt.set_persistent_base")
@@ -592,6 +723,11 @@ class VIEW3D_PT_tools_brush(PaintPanel):
col.prop(brush, "blend", text="Blend")
+ col = layout.column()
+ col.active = (brush.blend not in ('ERASE_ALPHA', 'ADD_ALPHA'))
+ col.prop(brush, "use_alpha")
+
+
# Weight Paint Mode #
elif context.weight_paint_object and brush:
@@ -650,9 +786,88 @@ class VIEW3D_PT_tools_brush_texture(PaintPanel):
col = layout.column()
- col.template_ID_preview(brush, "texture", new="texture.new", rows=2, cols=4)
+ col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
+
+ if context.sculpt_object:
+ #XXX duplicated from properties_texture.py
+
+ wide_ui = context.region.width > narrowui
+
+
+ col.separator()
+
+
+ col.label(text="Brush Mapping:")
+ row = col.row(align=True)
+ row.prop(tex_slot, "map_mode", expand=True)
+
+ col.separator()
+
+ col = layout.column()
+ col.active = tex_slot.map_mode in ('FIXED')
+ col.label(text="Angle:")
+
+ col = layout.column()
+ if not brush.use_anchor and brush.sculpt_tool not in ('GRAB', 'SNAKE_HOOK', 'THUMB', 'ROTATE') and tex_slot.map_mode in ('FIXED'):
+ col.prop(brush, "texture_angle_source", text="")
+ else:
+ col.prop(brush, "texture_angle_source_no_random", text="")
+
+ #row = col.row(align=True)
+ #row.label(text="Angle:")
+ #row.active = tex_slot.map_mode in ('FIXED', 'TILED')
+
+ #row = col.row(align=True)
+
+ #col = row.column()
+ #col.active = tex_slot.map_mode in ('FIXED')
+ #col.prop(brush, "use_rake", toggle=True, icon='PARTICLEMODE', text="")
+
+ col = layout.column()
+ col.prop(tex_slot, "angle", text="")
+ col.active = tex_slot.map_mode in ('FIXED', 'TILED')
+
+ #col = layout.column()
+ #col.prop(brush, "use_random_rotation")
+ #col.active = (not brush.use_rake) and (not brush.use_anchor) and brush.sculpt_tool not in ('GRAB', 'SNAKE_HOOK', 'THUMB', 'ROTATE') and tex_slot.map_mode in ('FIXED')
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(tex_slot, "offset")
+
+ if wide_ui:
+ col = split.column()
+ else:
+ col.separator()
+
+ col.prop(tex_slot, "size")
+
+ col = layout.column()
+
+ row = col.row(align=True)
+ row.label(text="Sample Bias:")
+ row = col.row(align=True)
+ row.prop(brush, "texture_sample_bias", slider=True, text="")
+
+ row = col.row(align=True)
+ row.label(text="Overlay:")
+ row.active = tex_slot.map_mode in ('FIXED', 'TILED')
+
+ row = col.row(align=True)
+
+ col = row.column()
+
+ if brush.use_texture_overlay:
+ col.prop(brush, "use_texture_overlay", toggle=True, text="", icon='MUTE_IPO_OFF')
+ else:
+ col.prop(brush, "use_texture_overlay", toggle=True, text="", icon='MUTE_IPO_ON')
+
+ col.active = tex_slot.map_mode in ('FIXED', 'TILED')
- col.row().prop(tex_slot, "map_mode", expand=True)
+ col = row.column()
+ col.prop(brush, "texture_overlay_alpha", text="Alpha")
+ col.active = tex_slot.map_mode in ('FIXED', 'TILED') and brush.use_texture_overlay
class VIEW3D_PT_tools_brush_tool(PaintPanel):
@@ -676,15 +891,11 @@ class VIEW3D_PT_tools_brush_tool(PaintPanel):
col = layout.column(align=True)
if context.sculpt_object:
- col.prop(brush, "sculpt_tool", expand=True)
+ col.prop(brush, "sculpt_tool", expand=False, text="")
elif context.texture_paint_object:
- col.prop(brush, "imagepaint_tool", expand=True)
- #col.prop_enum(settings, "tool", 'DRAW')
- #col.prop_enum(settings, "tool", 'SOFTEN')
- #col.prop_enum(settings, "tool", 'CLONE')
- #col.prop_enum(settings, "tool", 'SMEAR')
+ col.prop(brush, "imagepaint_tool", expand=False, text="")
elif context.vertex_paint_object or context.weight_paint_object:
- col.prop(brush, "vertexpaint_tool", expand=True)
+ col.prop(brush, "vertexpaint_tool", expand=False, text="")
class VIEW3D_PT_tools_brush_stroke(PaintPanel):
@@ -705,29 +916,83 @@ class VIEW3D_PT_tools_brush_stroke(PaintPanel):
brush = settings.brush
texture_paint = context.texture_paint_object
+ col = layout.column()
+
if context.sculpt_object:
- if brush.sculpt_tool != 'LAYER':
- layout.prop(brush, "use_anchor")
- layout.prop(brush, "use_rake")
+ col.label(text="Stroke Method:")
+ col.prop(brush, "stroke_method", text="")
+
+ if brush.use_anchor:
+ col.separator()
+ row = col.row()
+ row.prop(brush, "edge_to_edge", "Edge To Edge")
+
+ if brush.use_airbrush:
+ col.separator()
+ row = col.row()
+ row.prop(brush, "rate", text="Rate", slider=True)
+
+ if brush.use_space:
+ col.separator()
+ row = col.row()
+ row.active = brush.use_space
+ row.prop(brush, "spacing", text="Spacing")
+
+ if brush.sculpt_tool not in ('GRAB', 'THUMB', 'SNAKE_HOOK', 'ROTATE') and (not brush.use_anchor) and (not brush.restore_mesh):
+ col = layout.column()
+ col.separator()
- layout.prop(brush, "use_airbrush")
- col = layout.column()
- col.active = brush.use_airbrush
- col.prop(brush, "rate", slider=True)
+ col.prop(brush, "use_smooth_stroke")
+
+ sub = col.column()
+ sub.active = brush.use_smooth_stroke
+ sub.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
+ sub.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
+
+ col.separator()
+
+ row = col.row(align=True)
+ row.prop(brush, "jitter", slider=True)
+ row.prop(brush, "use_jitter_pressure", toggle=True, text="")
+
+ else:
+ row = col.row()
+ row.prop(brush, "use_airbrush")
+
+ row = col.row()
+ row.active = brush.use_airbrush and (not brush.use_space) and (not brush.use_anchor)
+ row.prop(brush, "rate", slider=True)
+
+ col.separator()
+
+ if not texture_paint:
+ row = col.row()
+ row.prop(brush, "use_smooth_stroke")
+
+ col = layout.column()
+ col.active = brush.use_smooth_stroke
+ col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
+ col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
+
+ col.separator()
- if not texture_paint:
- layout.prop(brush, "use_smooth_stroke")
col = layout.column()
- col.active = brush.use_smooth_stroke
- col.prop(brush, "smooth_stroke_radius", text="Radius", slider=True)
- col.prop(brush, "smooth_stroke_factor", text="Factor", slider=True)
+ col.active = (not brush.use_anchor) and (brush.sculpt_tool not in ('GRAB', 'THUMB', 'ROTATE', 'SNAKE_HOOK'))
- layout.prop(brush, "use_space")
- row = layout.row(align=True)
- row.active = brush.use_space
- row.prop(brush, "spacing", text="Distance", slider=True)
- if texture_paint:
- row.prop(brush, "use_spacing_pressure", toggle=True, text="")
+ row = col.row()
+ row.prop(brush, "use_space")
+
+ row = col.row()
+ row.active = brush.use_space
+ row.prop(brush, "spacing", text="Spacing")
+
+ #col.prop(brush, "use_space_atten", text="Adaptive Strength")
+ #col.prop(brush, "use_adaptive_space", text="Adaptive Spacing")
+
+ #col.separator()
+
+ #if texture_paint:
+ # row.prop(brush, "use_spacing_pressure", toggle=True, text="")
class VIEW3D_PT_tools_brush_curve(PaintPanel):
@@ -745,11 +1010,19 @@ class VIEW3D_PT_tools_brush_curve(PaintPanel):
brush = settings.brush
layout.template_curve_mapping(brush, "curve", brush=True)
- layout.operator_menu_enum("brush.curve_preset", property="shape")
+ row = layout.row(align=True)
+ row.operator("brush.curve_preset", icon="SMOOTHCURVE", text="").shape = 'SMOOTH'
+ row.operator("brush.curve_preset", icon="SPHERECURVE", text="").shape = 'ROUND'
+ row.operator("brush.curve_preset", icon="ROOTCURVE", text="").shape = 'ROOT'
+ row.operator("brush.curve_preset", icon="SHARPCURVE", text="").shape = 'SHARP'
+ row.operator("brush.curve_preset", icon="LINCURVE", text="").shape = 'LINE'
+ row.operator("brush.curve_preset", icon="NOCURVE", text="").shape = 'MAX'
+ row.operator("brush.curve_preset", icon="RNDCURVE", text="").shape = 'MID9'
class VIEW3D_PT_sculpt_options(PaintPanel):
bl_label = "Options"
+ bl_default_closed = True
def poll(self, context):
return (context.sculpt_object and context.tool_settings.sculpt)
@@ -757,25 +1030,100 @@ class VIEW3D_PT_sculpt_options(PaintPanel):
def draw(self, context):
layout = self.layout
+ wide_ui = context.region.width > narrowui
+
sculpt = context.tool_settings.sculpt
+ settings = self.paint_settings(context)
+ brush = settings.brush
- col = layout.column()
- col.prop(sculpt, "show_brush")
- col.prop(sculpt, "fast_navigate")
+ split = layout.split()
+
+ col = split.column()
- split = self.layout.split()
+ edit = context.user_preferences.edit
+ col.label(text="Unified Settings:")
+ col.prop(edit, "sculpt_paint_use_unified_size", text="Size")
+ col.prop(edit, "sculpt_paint_use_unified_strength", text="Strength")
+
+ if wide_ui:
+ col = split.column()
+ else:
+ col.separator()
+
+ col.label(text="Lock:")
+ row = col.row(align=True)
+ row.prop(sculpt, "lock_x", text="X", toggle=True)
+ row.prop(sculpt, "lock_y", text="Y", toggle=True)
+ row.prop(sculpt, "lock_z", text="Z", toggle=True)
+
+class VIEW3D_PT_sculpt_symmetry(PaintPanel):
+ bl_label = "Symmetry"
+ bl_default_closed = True
+
+ def poll(self, context):
+ return (context.sculpt_object and context.tool_settings.sculpt)
+
+ def draw(self, context):
+ wide_ui = context.region.width > narrowui
+
+ layout = self.layout
+
+ sculpt = context.tool_settings.sculpt
+ settings = self.paint_settings(context)
+ brush = settings.brush
+
+ split = layout.split()
col = split.column()
- col.label(text="Symmetry:")
+
+ col.label(text="Mirror:")
col.prop(sculpt, "symmetry_x", text="X")
col.prop(sculpt, "symmetry_y", text="Y")
col.prop(sculpt, "symmetry_z", text="Z")
- col = split.column()
- col.label(text="Lock:")
- col.prop(sculpt, "lock_x", text="X")
- col.prop(sculpt, "lock_y", text="Y")
- col.prop(sculpt, "lock_z", text="Z")
+ if wide_ui:
+ col = split.column()
+ else:
+ col.separator()
+
+ col.prop(sculpt, "radial_symm", text="Radial")
+
+ col = layout.column()
+
+ col.separator()
+
+ col.prop(sculpt, "use_symmetry_feather", text="Feather")
+
+class VIEW3D_PT_tools_brush_appearance(PaintPanel):
+ bl_label = "Appearance"
+ bl_default_closed = True
+
+ def poll(self, context):
+ return (context.sculpt_object and context.tool_settings.sculpt) or (context.vertex_paint_object and context.tool_settings.vertex_paint) or (context.weight_paint_object and context.tool_settings.weight_paint) or (context.texture_paint_object and context.tool_settings.image_paint)
+
+ def draw(self, context):
+ layout = self.layout
+
+ sculpt = context.tool_settings.sculpt
+ settings = self.paint_settings(context)
+ brush = settings.brush
+
+ col = layout.column();
+
+ if context.sculpt_object and context.tool_settings.sculpt:
+ #if brush.sculpt_tool in ('DRAW', 'INFLATE', 'CLAY', 'CLAY_TUBES', 'PINCH', 'CREASE', 'BLOB', 'FLATTEN'):
+ if brush.sculpt_tool in ('DRAW', 'INFLATE', 'CLAY', 'PINCH', 'CREASE', 'BLOB', 'FLATTEN'):
+ col.prop(brush, "add_col", text="Add Color")
+ col.prop(brush, "sub_col", text="Substract Color")
+ else:
+ col.prop(brush, "add_col", text="Color")
+
+ col.separator()
+
+ col = layout.column()
+ col.label(text="Icon:")
+ #col.template_ID_preview(brush, "image_icon", open="image.open", filter="is_image_icon", rows=3, cols=8)
+ col.template_ID_preview(brush, "image_icon", open="image.open", rows=3, cols=8)
# ********** default tools for weightpaint ****************
@@ -907,6 +1255,18 @@ class VIEW3D_PT_tools_projectpaint(View3DPanel):
sub = col.column()
sub.prop(ipaint, "seam_bleed")
+ col.label(text="External Editing")
+ row = col.split(align=True, percentage=0.55)
+ row.operator("image.project_edit", text="Quick Edit")
+ row.operator("image.project_apply", text="Apply")
+ row = col.row(align=True)
+ row.prop(ipaint, "screen_grab_size", text="")
+
+ sub = col.column()
+ sub.operator("paint.project_image", text="Apply Camera Image")
+
+ sub.operator("image.save_dirty", text="Save All Edited")
+
class VIEW3D_MT_tools_projectpaint_clone(bpy.types.Menu):
bl_label = "Clone Layer"
@@ -915,7 +1275,7 @@ class VIEW3D_MT_tools_projectpaint_clone(bpy.types.Menu):
layout = self.layout
for i, tex in enumerate(context.active_object.data.uv_textures):
prop = layout.operator("wm.context_set_int", text=tex.name)
- prop.path = "active_object.data.uv_texture_clone_index"
+ prop.data_path = "active_object.data.uv_texture_clone_index"
prop.value = i
@@ -926,7 +1286,7 @@ class VIEW3D_MT_tools_projectpaint_stencil(bpy.types.Menu):
layout = self.layout
for i, tex in enumerate(context.active_object.data.uv_textures):
prop = layout.operator("wm.context_set_int", text=tex.name)
- prop.path = "active_object.data.uv_texture_stencil_index"
+ prop.data_path = "active_object.data.uv_texture_stencil_index"
prop.value = i
@@ -986,12 +1346,15 @@ class VIEW3D_PT_tools_particlemode(View3DPanel):
col.active = pe.editable
col.label(text="Draw:")
col.prop(pe, "draw_step", text="Path Steps")
- if pe.type == 'PARTICLES':
- col.prop(pe, "draw_particles", text="Particles")
- col.prop(pe, "fade_time")
- sub = col.row()
- sub.active = pe.fade_time
- sub.prop(pe, "fade_frames", slider=True)
+ if pe.hair:
+ col.prop(pe, "draw_particles", text="Children")
+ else:
+ if pe.type == 'PARTICLES':
+ col.prop(pe, "draw_particles", text="Particles")
+ col.prop(pe, "fade_time")
+ sub = col.row()
+ sub.active = pe.fade_time
+ sub.prop(pe, "fade_frames", slider=True)
classes = [
@@ -1010,9 +1373,11 @@ classes = [
VIEW3D_PT_tools_posemode_options,
VIEW3D_PT_tools_brush,
VIEW3D_PT_tools_brush_texture,
- VIEW3D_PT_tools_brush_tool,
VIEW3D_PT_tools_brush_stroke,
VIEW3D_PT_tools_brush_curve,
+ VIEW3D_PT_tools_brush_appearance,
+ VIEW3D_PT_tools_brush_tool,
+ VIEW3D_PT_sculpt_symmetry,
VIEW3D_PT_sculpt_options,
VIEW3D_PT_tools_vertexpaint,
VIEW3D_PT_tools_weightpaint_options,