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:
-rw-r--r--release/Makefile209
-rw-r--r--release/VERSION2
-rwxr-xr-xrelease/bin/blender-thumbnailer.py54
-rw-r--r--release/datafiles/blenderbuttonsbin209697 -> 210319 bytes
-rw-r--r--release/datafiles/ctodata.py58
-rwxr-xr-xrelease/datafiles/datatoc.py4
-rw-r--r--release/datafiles/prviconsbin12878 -> 12311 bytes
-rw-r--r--release/datafiles/splash.pngbin218043 -> 174800 bytes
-rw-r--r--release/freedesktop/icons/16x16/blender.pngbin746 -> 845 bytes
-rw-r--r--release/freedesktop/icons/16x16/blender.svg250
-rw-r--r--release/freedesktop/icons/16x16/blender.xcf.bz2bin1405 -> 0 bytes
-rw-r--r--release/freedesktop/icons/22x22/blender.pngbin1219 -> 1236 bytes
-rw-r--r--release/freedesktop/icons/22x22/blender.svg250
-rw-r--r--release/freedesktop/icons/22x22/blender.xcf.bz2bin1792 -> 0 bytes
-rw-r--r--release/freedesktop/icons/32x32/blender.pngbin1929 -> 1955 bytes
-rw-r--r--release/freedesktop/icons/32x32/blender.svg138
-rwxr-xr-xrelease/getversion.py66
-rw-r--r--release/plugins/sequence/color-correction-hsv.c3
-rw-r--r--release/plugins/sequence/color-correction-yuv.c3
-rw-r--r--release/scripts/io/netrender/__init__.py31
-rw-r--r--release/scripts/io/netrender/balancing.py15
-rw-r--r--release/scripts/io/netrender/client.py122
-rw-r--r--release/scripts/io/netrender/master.py64
-rw-r--r--release/scripts/io/netrender/master_html.py90
-rw-r--r--release/scripts/io/netrender/model.py88
-rw-r--r--release/scripts/io/netrender/netrender.js12
-rw-r--r--release/scripts/io/netrender/operators.py134
-rw-r--r--release/scripts/io/netrender/slave.py86
-rw-r--r--release/scripts/io/netrender/thumbnail.py81
-rw-r--r--release/scripts/io/netrender/ui.py173
-rw-r--r--release/scripts/io/netrender/utils.py150
-rw-r--r--release/scripts/io/netrender/versioning.py72
-rw-r--r--release/scripts/keyingsets/keyingsets_builtins.py224
-rw-r--r--release/scripts/modules/add_object_utils.py36
-rw-r--r--release/scripts/modules/animsys_refactor.py89
-rw-r--r--release/scripts/modules/bpy/__init__.py9
-rw-r--r--release/scripts/modules/bpy/ops.py83
-rw-r--r--release/scripts/modules/bpy/path.py31
-rw-r--r--release/scripts/modules/bpy/utils.py170
-rw-r--r--release/scripts/modules/bpy_types.py139
-rw-r--r--release/scripts/modules/console/__init__.py25
-rw-r--r--release/scripts/modules/console/complete_calltip.py34
-rw-r--r--release/scripts/modules/console/complete_import.py25
-rw-r--r--release/scripts/modules/console/complete_namespace.py25
-rw-r--r--release/scripts/modules/console/intellisense.py31
-rw-r--r--release/scripts/modules/image_utils.py27
-rw-r--r--release/scripts/modules/io_utils.py4
-rw-r--r--release/scripts/modules/keyingsets_utils.py (renamed from release/scripts/keyingsets/keyingsets_utils.py)139
-rw-r--r--release/scripts/modules/rigify/__init__.py560
-rw-r--r--release/scripts/modules/rigify/arm_biped.py396
-rw-r--r--release/scripts/modules/rigify/copy.py112
-rw-r--r--release/scripts/modules/rigify/delta.py162
-rw-r--r--release/scripts/modules/rigify/eye_balls.py405
-rw-r--r--release/scripts/modules/rigify/eye_lid.py687
-rw-r--r--release/scripts/modules/rigify/finger_curl.py378
-rw-r--r--release/scripts/modules/rigify/leg_biped.py501
-rw-r--r--release/scripts/modules/rigify/leg_quadruped.py497
-rw-r--r--release/scripts/modules/rigify/mouth.py756
-rw-r--r--release/scripts/modules/rigify/neck.py344
-rw-r--r--release/scripts/modules/rigify/neck_flex.py348
-rw-r--r--release/scripts/modules/rigify/palm_curl.py270
-rw-r--r--release/scripts/modules/rigify/shape_key_control.py320
-rw-r--r--release/scripts/modules/rigify/shape_key_distance.py172
-rw-r--r--release/scripts/modules/rigify/shape_key_rotdiff.py172
-rw-r--r--release/scripts/modules/rigify/spine_pivot_flex.py481
-rw-r--r--release/scripts/modules/rigify/stretch.py109
-rw-r--r--release/scripts/modules/rigify/stretch_twist.py152
-rw-r--r--release/scripts/modules/rigify/tail_control.py165
-rw-r--r--release/scripts/modules/rigify/tongue.py361
-rw-r--r--release/scripts/modules/rigify/track_dual.py110
-rw-r--r--release/scripts/modules/rigify/track_reverse.py100
-rw-r--r--release/scripts/modules/rigify_utils.py467
-rw-r--r--release/scripts/modules/rna_info.py6
-rw-r--r--release/scripts/modules/rna_prop_ui.py36
-rw-r--r--release/scripts/modules/sys_info.py111
-rw-r--r--release/scripts/op/add_armature_human.py616
-rw-r--r--release/scripts/op/add_mesh_torus.py16
-rw-r--r--release/scripts/op/animsys_update.py13
-rw-r--r--release/scripts/op/console_python.py37
-rw-r--r--release/scripts/op/fcurve_euler_filter.py45
-rw-r--r--release/scripts/op/image.py20
-rw-r--r--release/scripts/op/io_anim_bvh/__init__.py81
-rw-r--r--release/scripts/op/io_anim_bvh/import_bvh.py568
-rw-r--r--release/scripts/op/io_mesh_ply/__init__.py75
-rw-r--r--release/scripts/op/io_mesh_ply/export_ply.py206
-rw-r--r--release/scripts/op/io_scene_3ds/__init__.py84
-rw-r--r--release/scripts/op/io_scene_3ds/export_3ds.py1044
-rw-r--r--release/scripts/op/io_scene_3ds/import_3ds.py794
-rw-r--r--release/scripts/op/io_scene_fbx/__init__.py122
-rw-r--r--release/scripts/op/io_scene_fbx/export_fbx.py2892
-rw-r--r--release/scripts/op/io_scene_obj/__init__.py144
-rw-r--r--release/scripts/op/io_scene_obj/export_obj.py842
-rw-r--r--release/scripts/op/io_scene_obj/import_obj.py1219
-rw-r--r--release/scripts/op/io_scene_x3d/__init__.py61
-rw-r--r--release/scripts/op/io_scene_x3d/export_x3d.py1123
-rw-r--r--release/scripts/op/io_shape_mdd/__init__.py117
-rw-r--r--release/scripts/op/io_shape_mdd/export_mdd.py131
-rw-r--r--release/scripts/op/io_shape_mdd/import_mdd.py105
-rw-r--r--release/scripts/op/mesh.py8
-rw-r--r--release/scripts/op/nla.py22
-rw-r--r--release/scripts/op/object.py52
-rw-r--r--release/scripts/op/object_align.py296
-rw-r--r--release/scripts/op/object_randomize_transform.py71
-rw-r--r--release/scripts/op/presets.py224
-rw-r--r--release/scripts/op/screen_play_rendered_anim.py12
-rw-r--r--release/scripts/op/sequencer.py4
-rw-r--r--release/scripts/op/uv.py89
-rw-r--r--release/scripts/op/uvcalc_follow_active.py40
-rw-r--r--release/scripts/op/uvcalc_smart_project.py43
-rw-r--r--release/scripts/op/vertexpaint_dirt.py6
-rw-r--r--release/scripts/op/wm.py77
-rw-r--r--release/scripts/presets/ffmpeg/DV.py3
-rw-r--r--release/scripts/presets/ffmpeg/DVD.py6
-rw-r--r--release/scripts/presets/ffmpeg/SVCD.py6
-rw-r--r--release/scripts/presets/ffmpeg/VCD.py6
-rw-r--r--release/scripts/presets/ffmpeg/h264.py2
-rw-r--r--release/scripts/presets/ffmpeg/theora.py2
-rw-r--r--release/scripts/presets/ffmpeg/xvid.py2
-rw-r--r--release/scripts/presets/keyconfig/maya.py (renamed from release/scripts/presets/interaction/maya.py)6
-rw-r--r--release/scripts/presets/render/HDV_1080p.py2
-rw-r--r--release/scripts/presets/render/HDV_NTSC_1080p.py8
-rw-r--r--release/scripts/presets/render/HDV_PAL_1080p.py8
-rw-r--r--release/scripts/presets/sss/apple.py6
-rw-r--r--release/scripts/presets/sss/chicken.py6
-rw-r--r--release/scripts/presets/sss/cream.py6
-rw-r--r--release/scripts/presets/sss/ketchup.py6
-rw-r--r--release/scripts/presets/sss/marble.py6
-rw-r--r--release/scripts/presets/sss/potato.py6
-rw-r--r--release/scripts/presets/sss/skim_milk.py6
-rw-r--r--release/scripts/presets/sss/skin1.py6
-rw-r--r--release/scripts/presets/sss/skin2.py6
-rw-r--r--release/scripts/presets/sss/whole_milk.py6
-rw-r--r--release/scripts/templates/addon_add_object.py78
-rw-r--r--release/scripts/templates/background_job.py114
-rw-r--r--release/scripts/templates/builtin_keyingset.py38
-rw-r--r--release/scripts/templates/gamelogic.py13
-rw-r--r--release/scripts/templates/gamelogic_basic.py4
-rw-r--r--release/scripts/templates/gamelogic_module.py5
-rw-r--r--release/scripts/templates/operator.py63
-rw-r--r--release/scripts/templates/operator_export.py66
-rw-r--r--release/scripts/templates/operator_mesh_add.py106
-rw-r--r--release/scripts/templates/operator_modal.py14
-rw-r--r--release/scripts/templates/operator_modal_draw.py16
-rw-r--r--release/scripts/templates/operator_modal_view3d.py19
-rw-r--r--release/scripts/templates/operator_simple.py15
-rw-r--r--release/scripts/templates/operator_uv.py16
-rw-r--r--release/scripts/templates/panel_simple.py13
-rw-r--r--release/scripts/ui/properties_animviz.py5
-rw-r--r--release/scripts/ui/properties_data_armature.py15
-rw-r--r--release/scripts/ui/properties_data_armature_rigify.py325
-rw-r--r--release/scripts/ui/properties_data_bone.py85
-rw-r--r--release/scripts/ui/properties_data_camera.py7
-rw-r--r--release/scripts/ui/properties_data_curve.py43
-rw-r--r--release/scripts/ui/properties_data_empty.py4
-rw-r--r--release/scripts/ui/properties_data_lamp.py5
-rw-r--r--release/scripts/ui/properties_data_lattice.py5
-rw-r--r--release/scripts/ui/properties_data_mesh.py23
-rw-r--r--release/scripts/ui/properties_data_metaball.py12
-rw-r--r--release/scripts/ui/properties_data_modifier.py30
-rw-r--r--release/scripts/ui/properties_game.py46
-rw-r--r--release/scripts/ui/properties_material.py50
-rw-r--r--release/scripts/ui/properties_object.py45
-rw-r--r--release/scripts/ui/properties_object_constraint.py48
-rw-r--r--release/scripts/ui/properties_particle.py202
-rw-r--r--release/scripts/ui/properties_physics_cloth.py21
-rw-r--r--release/scripts/ui/properties_physics_common.py108
-rw-r--r--release/scripts/ui/properties_physics_field.py31
-rw-r--r--release/scripts/ui/properties_physics_fluid.py26
-rw-r--r--release/scripts/ui/properties_physics_smoke.py67
-rw-r--r--release/scripts/ui/properties_physics_softbody.py21
-rw-r--r--release/scripts/ui/properties_render.py55
-rw-r--r--release/scripts/ui/properties_scene.py16
-rw-r--r--release/scripts/ui/properties_texture.py510
-rw-r--r--release/scripts/ui/properties_world.py15
-rw-r--r--release/scripts/ui/space_console.py45
-rw-r--r--release/scripts/ui/space_dopesheet.py129
-rw-r--r--release/scripts/ui/space_filebrowser.py8
-rw-r--r--release/scripts/ui/space_graph.py40
-rw-r--r--release/scripts/ui/space_image.py68
-rw-r--r--release/scripts/ui/space_info.py69
-rw-r--r--release/scripts/ui/space_logic.py4
-rw-r--r--release/scripts/ui/space_nla.py30
-rw-r--r--release/scripts/ui/space_node.py40
-rw-r--r--release/scripts/ui/space_outliner.py4
-rw-r--r--release/scripts/ui/space_sequencer.py76
-rw-r--r--release/scripts/ui/space_text.py6
-rw-r--r--release/scripts/ui/space_time.py52
-rw-r--r--release/scripts/ui/space_userpref.py167
-rw-r--r--release/scripts/ui/space_userpref_keymap.py35
-rw-r--r--release/scripts/ui/space_view3d.py179
-rw-r--r--release/scripts/ui/space_view3d_toolbar.py168
-rw-r--r--release/test/pep8.py98
-rw-r--r--release/test/rna_array.py297
-rw-r--r--release/test/rna_info_dump.py131
-rw-r--r--release/text/readme.html10
-rw-r--r--release/windows/extra/Help.url4
-rw-r--r--release/windows/installer/00.sconsblender.nsi58
-rwxr-xr-xrelease/windows/specific.sh95
198 files changed, 5281 insertions, 21766 deletions
diff --git a/release/Makefile b/release/Makefile
deleted file mode 100644
index bef76b349b2..00000000000
--- a/release/Makefile
+++ /dev/null
@@ -1,209 +0,0 @@
-# -*- mode: gnumakefile; tab-width: 8; indent-tabs-mode: t; -*-
-# vim: tabstop=8
-# $Id$
-#
-# ***** 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.
-#
-# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): none yet.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-include nan_definitions.mk
-
-export VERSION := $(shell ./getversion.py)
-
-BLENDNAME=blender-$(VERSION)-$(CONFIG_GUESS)-py$(NAN_PYTHON_VERSION)$(TYPE)
-export DISTDIR=$(NAN_OBJDIR)/$(BLENDNAME)
-export CONFDIR=$(DISTDIR)/.blender
-
-ifeq ($(OS),$(findstring $(OS), "freebsd irix linux openbsd solaris"))
- TAR="tar"
- TARFLAGS="cf"
- EXT0=""
- EXT1=".tar"
- COMPRESS="bzip2"
- COMPRESSFLAGS="-f"
- EXT2=".bz2"
- ifeq ($(OS), solaris)
- ifeq ($(CPU), i386)
- NOPLUGINS?=true
- endif
- endif
- # don"t build plugins on irix if using gcc
- ifeq ($(OS), irix)
- ifeq ($(IRIX_USE_GCC), true)
- NOPLUGINS?=true
- endif
- endif
-endif
-
-ifeq ($(OS),windows)
- TAR="zip"
- TARFLAGS="-r9"
- EXT0=".exe"
- EXT1=".zip"
- NOPLUGINS?=true
- NOSTRIP?=true
-endif
-
-ifeq ($(OS),darwin)
- TAR="tar"
- TARFLAGS="cf"
- EXT0=".app"
- EXT1=".tar"
- COMPRESS="bzip2"
- COMPRESSFLAGS="-f"
- EXT2=".bz2"
-endif
-
-release: all
-
-all:
- @$(MAKE) pkg TYPE=""
-ifeq ($(WITH_BF_STATICOPENGL), true)
- @$(MAKE) pkg TYPE="-static"
-endif
-
-# OS independent targets below:
-
-dist: all
-
-package: version makedirs
-
-install: package
- @#echo "****> Install text"
- @cp text/readme.html $(DISTDIR)
- @cp text/*.txt $(DISTDIR)
- ifeq ($(FREEDESKTOP), true)
- @#echo "****> Install freedesktop icons"
- @mkdir $(DISTDIR)/icons
- @mkdir $(DISTDIR)/icons/16x16
- @cp freedesktop/icons/16x16/blender.png $(DISTDIR)/icons/16x16
- @mkdir $(DISTDIR)/icons/22x22
- @cp freedesktop/icons/22x22/blender.png $(DISTDIR)/icons/22x22
- @mkdir $(DISTDIR)/icons/32x32
- @cp freedesktop/icons/32x32/blender.png $(DISTDIR)/icons/32x32
- @mkdir $(DISTDIR)/icons/scalable
- @cp freedesktop/icons/scalable/blender.svg $(DISTDIR)/icons/scalable
- endif
- @echo "----> Make Config dir .blender"
- @mkdir -p $(CONFDIR)
- @# possible overruling .txt text documents
- @[ ! -d $(CONFIG_GUESS)/text ] || \
- cp -f $(CONFIG_GUESS)/text/*.txt $(DISTDIR)
-#on OS X the contents of the .blender dir is already inside the bundle
- ifneq ($(OS), darwin)
- @[ ! -d $(OCGDIR)/bin/.blender ] || \
- cp -r $(OCGDIR)/bin/.blender $(DISTDIR)
- @cp $(NANBLENDERHOME)/release/bin/.blender/.Blanguages $(CONFDIR)
- @cp $(NANBLENDERHOME)/release/bin/.blender/.bfont.ttf $(CONFDIR)
- endif
- @echo "----> Copy blender$(EXT0) executable"
- ifeq ($(TYPE),-static)
- @cp $(OCGDIR)/bin/blenderstatic$(EXT0) $(DISTDIR)/blender$(EXT0)
- else
- ifeq ($(OS),darwin)
- @cp -r $(OCGDIR)/bin/blender$(EXT0) $(DISTDIR)/Blender$(EXT0)
- else
- @cp $(OCGDIR)/bin/blender$(EXT0) $(DISTDIR)/blender$(EXT0)
- endif
- @if [ -f $(OCGDIR)/bin/blenderplayer$(EXTO) ]; then \
- cp $(OCGDIR)/bin/blenderplayer$(EXTO) \
- $(DISTDIR)/blenderplayer$(EXTO) ; \
- fi
- endif
-
-ifneq ($(NOPLUGINS),true)
- @echo "----> Copy and compile plugins"
- @cp -r plugins $(DISTDIR)/plugins
- @mkdir -p $(DISTDIR)/plugins/include
- @cp ../source/blender/blenpluginapi/*.h $(DISTDIR)/plugins/include/
- @chmod 755 $(DISTDIR)/plugins/bmake
- @$(MAKE) -C $(DISTDIR)/plugins all > /dev/null || exit 1;
- @rm -f $(DISTDIR)/plugins/*/*.o
-
-#on OS X the plugins move to the installation directory
- ifneq ($(OS),darwin)
- @mkdir -p $(CONFDIR)/plugins/sequence
- @mkdir -p $(CONFDIR)/plugins/texture
- @mv $(DISTDIR)/plugins/sequence/*.so $(CONFDIR)/plugins/sequence
- @mv $(DISTDIR)/plugins/texture/*.so $(CONFDIR)/plugins/texture
- endif
-endif
-
- @echo "----> Copy python infrastructure"
- @[ ! -d scripts ] || cp -r scripts $(CONFDIR)/scripts
-
- ifeq ($(OS),darwin)
- @echo "----> Copy python modules"
- @mkdir $(CONFDIR)/python/
- @unzip -q $(LCGDIR)/release/python.zip -d $(CONFDIR)/python/
- endif
-
- ifeq ($(OS),darwin)
- @echo "----> Move .blender to .app/Contents/MacOS/"
- @rm -fr $(DISTDIR)/blender$(EXT0)/Contents/MacOS/.blender
- @mv $(DISTDIR)/.blender $(DISTDIR)/blender$(EXT0)/Contents/MacOS/
- endif
-
- ifneq ($(NOSTRIP),true)
- @echo "----> Strip blender executable"
- ifeq ($(OS),darwin)
- @strip -x $(DISTDIR)/blender$(EXT0)/Contents/MacOS/blender
- else
- @strip -x $(DISTDIR)/blender$(EXT0)
- @if [ -f $(DISTDIR)/blenderplayer$(EXTO) ]; then \
- strip -x $(DISTDIR)/blenderplayer$(EXT0) ; \
- fi
- endif
- endif
- @[ ! -x $(CONFIG_GUESS)/specific.sh ] || (\
- echo "**--> Execute specific.sh in $(CONFIG_GUESS)/" && \
- cd $(CONFIG_GUESS) && ./specific.sh )
- @echo "----> Cleaning .svn metadata directories"
- @find $(DISTDIR) -type d -name ".svn" | xargs rm -fr
-
-pkg: install
- @echo "----> Create distribution file $(BLENDNAME)$(EXT1)"
- @#enable the next sleep if you get 'tar file changed while reading'
- @#sleep 10
- rm -f $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1)*
- @cd $(NAN_OBJDIR) && $(TAR) $(TARFLAGS) $(VERSION)/$(BLENDNAME)$(EXT1) $(BLENDNAME)
- ifdef COMPRESS
- @echo "----> Compressing distribution to $(BLENDNAME)$(EXT1)$(EXT2)"
- @$(COMPRESS) $(COMPRESSFLAGS) $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1)
- endif
- @#echo "****> Clean up temporary distribution directory"
- @#rm -fr $(DISTDIR)
- @echo "****> $(NAN_OBJDIR)/$(VERSION)/$(BLENDNAME)$(EXT1)$(EXT2) is ready"
-
-version: FORCE
- @echo "*---> Create $(BLENDNAME) package"
-
-makedirs: FORCE
- @echo "****> Create package directory $(VERSION) if necessary"
- @[ -d $(NAN_OBJDIR)/$(VERSION) ] || mkdir $(NAN_OBJDIR)/$(VERSION)
- @echo "****> Remove and recreate temporary distribution directory"
- @rm -fr $(DISTDIR)
- @mkdir $(DISTDIR)
-
-FORCE:
diff --git a/release/VERSION b/release/VERSION
index 6020b0f868b..9a256b1d546 100644
--- a/release/VERSION
+++ b/release/VERSION
@@ -1 +1 @@
-2.54-beta
+2.56a-beta
diff --git a/release/bin/blender-thumbnailer.py b/release/bin/blender-thumbnailer.py
index be870560110..8b93eebdeec 100755
--- a/release/bin/blender-thumbnailer.py
+++ b/release/bin/blender-thumbnailer.py
@@ -18,40 +18,65 @@
#
# ##### END GPL LICENSE BLOCK #####
+# <pep8 compliant>
+
"""
Thumbnailer runs with python 2.6 and 3.x.
To run automatically with nautilus:
gconftool --type boolean --set /desktop/gnome/thumbnailers/application@x-blender/enable true
- gconftool --type string --set /desktop/gnome/thumbnailers/application@x-blender/command "blender-thumbnailer.py %i %o"
+ gconftool --type string --set /desktop/gnome/thumbnailers/application@x-blender/command "blender-thumbnailer.py %u %o"
"""
import struct
+
+def open_wrapper_get():
+ """ wrap OS spesific read functionality here, fallback to 'open()'
+ """
+
+ def open_gio(path, mode):
+ g_file = gio.File(path).read()
+ g_file.orig_seek = g_file.seek
+
+ def new_seek(offset, whence=0):
+ return g_file.orig_seek(offset, [1, 0, 2][whence])
+
+ g_file.seek = new_seek
+ return g_file
+
+ try:
+ import gio
+ return open_gio
+ except ImportError:
+ return open
+
+
def blend_extract_thumb(path):
import os
+ open_wrapper = open_wrapper_get()
# def MAKE_ID(tag): ord(tag[0])<<24 | ord(tag[1])<<16 | ord(tag[2])<<8 | ord(tag[3])
- REND = 1145980242 # MAKE_ID(b'REND')
- TEST = 1414743380 # MAKE_ID(b'TEST')
+ REND = 1145980242 # MAKE_ID(b'REND')
+ TEST = 1414743380 # MAKE_ID(b'TEST')
- blendfile = open(path, 'rb')
+ blendfile = open_wrapper(path, 'rb')
head = blendfile.read(12)
- if head[0:2] == b'\x1f\x8b': # gzip magic
+ if head[0:2] == b'\x1f\x8b': # gzip magic
import gzip
blendfile.close()
- blendfile = gzip.open(path, 'rb')
+ blendfile = gzip.GzipFile('', 'rb', 0, open_wrapper(path, 'rb'))
head = blendfile.read(12)
if not head.startswith(b'BLENDER'):
blendfile.close()
return None, 0, 0
- is_64_bit = (head[7] == b'-')
+ is_64_bit = (head[7] == b'-'[0])
# true for PPC, false for X86
- is_big_endian = (head[8] == b'V')
+ is_big_endian = (head[8] == b'V'[0])
# blender pre 2.5 had no thumbs
if head[9:11] <= b'24':
@@ -66,23 +91,22 @@ def blend_extract_thumb(path):
if len(bhead) < sizeof_bhead:
return None, 0, 0
- code, length = struct.unpack(int_endian_pair, bhead[0:8]) # 8 == sizeof(int) * 2
+ code, length = struct.unpack(int_endian_pair, bhead[0:8]) # 8 == sizeof(int) * 2
if code == REND:
blendfile.seek(length, os.SEEK_CUR)
else:
break
-
-
+
if code != TEST:
return None, 0, 0
try:
- x, y = struct.unpack(int_endian_pair, blendfile.read(8)) # 8 == sizeof(int) * 2
+ x, y = struct.unpack(int_endian_pair, blendfile.read(8)) # 8 == sizeof(int) * 2
except struct.error:
return None, 0, 0
- length -= 8 # sizeof(int) * 2
+ length -= 8 # sizeof(int) * 2
if length != x * y * 4:
return None, 0, 0
@@ -116,13 +140,13 @@ def write_png(buf, width, height):
if __name__ == '__main__':
import sys
- if len(sys.argv) < 2:
+ if len(sys.argv) < 3:
print("Expected 2 arguments <input.blend> <output.png>")
else:
file_in = sys.argv[-2]
buf, width, height = blend_extract_thumb(file_in)
-
+
if buf:
file_out = sys.argv[-1]
diff --git a/release/datafiles/blenderbuttons b/release/datafiles/blenderbuttons
index b9fa75cc254..42e82430ca1 100644
--- a/release/datafiles/blenderbuttons
+++ b/release/datafiles/blenderbuttons
Binary files differ
diff --git a/release/datafiles/ctodata.py b/release/datafiles/ctodata.py
new file mode 100644
index 00000000000..be33f724deb
--- /dev/null
+++ b/release/datafiles/ctodata.py
@@ -0,0 +1,58 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# ***** 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.
+#
+# The Original Code is Copyright (C) 2009 Blender Foundation.
+# All rights reserved.
+#
+# Contributor(s): Campbell Barton
+#
+# ***** END GPL LICENCE BLOCK *****
+
+
+# <pep8 compliant>
+
+import sys
+import os
+
+if len(sys.argv) < 2:
+ sys.stdout.write("Usage: ctodata <c_file>\n")
+ sys.exit(1)
+
+filename = sys.argv[1]
+
+try:
+ fpin = open(filename, "r")
+except:
+ sys.stdout.write("Unable to open input %s\n" % sys.argv[1])
+ sys.exit(1)
+
+data = fpin.read().rsplit("{")[-1].split("}")[0]
+data = data.replace(",", " ")
+data = data.split()
+data = bytes([int(v) for v in data])
+
+dname = filename + ".ctodata"
+
+try:
+ fpout = open(dname, "wb")
+except:
+ sys.stdout.write("Unable to open output %s\n" % dname)
+ sys.exit(1)
+
+fpout.write(data)
diff --git a/release/datafiles/datatoc.py b/release/datafiles/datatoc.py
index 7ad96440222..564070dcf9f 100755
--- a/release/datafiles/datatoc.py
+++ b/release/datafiles/datatoc.py
@@ -45,8 +45,8 @@ fpin.seek(0, os.SEEK_END)
size = fpin.tell()
fpin.seek(0)
-if filename[0] == ".":
- filename = filename[1:]
+if filename[0:2] == "." + os.sep:
+ filename = filename[2:]
cname = filename + ".c"
sys.stdout.write("Making C file <%s>\n" % cname)
diff --git a/release/datafiles/prvicons b/release/datafiles/prvicons
index 2f715172209..364d9678f0b 100644
--- a/release/datafiles/prvicons
+++ b/release/datafiles/prvicons
Binary files differ
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index 36ebb154ca9..9207b935271 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/freedesktop/icons/16x16/blender.png b/release/freedesktop/icons/16x16/blender.png
index 238d67321a7..2ddf0deff21 100644
--- a/release/freedesktop/icons/16x16/blender.png
+++ b/release/freedesktop/icons/16x16/blender.png
Binary files differ
diff --git a/release/freedesktop/icons/16x16/blender.svg b/release/freedesktop/icons/16x16/blender.svg
new file mode 100644
index 00000000000..7835b312a6c
--- /dev/null
+++ b/release/freedesktop/icons/16x16/blender.svg
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg7854"
+ sodipodi:version="0.32"
+ inkscape:version="0.48.0 r9654"
+ version="1.0"
+ sodipodi:docname="blender.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ sodipodi:modified="true"
+ inkscape:export-filename="/home/user/my/blender/builds/blender/release/freedesktop/icons/16x16/blender.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs7856">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient39171">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop39173" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop39175" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient39155">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop39157" />
+ <stop
+ style="stop-color:#dadada;stop-opacity:1;"
+ offset="1"
+ id="stop39159" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient35500">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop35502" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop35504" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient35488">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop35490" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop35492" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3564">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop3566" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop3568" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3564"
+ id="linearGradient34576"
+ gradientUnits="userSpaceOnUse"
+ x1="185.9903"
+ y1="193.33229"
+ x2="190.46461"
+ y2="-458.05771"
+ gradientTransform="matrix(0.06818845,0,0,0.06818845,22.51112,27.02885)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient35488"
+ id="radialGradient35494"
+ cx="28.019106"
+ cy="38.98439"
+ fx="28.019106"
+ fy="38.98439"
+ r="15.467961"
+ gradientTransform="matrix(1,0,0,0.342857,0,25.61831)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient35500"
+ id="linearGradient35506"
+ x1="21.204315"
+ y1="21.699249"
+ x2="20.155914"
+ y2="-26.908371"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient39155"
+ id="linearGradient39161"
+ x1="31.1875"
+ y1="18.875"
+ x2="29.875"
+ y2="34.375"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient39171"
+ id="radialGradient39177"
+ cx="26.109201"
+ cy="19.668886"
+ fx="26.109201"
+ fy="19.668886"
+ r="20.278975"
+ gradientTransform="matrix(1.647222,0,0,1.26792,-15.47413,-5.79794)"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#e0e0e0"
+ borderopacity="1"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.245778"
+ inkscape:cx="10.326105"
+ inkscape:cy="15.440713"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ width="48px"
+ height="48px"
+ inkscape:showpageshadow="false"
+ inkscape:window-width="1392"
+ inkscape:window-height="976"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="false"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7859">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:source>http://jimmac.musichall.cz</dc:source>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:title></dc:title>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-32)">
+ <g
+ id="blender"
+ transform="matrix(0.32150786,0,0,0.32150786,0.0378132,31.723202)"
+ inkscape:label="blender">
+ <path
+ transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)"
+ d="m 43.487067,38.98439 c 0,2.928932 -6.925242,5.303301 -15.467961,5.303301 -8.542719,0 -15.467961,-2.374369 -15.467961,-5.303301 0,-2.928932 6.925242,-5.303301 15.467961,-5.303301 8.542719,0 15.467961,2.374369 15.467961,5.303301 z"
+ sodipodi:ry="5.3033009"
+ sodipodi:rx="15.467961"
+ sodipodi:cy="38.98439"
+ sodipodi:cx="28.019106"
+ id="path35486"
+ style="opacity:0.54857142;color:#000000;fill:url(#radialGradient35494);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:nodetypes="csssssssssscccsscccscccssccc"
+ d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -2.434775,-0.6939758 -3.431728,0.00488 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 3.792068,3.0680399 5.702368,4.5676189 0,0 -17.551681,-0.01171 -17.551681,-0.01171 -1.994685,0 -3.1682604,0.947915 -3.4153942,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800212,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -15.901723,11.764162 -15.901723,11.764162 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 z"
+ id="path2482"
+ style="fill:#f57900;fill-rule:evenodd;stroke:#ce5c00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
+ inkscape:connector-curvature="0" />
+ <path
+ transform="matrix(0.821621,0,0,0.839506,5.875686,3.882724)"
+ d="m 42.75,25.75 c 0,5.591883 -5.176708,10.125 -11.5625,10.125 -6.385792,0 -11.5625,-4.533117 -11.5625,-10.125 0,-5.591883 5.176708,-10.125 11.5625,-10.125 6.385792,0 11.5625,4.533117 11.5625,10.125 z"
+ sodipodi:ry="10.125"
+ sodipodi:rx="11.5625"
+ sodipodi:cy="25.75"
+ sodipodi:cx="31.1875"
+ id="path39153"
+ style="color:#000000;fill:url(#linearGradient39161);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:nodetypes="cssssscscczccsccssssccscccccscssc"
+ id="path3562"
+ d="m 25.796988,6.0267804 c -0.404852,5.53e-4 -0.818619,0.1256944 -1.095272,0.3196267 -7.14e-4,7.142e-4 -0.0014,0.00143 -0.0021,0.00213 -0.280209,0.1956525 -0.336859,0.3680061 -0.345206,0.4602725 -0.0083,0.092266 -0.01324,0.1672776 0.189655,0.3345475 0.01899,0.015735 0.03747,0.032076 0.0554,0.049009 0.124258,0.1010285 5.704394,4.6389489 5.704394,4.6389489 0.373658,0.304091 0.51584,0.810232 0.355197,1.264415 -0.160635,0.454191 -0.589422,0.382732 -1.071174,0.384283 -5.634142,0.05114 -17.60967,0.01918 -17.60967,0.01918 -0.952967,6.38e-4 -2.3472795,0.516793 -2.4135719,1.585761 -0.063562,1.024947 0.9093059,1.457499 1.5782589,1.457499 0,0 8.830403,-0.01705 8.830403,-0.01705 0.488364,-5.91e-4 0.922857,0.221532 1.080466,0.683755 0.15761,0.462231 0.0033,0.53156 -0.383664,0.829439 0,0 -15.9006939,12.205735 -15.9006939,12.205735 -0.00142,0.0014 -0.00284,0.0028 -0.00426,0.0043 -0.064038,0.04879 -0.084772,0.06226 -0.061795,0.04476 -0.5536756,0.424618 -0.8961097,0.98072 -1.0185711,1.476701 -0.1224537,0.495981 -0.04659,0.882548 0.1875202,1.182646 0.4788333,0.613413 1.7693735,0.732111 2.8980115,-0.178996 0,0 8.6727243,-7.09799 8.6727243,-7.09799 0.361955,-0.295752 0.867758,-0.340606 1.276111,-0.113169 0.408345,0.227437 0.636512,0.681082 0.575631,1.144518 0,0 -0.112502,0.980045 -0.10655,1.370159 0.192357,2.636407 1.448328,4.914995 3.115366,6.91474 2.877746,3.172809 6.84939,4.556285 11.042271,4.719919 4.20342,-0.04394 8.185784,-1.662428 11.042264,-4.758277 5.218918,-6.385867 3.941737,-13.3639 -1.747326,-17.993227 C 36.14442,13.301598 31.42752,9.8792062 26.81986,6.3400589 c -0.0043,-0.00352 -0.0086,-0.00707 -0.01279,-0.010651 -0.0072,-0.00489 -0.01427,-0.00987 -0.02131,-0.014921 -0.210578,-0.1612288 -0.584681,-0.288267 -0.988772,-0.2877065 z"
+ style="opacity:0.4857143;fill:none;stroke:url(#linearGradient34576);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 26.007076,24.754048 c 0.07447,-1.361157 0.739293,-2.562655 1.738705,-3.413271 0.983518,-0.836183 2.304215,-1.346747 3.746876,-1.346747 1.441743,0 2.762441,0.510564 3.745729,1.346747 1.000515,0.850616 1.664539,2.051213 1.739875,3.41237 0.07718,1.400852 -0.4828,2.701576 -1.46425,3.66495 -1.000516,0.981409 -2.427099,1.597503 -4.021354,1.597503 -1.595172,0 -3.021756,-0.616094 -4.022225,-1.597503 -0.982461,-0.963374 -1.540507,-2.264098 -1.463356,-3.664049 z"
+ id="path2478"
+ style="fill:#3465a4;fill-rule:evenodd;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
+ id="path39166"
+ d="m 25.8125,6.03125 c -0.404852,5.528e-4 -0.848347,0.1185677 -1.125,0.3125 -0.280209,0.1956523 -0.335403,0.3764836 -0.34375,0.46875 -0.0083,0.092267 -0.01539,0.1764801 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.1010283 5.71875,4.65625 5.71875,4.65625 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -17.625,0.03125 -17.625,0.03125 -0.952967,6.38e-4 -2.3399576,0.524782 -2.40625,1.59375 -0.063562,1.024947 0.924797,1.4375 1.59375,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -15.875,12.21875 -15.875,12.21875 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.8828973 26.8125,6.34375 26.805335,6.3388584 26.788292,6.317553 26.78125,6.3125 26.570707,6.1513121 26.216591,6.0306895 25.8125,6.03125 z"
+ style="opacity:0.51999996;fill:url(#radialGradient39177);fill-opacity:1;fill-rule:evenodd;stroke:none"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+</svg>
diff --git a/release/freedesktop/icons/16x16/blender.xcf.bz2 b/release/freedesktop/icons/16x16/blender.xcf.bz2
deleted file mode 100644
index 67cb725ea79..00000000000
--- a/release/freedesktop/icons/16x16/blender.xcf.bz2
+++ /dev/null
Binary files differ
diff --git a/release/freedesktop/icons/22x22/blender.png b/release/freedesktop/icons/22x22/blender.png
index 3178ddd58ee..fad6f88526f 100644
--- a/release/freedesktop/icons/22x22/blender.png
+++ b/release/freedesktop/icons/22x22/blender.png
Binary files differ
diff --git a/release/freedesktop/icons/22x22/blender.svg b/release/freedesktop/icons/22x22/blender.svg
new file mode 100644
index 00000000000..0f71a2c4fce
--- /dev/null
+++ b/release/freedesktop/icons/22x22/blender.svg
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="22"
+ height="22"
+ id="svg7854"
+ sodipodi:version="0.32"
+ inkscape:version="0.48.0 r9654"
+ version="1.0"
+ sodipodi:docname="blender.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ sodipodi:modified="true"
+ inkscape:export-filename="/home/user/my/blender/builds/blender/release/freedesktop/icons/22x22/blender.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs7856">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient39171">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop39173" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop39175" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient39155">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop39157" />
+ <stop
+ style="stop-color:#dadada;stop-opacity:1;"
+ offset="1"
+ id="stop39159" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient35500">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop35502" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop35504" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient35488">
+ <stop
+ style="stop-color:black;stop-opacity:1;"
+ offset="0"
+ id="stop35490" />
+ <stop
+ style="stop-color:black;stop-opacity:0;"
+ offset="1"
+ id="stop35492" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3564">
+ <stop
+ style="stop-color:white;stop-opacity:1;"
+ offset="0"
+ id="stop3566" />
+ <stop
+ style="stop-color:white;stop-opacity:0;"
+ offset="1"
+ id="stop3568" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3564"
+ id="linearGradient34576"
+ gradientUnits="userSpaceOnUse"
+ x1="185.9903"
+ y1="193.33229"
+ x2="190.46461"
+ y2="-458.05771"
+ gradientTransform="matrix(0.06818845,0,0,0.06818845,22.51112,27.02885)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient35488"
+ id="radialGradient35494"
+ cx="28.019106"
+ cy="38.98439"
+ fx="28.019106"
+ fy="38.98439"
+ r="15.467961"
+ gradientTransform="matrix(1,0,0,0.342857,0,25.61831)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient35500"
+ id="linearGradient35506"
+ x1="21.204315"
+ y1="21.699249"
+ x2="20.155914"
+ y2="-26.908371"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient39155"
+ id="linearGradient39161"
+ x1="31.1875"
+ y1="18.875"
+ x2="29.875"
+ y2="34.375"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient39171"
+ id="radialGradient39177"
+ cx="26.109201"
+ cy="19.668886"
+ fx="26.109201"
+ fy="19.668886"
+ r="20.278975"
+ gradientTransform="matrix(1.647222,0,0,1.26792,-15.47413,-5.79794)"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#e0e0e0"
+ borderopacity="1"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="16.245778"
+ inkscape:cx="10.326105"
+ inkscape:cy="15.440713"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ width="48px"
+ height="48px"
+ inkscape:showpageshadow="false"
+ inkscape:window-width="1392"
+ inkscape:window-height="976"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="false"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata7859">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Jakub Steiner</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:source>http://jimmac.musichall.cz</dc:source>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:title></dc:title>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-26)">
+ <g
+ id="blender"
+ transform="matrix(0.45418175,0,0,0.45418175,-0.2261234,25.847379)"
+ inkscape:label="blender">
+ <path
+ transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)"
+ d="m 43.487067,38.98439 c 0,2.928932 -6.925242,5.303301 -15.467961,5.303301 -8.542719,0 -15.467961,-2.374369 -15.467961,-5.303301 0,-2.928932 6.925242,-5.303301 15.467961,-5.303301 8.542719,0 15.467961,2.374369 15.467961,5.303301 z"
+ sodipodi:ry="5.3033009"
+ sodipodi:rx="15.467961"
+ sodipodi:cy="38.98439"
+ sodipodi:cx="28.019106"
+ id="path35486"
+ style="opacity:0.54857142;color:#000000;fill:url(#radialGradient35494);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:nodetypes="csssssssssscccsscccscccssccc"
+ d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -2.434775,-0.6939758 -3.431728,0.00488 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 3.792068,3.0680399 5.702368,4.5676189 0,0 -17.551681,-0.01171 -17.551681,-0.01171 -1.994685,0 -3.1682604,0.947915 -3.4153942,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800212,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -15.901723,11.764162 -15.901723,11.764162 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 z"
+ id="path2482"
+ style="fill:#f57900;fill-rule:evenodd;stroke:#ce5c00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
+ inkscape:connector-curvature="0" />
+ <path
+ transform="matrix(0.821621,0,0,0.839506,5.875686,3.882724)"
+ d="m 42.75,25.75 c 0,5.591883 -5.176708,10.125 -11.5625,10.125 -6.385792,0 -11.5625,-4.533117 -11.5625,-10.125 0,-5.591883 5.176708,-10.125 11.5625,-10.125 6.385792,0 11.5625,4.533117 11.5625,10.125 z"
+ sodipodi:ry="10.125"
+ sodipodi:rx="11.5625"
+ sodipodi:cy="25.75"
+ sodipodi:cx="31.1875"
+ id="path39153"
+ style="color:#000000;fill:url(#linearGradient39161);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:nodetypes="cssssscscczccsccssssccscccccscssc"
+ id="path3562"
+ d="m 25.796988,6.0267804 c -0.404852,5.53e-4 -0.818619,0.1256944 -1.095272,0.3196267 -7.14e-4,7.142e-4 -0.0014,0.00143 -0.0021,0.00213 -0.280209,0.1956525 -0.336859,0.3680061 -0.345206,0.4602725 -0.0083,0.092266 -0.01324,0.1672776 0.189655,0.3345475 0.01899,0.015735 0.03747,0.032076 0.0554,0.049009 0.124258,0.1010285 5.704394,4.6389489 5.704394,4.6389489 0.373658,0.304091 0.51584,0.810232 0.355197,1.264415 -0.160635,0.454191 -0.589422,0.382732 -1.071174,0.384283 -5.634142,0.05114 -17.60967,0.01918 -17.60967,0.01918 -0.952967,6.38e-4 -2.3472795,0.516793 -2.4135719,1.585761 -0.063562,1.024947 0.9093059,1.457499 1.5782589,1.457499 0,0 8.830403,-0.01705 8.830403,-0.01705 0.488364,-5.91e-4 0.922857,0.221532 1.080466,0.683755 0.15761,0.462231 0.0033,0.53156 -0.383664,0.829439 0,0 -15.9006939,12.205735 -15.9006939,12.205735 -0.00142,0.0014 -0.00284,0.0028 -0.00426,0.0043 -0.064038,0.04879 -0.084772,0.06226 -0.061795,0.04476 -0.5536756,0.424618 -0.8961097,0.98072 -1.0185711,1.476701 -0.1224537,0.495981 -0.04659,0.882548 0.1875202,1.182646 0.4788333,0.613413 1.7693735,0.732111 2.8980115,-0.178996 0,0 8.6727243,-7.09799 8.6727243,-7.09799 0.361955,-0.295752 0.867758,-0.340606 1.276111,-0.113169 0.408345,0.227437 0.636512,0.681082 0.575631,1.144518 0,0 -0.112502,0.980045 -0.10655,1.370159 0.192357,2.636407 1.448328,4.914995 3.115366,6.91474 2.877746,3.172809 6.84939,4.556285 11.042271,4.719919 4.20342,-0.04394 8.185784,-1.662428 11.042264,-4.758277 5.218918,-6.385867 3.941737,-13.3639 -1.747326,-17.993227 C 36.14442,13.301598 31.42752,9.8792062 26.81986,6.3400589 c -0.0043,-0.00352 -0.0086,-0.00707 -0.01279,-0.010651 -0.0072,-0.00489 -0.01427,-0.00987 -0.02131,-0.014921 -0.210578,-0.1612288 -0.584681,-0.288267 -0.988772,-0.2877065 z"
+ style="opacity:0.4857143;fill:none;stroke:url(#linearGradient34576);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 26.007076,24.754048 c 0.07447,-1.361157 0.739293,-2.562655 1.738705,-3.413271 0.983518,-0.836183 2.304215,-1.346747 3.746876,-1.346747 1.441743,0 2.762441,0.510564 3.745729,1.346747 1.000515,0.850616 1.664539,2.051213 1.739875,3.41237 0.07718,1.400852 -0.4828,2.701576 -1.46425,3.66495 -1.000516,0.981409 -2.427099,1.597503 -4.021354,1.597503 -1.595172,0 -3.021756,-0.616094 -4.022225,-1.597503 -0.982461,-0.963374 -1.540507,-2.264098 -1.463356,-3.664049 z"
+ id="path2478"
+ style="fill:#3465a4;fill-rule:evenodd;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
+ id="path39166"
+ d="m 25.8125,6.03125 c -0.404852,5.528e-4 -0.848347,0.1185677 -1.125,0.3125 -0.280209,0.1956523 -0.335403,0.3764836 -0.34375,0.46875 -0.0083,0.092267 -0.01539,0.1764801 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.1010283 5.71875,4.65625 5.71875,4.65625 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -17.625,0.03125 -17.625,0.03125 -0.952967,6.38e-4 -2.3399576,0.524782 -2.40625,1.59375 -0.063562,1.024947 0.924797,1.4375 1.59375,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -15.875,12.21875 -15.875,12.21875 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.8828973 26.8125,6.34375 26.805335,6.3388584 26.788292,6.317553 26.78125,6.3125 26.570707,6.1513121 26.216591,6.0306895 25.8125,6.03125 z"
+ style="opacity:0.51999996;fill:url(#radialGradient39177);fill-opacity:1;fill-rule:evenodd;stroke:none"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+</svg>
diff --git a/release/freedesktop/icons/22x22/blender.xcf.bz2 b/release/freedesktop/icons/22x22/blender.xcf.bz2
deleted file mode 100644
index fb4396252ab..00000000000
--- a/release/freedesktop/icons/22x22/blender.xcf.bz2
+++ /dev/null
Binary files differ
diff --git a/release/freedesktop/icons/32x32/blender.png b/release/freedesktop/icons/32x32/blender.png
index 4c9acf10d63..6426ade96b6 100644
--- a/release/freedesktop/icons/32x32/blender.png
+++ b/release/freedesktop/icons/32x32/blender.png
Binary files differ
diff --git a/release/freedesktop/icons/32x32/blender.svg b/release/freedesktop/icons/32x32/blender.svg
index 241111c5c64..030d551699b 100644
--- a/release/freedesktop/icons/32x32/blender.svg
+++ b/release/freedesktop/icons/32x32/blender.svg
@@ -1,8 +1,9 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://web.resource.org/cc/"
+ xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
@@ -13,15 +14,14 @@
height="32"
id="svg7854"
sodipodi:version="0.32"
- inkscape:version="0.44+devel"
+ inkscape:version="0.48.0 r9654"
version="1.0"
- sodipodi:docbase="/home/jimmac/gfx/ximian/art/icons/application-icons/blender/32x32"
sodipodi:docname="blender.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
- inkscape:export-filename="/home/jimmac/gfx/ximian/art/icons/application-icons/blender/32x32/blender.png"
+ sodipodi:modified="true"
+ inkscape:export-filename="/home/user/my/blender/builds/blender/release/freedesktop/icons/32x32/blender.png"
inkscape:export-xdpi="90"
- inkscape:export-ydpi="90"
- sodipodi:modified="true">
+ inkscape:export-ydpi="90">
<defs
id="defs7856">
<linearGradient
@@ -88,11 +88,11 @@
xlink:href="#linearGradient3564"
id="linearGradient34576"
gradientUnits="userSpaceOnUse"
- x1="213.58719"
- y1="195.85153"
- x2="183.16304"
- y2="-404.09323"
- gradientTransform="matrix(4.454064e-2,7.407134e-4,-7.396764e-4,4.445763e-2,14.51614,17.23777)" />
+ x1="185.9903"
+ y1="193.33229"
+ x2="190.46461"
+ y2="-458.05771"
+ gradientTransform="matrix(0.06818845,0,0,0.06818845,22.51112,27.02885)" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient35488"
@@ -111,7 +111,7 @@
x1="21.204315"
y1="21.699249"
x2="20.155914"
- y2="-26.279823"
+ y2="-26.908371"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
@@ -131,7 +131,7 @@
fx="26.109201"
fy="19.668886"
r="20.278975"
- gradientTransform="matrix(1.034353,0,0,0.794876,-9.267532,-3.559595)"
+ gradientTransform="matrix(1.647222,0,0,1.26792,-15.47413,-5.79794)"
gradientUnits="userSpaceOnUse" />
</defs>
<sodipodi:namedview
@@ -144,19 +144,20 @@
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="1"
- inkscape:cx="43.462736"
- inkscape:cy="4.2521067"
+ inkscape:zoom="8.1228891"
+ inkscape:cx="39.360762"
+ inkscape:cy="28.503541"
inkscape:document-units="px"
inkscape:current-layer="layer1"
- width="32px"
- height="32px"
+ width="48px"
+ height="48px"
inkscape:showpageshadow="false"
- inkscape:window-width="1046"
- inkscape:window-height="975"
- inkscape:window-x="66"
- inkscape:window-y="135"
- showgrid="true" />
+ inkscape:window-width="1392"
+ inkscape:window-height="976"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ showgrid="false"
+ inkscape:window-maximized="1" />
<metadata
id="metadata7859">
<rdf:RDF>
@@ -173,6 +174,7 @@
<dc:source>http://jimmac.musichall.cz</dc:source>
<cc:license
rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ <dc:title></dc:title>
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
@@ -194,45 +196,55 @@
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
- id="layer1">
- <path
- sodipodi:type="arc"
- style="opacity:0.54857142;color:black;fill:url(#radialGradient35494);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path35486"
- sodipodi:cx="28.019106"
- sodipodi:cy="38.98439"
- sodipodi:rx="15.467961"
- sodipodi:ry="5.3033009"
- d="M 43.487067 38.98439 A 15.467961 5.3033009 0 1 1 12.551145,38.98439 A 15.467961 5.3033009 0 1 1 43.487067 38.98439 z"
- transform="matrix(0.855157,0,0,0.922661,-5.661873,-11.9649)" />
- <path
- style="fill:#f57900;fill-rule:evenodd;stroke:#ce5c00;stroke-width:0.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
- id="path2482"
- d="M 10.187586,18.047598 C 10.194151,18.43397 10.319437,19.185177 10.503745,19.77445 C 10.894027,21.016706 11.555231,22.168099 12.476153,23.182358 C 13.420699,24.222933 14.58237,25.060495 15.925076,25.654464 C 17.337953,26.27861 18.867652,26.597469 20.454999,26.594958 C 22.042346,26.591604 23.571927,26.267543 24.984133,25.638869 C 26.326319,25.039035 27.487985,24.199467 28.431866,23.156206 C 29.350723,22.137924 30.010647,20.984688 30.400893,19.741759 C 30.598368,19.11307 30.720948,18.475882 30.772163,17.835427 C 30.821363,17.2061 30.800373,16.573491 30.710538,15.943511 C 30.536069,14.713677 30.109048,13.560455 29.453827,12.508078 C 28.852842,11.542152 28.079572,10.69606 27.160546,9.9842375 C 27.160546,9.9842375 27.161885,9.9829095 27.161885,9.9829095 C 27.161885,9.9829095 17.881797,2.8677916 17.881797,2.8677916 C 17.873902,2.861242 17.866682,2.8546924 17.858117,2.8488013 C 17.248098,2.3825367 16.224172,2.1628727 15.555131,2.6311026 C 14.876884,3.1039168 14.822425,4.0642627 15.423916,4.5593548 C 16.698828,5.564183 17.880332,6.5265263 19.162309,7.531231 C 19.162309,7.531231 6.4113444,7.545485 6.4113444,7.545485 C 5.0727388,7.545485 4.4964734,8.5678876 4.4728736,9.5288768 C 4.4498234,10.467487 5.2620561,11.472929 6.424444,11.473885 C 6.424444,11.473885 10.390015,11.491386 12.381198,11.487462 C 8.9576952,13.962892 5.5336567,16.437594 2.1103869,18.913339 C 1.1054891,19.68275 0.96699194,20.963058 1.5999701,21.773125 C 2.2441003,22.596939 3.4242293,22.597608 4.4422427,21.777148 C 4.4422427,21.777148 10.265656,17.018805 10.265656,17.018805 C 10.265656,17.018805 10.181697,17.661879 10.187586,18.047598 z "
- sodipodi:nodetypes="csssssssssscccssccczsccsccc" />
- <path
- sodipodi:type="arc"
- style="opacity:1;color:black;fill:url(#linearGradient39161);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:square;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
- id="path39153"
- sodipodi:cx="31.1875"
- sodipodi:cy="25.75"
- sodipodi:rx="11.5625"
- sodipodi:ry="10.125"
- d="M 42.75 25.75 A 11.5625 10.125 0 1 1 19.625,25.75 A 11.5625 10.125 0 1 1 42.75 25.75 z"
- transform="matrix(0.551379,0,0,0.562462,3.360761,1.826627)" />
- <path
- style="opacity:0.4857143;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient34576);stroke-width:0.99999857;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="M 16.183788,3.9296777 C 16.183788,3.9296777 22.025089,8.4966596 22.025089,8.4966596 C 22.025089,8.4966596 6.9390429,8.5415355 6.9390429,8.5415355 C 6.3165584,8.5315997 5.5564454,8.6449512 5.5327974,9.4661791 C 5.5073593,10.349574 6.2671953,10.457569 6.7979051,10.464836 C 6.7979051,10.464836 15.347353,10.518394 15.347353,10.518394 C 15.347353,10.518394 3.079864,19.266484 3.079864,19.266484 C 1.47422,20.468758 1.9792489,22.058029 3.8906658,20.968571 C 3.8906658,20.968571 11.342463,15.000098 11.342463,15.000098 C 11.056594,17.35207 10.954659,19.925404 12.987785,22.280595 C 14.812944,24.394875 17.412379,25.450616 20.14939,25.602847 C 22.895537,25.619861 25.602761,24.674185 27.502194,22.686776 C 30.98046,18.579998 30.310289,13.928183 26.644414,10.848146 C 23.747065,8.4138175 20.584277,6.070626 17.555006,3.7958257 C 16.683886,3.1416665 15.680806,3.4366807 16.183788,3.9296777 z "
- id="path3562"
- sodipodi:nodetypes="ccczcccscsccsss" />
- <path
- style="fill:#3465a4;fill-rule:evenodd;stroke:none;stroke-width:1.0074476;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
- id="path2478"
- d="M 16.870671,15.810225 C 16.920643,14.898262 17.366801,14.093269 18.037494,13.523364 C 18.697519,12.963129 19.583821,12.621056 20.551972,12.621056 C 21.519507,12.621056 22.40581,12.963129 23.065682,13.523364 C 23.737114,14.093269 24.182732,14.897658 24.233288,15.809622 C 24.285081,16.74818 23.909289,17.619653 23.250649,18.265104 C 22.579217,18.92264 21.621855,19.335417 20.551972,19.335417 C 19.481474,19.335417 18.524111,18.92264 17.85271,18.265104 C 17.193393,17.619653 16.818896,16.74818 16.870671,15.810225 z " />
- <path
- style="opacity:0.51999996;fill:url(#radialGradient39177);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="M 15.941783,4.3847816 C 17.160224,5.348799 19.447413,7.1153436 20.65481,8.0968354 C 20.65481,8.0968354 9.073948,8.076863 6.1653597,8.0745003 C 5.5669549,8.0749003 5.063419,8.5382068 5.0653433,9.4713907 C 5.0672676,10.404575 5.8023091,10.947103 6.2223706,10.947103 C 6.2223706,10.947103 13.891753,10.97234 13.891753,10.97234 C 13.891753,10.97234 3.0882332,18.695586 3.0882332,18.695586 C 1.1062913,20.339688 3.0177499,22.143676 4.8637336,20.782461 C 4.8637337,20.782461 10.861827,15.991544 10.861827,15.991544 C 10.861827,15.991544 10.271137,18.152894 11.144276,20.090121 C 12.499624,23.097221 18.793729,11.835099 29.102295,12.862231 C 28.569898,11.929654 27.713189,10.967578 26.774401,10.204911 C 26.774401,10.204911 20.820024,5.6743082 17.926696,3.45557 C 16.156642,2.1700393 14.822071,3.3579146 15.941783,4.3847816 z "
- id="path39166"
- sodipodi:nodetypes="ccczcccccscscc" />
+ id="layer1"
+ transform="translate(0,-16)">
+ <g
+ id="blender"
+ transform="matrix(0.65782075,0,0,0.65782075,-0.38501735,15.782256)"
+ inkscape:label="blender">
+ <path
+ transform="matrix(1.274286,0,0,1.377124,-7.569123,-16.70193)"
+ d="m 43.487067,38.98439 c 0,2.928932 -6.925242,5.303301 -15.467961,5.303301 -8.542719,0 -15.467961,-2.374369 -15.467961,-5.303301 0,-2.928932 6.925242,-5.303301 15.467961,-5.303301 8.542719,0 15.467961,2.374369 15.467961,5.303301 z"
+ sodipodi:ry="5.3033009"
+ sodipodi:rx="15.467961"
+ sodipodi:cy="38.98439"
+ sodipodi:cx="28.019106"
+ id="path35486"
+ style="opacity:0.54857142;color:#000000;fill:url(#radialGradient35494);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:nodetypes="csssssssssscccsscccscccssccc"
+ d="m 16.048489,28.093447 c 0.0098,0.576682 0.196474,1.697902 0.471116,2.577425 0.581566,1.854137 1.56684,3.572658 2.939126,5.086496 1.407488,1.553118 3.138519,2.803227 5.139315,3.68976 2.105357,0.931573 4.384795,1.407488 6.750134,1.403741 2.365339,-0.005 4.644601,-0.488686 6.74896,-1.427017 2.00002,-0.895288 3.731043,-2.148391 5.13754,-3.705517 1.369207,-1.519844 2.352576,-3.241114 2.934089,-5.096258 0.294262,-0.938353 0.476921,-1.889392 0.553238,-2.845308 0.07331,-0.939306 0.04204,-1.883511 -0.09183,-2.823792 -0.259981,-1.835599 -0.896294,-3.556847 -1.872652,-5.12758 -0.895541,-1.441699 -2.047808,-2.70454 -3.417268,-3.766975 0,0 0.002,-0.002 0.002,-0.002 0,0 -13.828458,-10.6197195 -13.828458,-10.6197195 -0.01176,-0.00978 -0.02252,-0.019551 -0.03529,-0.028344 -0.909003,-0.6959264 -2.434775,-0.6939758 -3.431728,0.00488 -1.01067,0.7057021 -1.091821,1.8092613 -0.195527,2.5482146 1.899775,1.4997633 3.792068,3.0680399 5.702368,4.5676189 0,0 -17.551681,-0.01171 -17.551681,-0.01171 -1.994685,0 -3.1682604,0.947915 -3.4153942,2.333683 -0.2180771,1.222836 0.7479213,2.738129 2.4800212,2.738129 2.956573,0.0039 5.942111,-0.0069 8.909215,-0.01272 0,0 -15.901723,11.764162 -15.901723,11.764162 -0.020527,0.01564 -0.041053,0.02933 -0.06158,0.04497 -1.4974197,1.148389 -1.9831951,3.059322 -1.0399808,4.268393 0.9598323,1.22959 2.9977653,1.230588 4.5147288,0.006 0,0 8.677593,-7.102098 8.677593,-7.102098 0,0 -0.12511,0.959824 -0.116333,1.535532 z"
+ id="path2482"
+ style="fill:#f57900;fill-rule:evenodd;stroke:#ce5c00;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none"
+ inkscape:connector-curvature="0" />
+ <path
+ transform="matrix(0.821621,0,0,0.839506,5.875686,3.882724)"
+ d="m 42.75,25.75 c 0,5.591883 -5.176708,10.125 -11.5625,10.125 -6.385792,0 -11.5625,-4.533117 -11.5625,-10.125 0,-5.591883 5.176708,-10.125 11.5625,-10.125 6.385792,0 11.5625,4.533117 11.5625,10.125 z"
+ sodipodi:ry="10.125"
+ sodipodi:rx="11.5625"
+ sodipodi:cy="25.75"
+ sodipodi:cx="31.1875"
+ id="path39153"
+ style="color:#000000;fill:url(#linearGradient39161);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ sodipodi:type="arc" />
+ <path
+ sodipodi:nodetypes="cssssscscczccsccssssccscccccscssc"
+ id="path3562"
+ d="m 25.796988,6.0267804 c -0.404852,5.53e-4 -0.818619,0.1256944 -1.095272,0.3196267 -7.14e-4,7.142e-4 -0.0014,0.00143 -0.0021,0.00213 -0.280209,0.1956525 -0.336859,0.3680061 -0.345206,0.4602725 -0.0083,0.092266 -0.01324,0.1672776 0.189655,0.3345475 0.01899,0.015735 0.03747,0.032076 0.0554,0.049009 0.124258,0.1010285 5.704394,4.6389489 5.704394,4.6389489 0.373658,0.304091 0.51584,0.810232 0.355197,1.264415 -0.160635,0.454191 -0.589422,0.382732 -1.071174,0.384283 -5.634142,0.05114 -17.60967,0.01918 -17.60967,0.01918 -0.952967,6.38e-4 -2.3472795,0.516793 -2.4135719,1.585761 -0.063562,1.024947 0.9093059,1.457499 1.5782589,1.457499 0,0 8.830403,-0.01705 8.830403,-0.01705 0.488364,-5.91e-4 0.922857,0.221532 1.080466,0.683755 0.15761,0.462231 0.0033,0.53156 -0.383664,0.829439 0,0 -15.9006939,12.205735 -15.9006939,12.205735 -0.00142,0.0014 -0.00284,0.0028 -0.00426,0.0043 -0.064038,0.04879 -0.084772,0.06226 -0.061795,0.04476 -0.5536756,0.424618 -0.8961097,0.98072 -1.0185711,1.476701 -0.1224537,0.495981 -0.04659,0.882548 0.1875202,1.182646 0.4788333,0.613413 1.7693735,0.732111 2.8980115,-0.178996 0,0 8.6727243,-7.09799 8.6727243,-7.09799 0.361955,-0.295752 0.867758,-0.340606 1.276111,-0.113169 0.408345,0.227437 0.636512,0.681082 0.575631,1.144518 0,0 -0.112502,0.980045 -0.10655,1.370159 0.192357,2.636407 1.448328,4.914995 3.115366,6.91474 2.877746,3.172809 6.84939,4.556285 11.042271,4.719919 4.20342,-0.04394 8.185784,-1.662428 11.042264,-4.758277 5.218918,-6.385867 3.941737,-13.3639 -1.747326,-17.993227 C 36.14442,13.301598 31.42752,9.8792062 26.81986,6.3400589 c -0.0043,-0.00352 -0.0086,-0.00707 -0.01279,-0.010651 -0.0072,-0.00489 -0.01427,-0.00987 -0.02131,-0.014921 -0.210578,-0.1612288 -0.584681,-0.288267 -0.988772,-0.2877065 z"
+ style="opacity:0.4857143;fill:none;stroke:url(#linearGradient34576);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ inkscape:connector-curvature="0" />
+ <path
+ d="m 26.007076,24.754048 c 0.07447,-1.361157 0.739293,-2.562655 1.738705,-3.413271 0.983518,-0.836183 2.304215,-1.346747 3.746876,-1.346747 1.441743,0 2.762441,0.510564 3.745729,1.346747 1.000515,0.850616 1.664539,2.051213 1.739875,3.41237 0.07718,1.400852 -0.4828,2.701576 -1.46425,3.66495 -1.000516,0.981409 -2.427099,1.597503 -4.021354,1.597503 -1.595172,0 -3.021756,-0.616094 -4.022225,-1.597503 -0.982461,-0.963374 -1.540507,-2.264098 -1.463356,-3.664049 z"
+ id="path2478"
+ style="fill:#3465a4;fill-rule:evenodd;stroke:none"
+ inkscape:connector-curvature="0" />
+ <path
+ sodipodi:nodetypes="csssscsccsscsccssssscsscccsssc"
+ id="path39166"
+ d="m 25.8125,6.03125 c -0.404852,5.528e-4 -0.848347,0.1185677 -1.125,0.3125 -0.280209,0.1956523 -0.335403,0.3764836 -0.34375,0.46875 -0.0083,0.092267 -0.01539,0.1764801 0.1875,0.34375 0.01899,0.015735 0.04457,0.014317 0.0625,0.03125 0.124258,0.1010283 5.71875,4.65625 5.71875,4.65625 0.373658,0.304091 0.504393,0.795817 0.34375,1.25 -0.160635,0.454191 -0.580748,0.373449 -1.0625,0.375 -5.634142,0.05114 -17.625,0.03125 -17.625,0.03125 -0.952967,6.38e-4 -2.3399576,0.524782 -2.40625,1.59375 -0.063562,1.024947 0.924797,1.4375 1.59375,1.4375 0,-1e-6 8.8125,0 8.8125,0 0.488364,-5.92e-4 0.936141,0.225277 1.09375,0.6875 0.157609,0.462231 -0.01926,0.514621 -0.40625,0.8125 0,0 -15.875,12.21875 -15.875,12.21875 -0.00142,0.0014 -0.029829,-0.0014 -0.03125,0 -0.064037,0.04879 -0.054226,0.04875 -0.03125,0.03125 -0.5536758,0.424619 -0.9087886,1.004019 -1.03125,1.5 -0.1224536,0.495981 -0.04661,0.856152 0.1875,1.15625 0.4788333,0.613413 1.777612,0.754857 2.90625,-0.15625 1e-7,10e-7 8.65625,-7.09375 8.65625,-7.09375 0.361955,-0.295753 0.872897,-0.352437 1.28125,-0.125 0.408345,0.227436 0.623381,0.692814 0.5625,1.15625 0,-1e-6 -0.0997,0.953636 -0.09375,1.34375 0.09498,1.301756 0.451616,2.521825 0.989039,3.664234 C 20.799917,36.321089 27.770982,19.392853 44.1875,21.03125 43.339652,19.54368 42.151282,18.185293 40.65625,16.96875 36.159865,13.309932 31.42016,9.8828973 26.8125,6.34375 26.805335,6.3388584 26.788292,6.317553 26.78125,6.3125 26.570707,6.1513121 26.216591,6.0306895 25.8125,6.03125 z"
+ style="opacity:0.51999996;fill:url(#radialGradient39177);fill-opacity:1;fill-rule:evenodd;stroke:none"
+ inkscape:connector-curvature="0" />
+ </g>
</g>
</svg>
diff --git a/release/getversion.py b/release/getversion.py
deleted file mode 100755
index 4c477229ef9..00000000000
--- a/release/getversion.py
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python
-# -*- mode: python; tab-width: 4; indent-tabs-mode: t; -*-
-# vim: tabstop=4
-# $Id$
-# ***** 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.
-#
-# The Original Code is Copyright (C) 2008 by the Blender Foundation
-# All rights reserved.
-#
-# The Original Code is: see repository.
-#
-# Contributor(s): see repository.
-
-# <pep8-80 compliant>
-
-import sys
-import os
-import re
-
-nanblenderhome = os.getenv("NANBLENDERHOME")
-
-if nanblenderhome is None:
- nanblenderhome = os.path.dirname(os.path.abspath(sys.argv[0])) + "/.."
-
-config = nanblenderhome + "/source/blender/blenkernel/BKE_blender.h"
-
-infile = open(config)
-
-major = None
-minor = None
-
-for line in infile.readlines():
- m = re.search("#define BLENDER_VERSION\s+(\d+)", line)
- if m:
- major = m.group(1)
- m = re.search("#define BLENDER_SUBVERSION\s+(\d+)", line)
- if m:
- minor = m.group(1)
- if minor and major:
- major = float(major) / 100.0
- break
-
-infile.close()
-
-# Major was changed to float, but minor is still a string
-if minor and major:
- if minor == "0":
- print "%.2f" % major
- else:
- print "%.2f.%s" % (major, minor)
-else:
- print "unknownversion"
diff --git a/release/plugins/sequence/color-correction-hsv.c b/release/plugins/sequence/color-correction-hsv.c
index 120ca76bbe7..cff2f1aad82 100644
--- a/release/plugins/sequence/color-correction-hsv.c
+++ b/release/plugins/sequence/color-correction-hsv.c
@@ -187,12 +187,13 @@ void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width,
double gamma_table[256];
double uv_table[256];
float *destf = out->rect_float;
- float *src1f = ibuf1->rect_float;
+ float *src1f;
if (!ibuf1) return;
dest= (char *) out->rect;
src1= (char *) ibuf1->rect;
+ src1f= ibuf1->rect_float;
for (y = 0; y < 256; y++) {
float v = 1.0 * y / 255;
diff --git a/release/plugins/sequence/color-correction-yuv.c b/release/plugins/sequence/color-correction-yuv.c
index 721cadb07ce..b80489f3b0b 100644
--- a/release/plugins/sequence/color-correction-yuv.c
+++ b/release/plugins/sequence/color-correction-yuv.c
@@ -120,12 +120,13 @@ void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width,
float gamma_table[256];
float uv_table[256];
float *destf = out->rect_float;
- float *src1f = ibuf1->rect_float;
+ float *src1f;
if (!ibuf1) return;
dest= (char *) out->rect;
src1= (char *) ibuf1->rect;
+ src1f= ibuf1->rect_float;
for (y = 0; y < 256; y++) {
float v = 1.0 * y / 255;
diff --git a/release/scripts/io/netrender/__init__.py b/release/scripts/io/netrender/__init__.py
index b8c1fddc691..6c4ed4119fc 100644
--- a/release/scripts/io/netrender/__init__.py
+++ b/release/scripts/io/netrender/__init__.py
@@ -20,16 +20,18 @@
# To support reload properly, try to access a package var, if it's there, reload everything
if "init_data" in locals():
- reload(model)
- reload(operators)
- reload(client)
- reload(slave)
- reload(master)
- reload(master_html)
- reload(utils)
- reload(balancing)
- reload(ui)
- reload(repath)
+ import imp
+ imp.reload(model)
+ imp.reload(operators)
+ imp.reload(client)
+ imp.reload(slave)
+ imp.reload(master)
+ imp.reload(master_html)
+ imp.reload(utils)
+ imp.reload(balancing)
+ imp.reload(ui)
+ imp.reload(repath)
+ imp.reload(versioning)
else:
from netrender import model
from netrender import operators
@@ -41,18 +43,25 @@ else:
from netrender import balancing
from netrender import ui
from netrender import repath
+ from netrender import versioning
jobs = []
slaves = []
blacklist = []
init_file = ""
-init_address = True
+valid_address = False
init_data = True
def register():
ui.addProperties()
+
+ import bpy
+ scene = bpy.context.scene
+ if scene:
+ netsettings = scene.network_render
+ ui.init_data(netsettings)
def unregister():
diff --git a/release/scripts/io/netrender/balancing.py b/release/scripts/io/netrender/balancing.py
index 95f345249f2..dde3ad53084 100644
--- a/release/scripts/io/netrender/balancing.py
+++ b/release/scripts/io/netrender/balancing.py
@@ -25,6 +25,9 @@ class RatingRule:
def __init__(self):
self.enabled = True
+ def id(self):
+ return str(id(self))
+
def rate(self, job):
return 0
@@ -32,6 +35,9 @@ class ExclusionRule:
def __init__(self):
self.enabled = True
+ def id(self):
+ return str(id(self))
+
def test(self, job):
return False
@@ -39,6 +45,9 @@ class PriorityRule:
def __init__(self):
self.enabled = True
+ def id(self):
+ return str(id(self))
+
def test(self, job):
return False
@@ -50,13 +59,13 @@ class Balancer:
def ruleByID(self, rule_id):
for rule in self.rules:
- if id(rule) == rule_id:
+ if rule.id() == rule_id:
return rule
for rule in self.priorities:
- if id(rule) == rule_id:
+ if rule.id() == rule_id:
return rule
for rule in self.exceptions:
- if id(rule) == rule_id:
+ if rule.id() == rule_id:
return rule
return None
diff --git a/release/scripts/io/netrender/client.py b/release/scripts/io/netrender/client.py
index c17944725b0..bc43b8cfbb7 100644
--- a/release/scripts/io/netrender/client.py
+++ b/release/scripts/io/netrender/client.py
@@ -92,8 +92,83 @@ def addPointCache(job, ob, point_cache, default_path):
previous_frame = previous_item[0]
job.addFile(cache_path + current_file, previous_frame + 1, next_frame - 1)
+def fillCommonJobSettings(job, job_name, netsettings):
+ job.name = job_name
+ job.category = netsettings.job_category
+
+ for slave in netrender.blacklist:
+ job.blacklist.append(slave.id)
+
+ job.chunks = netsettings.chunks
+ job.priority = netsettings.priority
+
+ if netsettings.job_type == "JOB_BLENDER":
+ job.type = netrender.model.JOB_BLENDER
+ elif netsettings.job_type == "JOB_PROCESS":
+ job.type = netrender.model.JOB_PROCESS
+ elif netsettings.job_type == "JOB_VCS":
+ job.type = netrender.model.JOB_VCS
+
def clientSendJob(conn, scene, anim = False):
netsettings = scene.network_render
+ if netsettings.job_type == "JOB_BLENDER":
+ return clientSendJobBlender(conn, scene, anim)
+ elif netsettings.job_type == "JOB_VCS":
+ return clientSendJobVCS(conn, scene, anim)
+
+def clientSendJobVCS(conn, scene, anim = False):
+ netsettings = scene.network_render
+ job = netrender.model.RenderJob()
+
+ if anim:
+ for f in range(scene.frame_start, scene.frame_end + 1):
+ job.addFrame(f)
+ else:
+ job.addFrame(scene.frame_current)
+
+ filename = bpy.data.filepath
+
+ if not filename.startswith(netsettings.vcs_wpath):
+ # this is an error, need better way to handle this
+ return
+
+ filename = filename[len(netsettings.vcs_wpath):]
+
+ if filename[0] in (os.sep, os.altsep):
+ filename = filename[1:]
+
+ print("CREATING VCS JOB", filename)
+
+ job.addFile(filename, signed=False)
+
+ job_name = netsettings.job_name
+ path, name = os.path.split(filename)
+ if job_name == "[default]":
+ job_name = name
+
+
+ fillCommonJobSettings(job, job_name, netsettings)
+
+ # VCS Specific code
+ job.version_info = netrender.model.VersioningInfo()
+ job.version_info.system = netsettings.vcs_system
+ job.version_info.wpath = netsettings.vcs_wpath
+ job.version_info.rpath = netsettings.vcs_rpath
+ job.version_info.revision = netsettings.vcs_revision
+
+ # try to send path first
+ conn.request("POST", "/job", json.dumps(job.serialize()))
+ response = conn.getresponse()
+ response.read()
+
+ job_id = response.getheader("job-id")
+
+ # a VCS job is always good right now, need error handling
+
+ return job_id
+
+def clientSendJobBlender(conn, scene, anim = False):
+ netsettings = scene.network_render
job = netrender.model.RenderJob()
if anim:
@@ -140,15 +215,13 @@ def clientSendJob(conn, scene, anim = False):
for object in bpy.data.objects:
for modifier in object.modifiers:
if modifier.type == 'FLUID_SIMULATION' and modifier.settings.type == "DOMAIN":
- addFluidFiles(job, bpy.path.abspath(modifier.settings.path))
+ addFluidFiles(job, bpy.path.abspath(modifier.settings.filepath))
elif modifier.type == "CLOTH":
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SOFT_BODY":
addPointCache(job, object, modifier.point_cache, default_path)
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
- addPointCache(job, object, modifier.domain_settings.point_cache_low, default_path)
- if modifier.domain_settings.use_high_resolution:
- addPointCache(job, object, modifier.domain_settings.point_cache_high, default_path)
+ addPointCache(job, object, modifier.domain_settings.point_cache, default_path)
elif modifier.type == "MULTIRES" and modifier.is_external:
file_path = bpy.path.abspath(modifier.filepath)
job.addFile(file_path)
@@ -160,14 +233,7 @@ def clientSendJob(conn, scene, anim = False):
#print(job.files)
- job.name = job_name
- job.category = netsettings.job_category
-
- for slave in netrender.blacklist:
- job.blacklist.append(slave.id)
-
- job.chunks = netsettings.chunks
- job.priority = netsettings.priority
+ fillCommonJobSettings(job, job_name, netsettings)
# try to send path first
conn.request("POST", "/job", json.dumps(job.serialize()))
@@ -195,7 +261,7 @@ def requestResult(conn, job_id, frame):
class NetworkRenderEngine(bpy.types.RenderEngine):
bl_idname = 'NET_RENDER'
bl_label = "Network Render"
- bl_postprocess = False
+ bl_use_postprocess = False
def render(self, scene):
if scene.network_render.mode == "RENDER_CLIENT":
self.render_client(scene)
@@ -211,7 +277,7 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
address = "" if netsettings.server_address == "[default]" else netsettings.server_address
- master.runMaster((address, netsettings.server_port), netsettings.use_master_broadcast, netsettings.use_master_clear, netsettings.path, self.update_stats, self.test_break)
+ master.runMaster((address, netsettings.server_port), netsettings.use_master_broadcast, netsettings.use_master_clear, bpy.path.abspath(netsettings.path), self.update_stats, self.test_break)
def render_slave(self, scene):
@@ -236,10 +302,11 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
# reading back result
self.update_stats("", "Network render waiting for results")
-
+
+
requestResult(conn, job_id, scene.frame_current)
response = conn.getresponse()
- response.read()
+ buf = response.read()
if response.status == http.client.NO_CONTENT:
new_job = True
@@ -248,13 +315,13 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
requestResult(conn, job_id, scene.frame_current)
response = conn.getresponse()
- response.read()
-
+ buf = response.read()
+
while response.status == http.client.ACCEPTED and not self.test_break():
time.sleep(1)
requestResult(conn, job_id, scene.frame_current)
response = conn.getresponse()
- response.read()
+ buf = response.read()
# cancel new jobs (animate on network) on break
if self.test_break() and new_job:
@@ -271,18 +338,22 @@ class NetworkRenderEngine(bpy.types.RenderEngine):
r = scene.render
x= int(r.resolution_x*r.resolution_percentage*0.01)
y= int(r.resolution_y*r.resolution_percentage*0.01)
+
+ result_path = os.path.join(bpy.path.abspath(netsettings.path), "output.exr")
+
+ folder = os.path.split(result_path)[0]
+
+ if not os.path.exists(folder):
+ os.mkdir(folder)
- f = open(os.path.join(netsettings.path, "output.exr"), "wb")
- buf = response.read(1024)
+ f = open(result_path, "wb")
- while buf:
- f.write(buf)
- buf = response.read(1024)
+ f.write(buf)
f.close()
result = self.begin_result(0, 0, x, y)
- result.load_from_file(os.path.join(netsettings.path, "output.exr"))
+ result.load_from_file(result_path)
self.end_result(result)
conn.close()
@@ -294,7 +365,6 @@ def compatible(module):
except: pass
del module
-#compatible("properties_render")
compatible("properties_world")
compatible("properties_material")
compatible("properties_data_mesh")
diff --git a/release/scripts/io/netrender/master.py b/release/scripts/io/netrender/master.py
index 11409bf372e..793e3bb51bf 100644
--- a/release/scripts/io/netrender/master.py
+++ b/release/scripts/io/netrender/master.py
@@ -27,6 +27,7 @@ from netrender.utils import *
import netrender.model
import netrender.balancing
import netrender.master_html
+import netrender.thumbnail as thumbnail
class MRenderFile(netrender.model.RenderFile):
def __init__(self, filepath, index, start, end, signature):
@@ -35,7 +36,7 @@ class MRenderFile(netrender.model.RenderFile):
def test(self):
self.found = os.path.exists(self.filepath)
- if self.found:
+ if self.found and self.signature != None:
found_signature = hashFile(self.filepath)
self.found = self.signature == found_signature
@@ -82,8 +83,6 @@ class MRenderJob(netrender.model.RenderJob):
self.save_path = ""
self.files = [MRenderFile(rfile.filepath, rfile.index, rfile.start, rfile.end, rfile.signature) for rfile in job_info.files]
- self.resolution = None
-
def initInfo(self):
if not self.resolution:
self.resolution = tuple(getFileInfo(self.files[0].filepath, ["bpy.context.scene.render.resolution_x", "bpy.context.scene.render.resolution_y", "bpy.context.scene.render.resolution_percentage"]))
@@ -105,9 +104,11 @@ class MRenderJob(netrender.model.RenderJob):
self.chunks = info_map["chunks"]
def testStart(self):
- for f in self.files:
- if not f.test():
- return False
+ # Don't test files for versionned jobs
+ if not self.version_info:
+ for f in self.files:
+ if not f.test():
+ return False
self.start()
self.initInfo()
@@ -201,6 +202,15 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
# is extremely slow due to some timeout..
sys.stderr.write("[%s] %s\n" % (self.log_date_time_string(), format%args))
+ def getInfoMap(self):
+ length = int(self.headers['content-length'])
+
+ if length > 0:
+ msg = str(self.rfile.read(length), encoding='utf8')
+ return json.loads(msg)
+ else:
+ return {}
+
def send_head(self, code = http.client.OK, headers = {}, content = "application/octet-stream"):
self.send_response(code)
self.send_header("Content-type", content)
@@ -297,7 +307,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
elif frame.status == DONE:
filename = os.path.join(job.save_path, "%06d.exr" % frame_number)
- thumbname = thumbnail(filename)
+ thumbname = thumbnail.generate(filename)
if thumbname:
f = open(thumbname, 'rb')
@@ -516,8 +526,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
job = self.server.getJobID(job_id)
if job:
- length = int(self.headers['content-length'])
- info_map = eval(str(self.rfile.read(length), encoding='utf8'))
+ info_map = self.getInfoMap()
job.edit(info_map)
self.send_head()
@@ -529,8 +538,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.send_head(http.client.NO_CONTENT)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "/balance_limit":
- length = int(self.headers['content-length'])
- info_map = eval(str(self.rfile.read(length), encoding='utf8'))
+ info_map = self.getInfoMap()
for rule_id, limit in info_map.items():
try:
rule = self.server.balancer.ruleByID(rule_id)
@@ -542,8 +550,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
self.send_head()
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "/balance_enable":
- length = int(self.headers['content-length'])
- info_map = eval(str(self.rfile.read(length), encoding='utf8'))
+ info_map = self.getInfoMap()
for rule_id, enabled in info_map.items():
rule = self.server.balancer.ruleByID(rule_id)
if rule:
@@ -555,13 +562,8 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
match = cancel_pattern.match(self.path)
if match:
- length = int(self.headers['content-length'])
-
- if length > 0:
- info_map = eval(str(self.rfile.read(length), encoding='utf8'))
- clear = info_map.get("clear", False)
- else:
- clear = False
+ info_map = self.getInfoMap()
+ clear = info_map.get("clear", False)
job_id = match.groups()[0]
@@ -582,13 +584,8 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
match = pause_pattern.match(self.path)
if match:
- length = int(self.headers['content-length'])
-
- if length > 0:
- info_map = eval(str(self.rfile.read(length), encoding='utf8'))
- status = info_map.get("status", None)
- else:
- status = None
+ info_map = self.getInfoMap()
+ status = info_map.get("status", None)
job_id = match.groups()[0]
@@ -607,13 +604,8 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
elif self.path == "/clear":
# cancel all jobs
- length = int(self.headers['content-length'])
-
- if length > 0:
- info_map = eval(str(self.rfile.read(length), encoding='utf8'))
- clear = info_map.get("clear", False)
- else:
- clear = False
+ info_map = self.getInfoMap()
+ clear = info_map.get("clear", False)
self.server.stats("", "Clearing jobs")
self.server.clear(clear)
@@ -769,7 +761,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
frame = job[job_frame]
if frame:
- if job.type == netrender.model.JOB_BLENDER:
+ if job.hasRenderResult():
if job_result == DONE:
length = int(self.headers['content-length'])
buf = self.rfile.read(length)
@@ -820,7 +812,7 @@ class RenderHandler(http.server.BaseHTTPRequestHandler):
frame = job[job_frame]
if frame:
- if job.type == netrender.model.JOB_BLENDER:
+ if job.hasRenderResult():
length = int(self.headers['content-length'])
buf = self.rfile.read(length)
f = open(os.path.join(job.save_path, "%06d.jpg" % job_frame), 'wb')
diff --git a/release/scripts/io/netrender/master_html.py b/release/scripts/io/netrender/master_html.py
index 74155f6bd66..877273207a8 100644
--- a/release/scripts/io/netrender/master_html.py
+++ b/release/scripts/io/netrender/master_html.py
@@ -20,6 +20,7 @@ import os
import re
import shutil
from netrender.utils import *
+import netrender.model
src_folder = os.path.split(__file__)[0]
@@ -115,6 +116,7 @@ def get(handler):
"id",
"name",
"category",
+ "type",
"chunks",
"priority",
"usage",
@@ -139,6 +141,7 @@ def get(handler):
job.id,
link(job.name, "/html/job" + job.id),
job.category if job.category else "<i>None</i>",
+ netrender.model.JOB_TYPES[job.type],
str(job.chunks) +
"""<button title="increase chunks size" onclick="request('/edit_%s', &quot;{'chunks': %i}&quot;);">+</button>""" % (job.id, job.chunks + 1) +
"""<button title="decrease chunks size" onclick="request('/edit_%s', &quot;{'chunks': %i}&quot;);" %s>-</button>""" % (job.id, job.chunks - 1, "disabled=True" if job.chunks == 1 else ""),
@@ -180,28 +183,28 @@ def get(handler):
for rule in handler.server.balancer.rules:
rowTable(
"rating",
- checkbox("", rule.enabled, "balance_enable('%i', '%s')" % (id(rule), str(not rule.enabled))),
+ checkbox("", rule.enabled, "balance_enable('%s', '%s')" % (rule.id(), str(not rule.enabled).lower())),
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;"
+ """<button title="edit limit" onclick="balance_edit('%s', '%s');">edit</button>""" % (rule.id(), 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))),
+ checkbox("", rule.enabled, "balance_enable('%s', '%s')" % (rule.id(), str(not rule.enabled).lower())),
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;"
+ """<button title="edit limit" onclick="balance_edit('%s', '%s');">edit</button>""" % (rule.id(), 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))),
+ checkbox("", rule.enabled, "balance_enable('%s', '%s')" % (rule.id(), str(not rule.enabled).lower())),
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;"
+ """<button title="edit limit" onclick="balance_edit('%s', '%s');">edit</button>""" % (rule.id(), str(rule.limit)) if hasattr(rule, "limit") else "&nbsp;"
)
endTable()
@@ -228,39 +231,52 @@ def get(handler):
endTable()
- output("<h2>Files</h2>")
-
- startTable()
- headerTable("path")
-
- 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:
- 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;)'")
+ if job.type == netrender.model.JOB_BLENDER:
+ output("<h2>Files</h2>")
+
+ startTable()
+ headerTable("path")
+
+ 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"):
- rowTable(os.path.split(file.filepath)[1], class_style = "cache")
-
- if tot_fluid > 0:
- rowTable("%i fluid bake files" % tot_fluid, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.fluid&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
- for file in job.files:
- if file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
- rowTable(os.path.split(file.filepath)[1], class_style = "fluid")
-
- endTable()
+ tot_cache += 1
+ elif file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
+ tot_fluid += 1
+ else:
+ 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;)'")
+ for file in job.files:
+ if file.filepath.endswith(".bphys"):
+ rowTable(os.path.split(file.filepath)[1], class_style = "cache")
+
+ if tot_fluid > 0:
+ rowTable("%i fluid bake files" % tot_fluid, class_style = "toggle", extra = "onclick='toggleDisplay(&quot;.fluid&quot;, &quot;none&quot;, &quot;table-row&quot;)'")
+ for file in job.files:
+ if file.filepath.endswith(".bobj.gz") or file.filepath.endswith(".bvel.gz"):
+ rowTable(os.path.split(file.filepath)[1], class_style = "fluid")
+
+ endTable()
+ elif job.type == netrender.model.JOB_VCS:
+ output("<h2>Versioning</h2>")
+
+ startTable()
+
+ rowTable("System", job.version_info.system.name)
+ rowTable("Remote Path", job.version_info.rpath)
+ rowTable("Working Path", job.version_info.wpath)
+ rowTable("Revision", job.version_info.revision)
+ rowTable("Render File", job.files[0].filepath)
+
+ endTable()
if job.blacklist:
output("<h2>Blacklist</h2>")
diff --git a/release/scripts/io/netrender/model.py b/release/scripts/io/netrender/model.py
index e7656f498b4..5fc0bc2a0bb 100644
--- a/release/scripts/io/netrender/model.py
+++ b/release/scripts/io/netrender/model.py
@@ -20,6 +20,7 @@ import sys, os
import http, http.client, http.server, urllib
import subprocess, shutil, time, hashlib
+import netrender.versioning as versioning
from netrender.utils import *
class LogFile:
@@ -96,11 +97,65 @@ class RenderSlave:
JOB_BLENDER = 1
JOB_PROCESS = 2
+JOB_VCS = 3
JOB_TYPES = {
- JOB_BLENDER: "Blender",
- JOB_PROCESS: "Process"
- }
+ JOB_BLENDER: "Blender",
+ JOB_PROCESS: "Process",
+ JOB_VCS: "Versioned",
+ }
+
+class VersioningInfo:
+ def __init__(self, info = None):
+ self._system = None
+ self.wpath = ""
+ self.rpath = ""
+ self.revision = ""
+
+ @property
+ def system(self):
+ return self._system
+
+ @system.setter
+ def system(self, value):
+ self._system = versioning.SYSTEMS[value]
+
+ def update(self):
+ self.system.update(self)
+
+ def serialize(self):
+ return {
+ "wpath": self.wpath,
+ "rpath": self.rpath,
+ "revision": self.revision,
+ "system": self.system.name
+ }
+
+ @staticmethod
+ def generate(system, path):
+ vs = VersioningInfo()
+ vs.wpath = path
+ vs.system = system
+
+ vs.rpath = vs.system.path(path)
+ vs.revision = vs.system.revision(path)
+
+ return vs
+
+
+ @staticmethod
+ def materialize(data):
+ if not data:
+ return None
+
+ vs = VersioningInfo()
+ vs.wpath = data["wpath"]
+ vs.rpath = data["rpath"]
+ vs.revision = data["revision"]
+ vs.system = data["system"]
+
+ return vs
+
class RenderFile:
def __init__(self, filepath = "", index = 0, start = -1, end = -1, signature=0):
@@ -142,6 +197,10 @@ class RenderJob:
self.chunks = 0
self.priority = 0
self.blacklist = []
+
+ self.version_info = None
+
+ self.resolution = None
self.usage = 0.0
self.last_dispatched = 0.0
@@ -156,9 +215,19 @@ class RenderJob:
self.chunks = job_info.chunks
self.priority = job_info.priority
self.blacklist = job_info.blacklist
+ self.version_info = job_info.version_info
+
+ def hasRenderResult(self):
+ return self.type in (JOB_BLENDER, JOB_VCS)
- def addFile(self, file_path, start=-1, end=-1):
- signature = hashFile(file_path)
+ def rendersWithBlender(self):
+ return self.type in (JOB_BLENDER, JOB_VCS)
+
+ def addFile(self, file_path, start=-1, end=-1, signed=True):
+ if signed:
+ signature = hashFile(file_path)
+ else:
+ signature = None
self.files.append(RenderFile(file_path, len(self.files), start, end, signature))
def addFrame(self, frame_number, command = ""):
@@ -225,7 +294,9 @@ class RenderJob:
"priority": self.priority,
"usage": self.usage,
"blacklist": self.blacklist,
- "last_dispatched": self.last_dispatched
+ "last_dispatched": self.last_dispatched,
+ "version_info": self.version_info.serialize() if self.version_info else None,
+ "resolution": self.resolution
}
@staticmethod
@@ -246,6 +317,11 @@ class RenderJob:
job.usage = data["usage"]
job.blacklist = data["blacklist"]
job.last_dispatched = data["last_dispatched"]
+ job.resolution = data["resolution"]
+
+ version_info = data.get("version_info", None)
+ if version_info:
+ job.version_info = VersioningInfo.materialize(version_info)
return job
diff --git a/release/scripts/io/netrender/netrender.js b/release/scripts/io/netrender/netrender.js
index 041a39a3ebc..1024a169571 100644
--- a/release/scripts/io/netrender/netrender.js
+++ b/release/scripts/io/netrender/netrender.js
@@ -20,9 +20,9 @@ function clear_jobs()
var r=confirm("Also delete files on master?");
if (r==true) {
- request('/clear', "{'clear':True}");
+ request('/clear', '{"clear":true}');
} else {
- request('/clear', "{'clear':False}");
+ request('/clear', '{"clear":false}');
}
}
@@ -31,9 +31,9 @@ function cancel_job(id)
var r=confirm("Also delete files on master?");
if (r==true) {
- request('/cancel_' + id, "{'clear':True}");
+ request('/cancel_' + id, '{"clear":true}');
} else {
- request('/cancel_' + id, "{'clear':False}");
+ request('/cancel_' + id, '{"clear":false}');
}
}
@@ -41,13 +41,13 @@ function balance_edit(id, old_value)
{
var new_value = prompt("New limit", old_value);
if (new_value != null && new_value != "") {
- request("/balance_limit", "{" + id + ":'" + new_value + "'}");
+ request("/balance_limit", '{"' + id + '":"' + new_value + '"}');
}
}
function balance_enable(id, value)
{
- request("/balance_enable", "{" + id + ":" + value + "}");
+ request("/balance_enable", '{"' + id + '":' + value + "}");
}
function showThumb(job, frame)
diff --git a/release/scripts/io/netrender/operators.py b/release/scripts/io/netrender/operators.py
index 2b40cd77125..f2c2fda7bde 100644
--- a/release/scripts/io/netrender/operators.py
+++ b/release/scripts/io/netrender/operators.py
@@ -26,6 +26,7 @@ import netrender
from netrender.utils import *
import netrender.client as client
import netrender.model
+import netrender.versioning as versioning
class RENDER_OT_netslave_bake(bpy.types.Operator):
'''NEED DESCRIPTION'''
@@ -61,12 +62,9 @@ class RENDER_OT_netslave_bake(bpy.types.Operator):
modifier.point_cache.use_disk_cache = True
modifier.point_cache.use_external = False
elif modifier.type == "SMOKE" and modifier.smoke_type == "TYPE_DOMAIN":
- modifier.domain_settings.point_cache_low.use_step = 1
- modifier.domain_settings.point_cache_low.use_disk_cache = True
- modifier.domain_settings.point_cache_low.use_external = False
- modifier.domain_settings.point_cache_high.use_step = 1
- modifier.domain_settings.point_cache_high.use_disk_cache = True
- modifier.domain_settings.point_cache_high.use_external = False
+ modifier.domain_settings.point_cache.use_step = 1
+ modifier.domain_settings.point_cache.use_disk_cache = True
+ modifier.domain_settings.point_cache.use_external = False
# particles modifier are stupid and don't contain data
# we have to go through the object property
@@ -354,7 +352,7 @@ class RENDER_OT_netclientcancel(bpy.types.Operator):
if conn:
job = netrender.jobs[netsettings.active_job_index]
- conn.request("POST", cancelURL(job.id))
+ conn.request("POST", cancelURL(job.id), json.dumps({'clear':False}))
response = conn.getresponse()
response.read()
@@ -381,7 +379,7 @@ class RENDER_OT_netclientcancelall(bpy.types.Operator):
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
- conn.request("POST", "/clear")
+ conn.request("POST", "/clear", json.dumps({'clear':False}))
response = conn.getresponse()
response.read()
@@ -403,7 +401,7 @@ class netclientdownload(bpy.types.Operator):
@classmethod
def poll(cls, context):
netsettings = context.scene.network_render
- return netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0
+ return netsettings.active_job_index >= 0 and len(netsettings.jobs) > netsettings.active_job_index
def execute(self, context):
netsettings = context.scene.network_render
@@ -412,29 +410,71 @@ class netclientdownload(bpy.types.Operator):
conn = clientConnection(netsettings.server_address, netsettings.server_port, self.report)
if conn:
- job = netrender.jobs[netsettings.active_job_index]
-
+ job_id = netrender.jobs[netsettings.active_job_index].id
+
+ conn.request("GET", "/status", headers={"job-id":job_id})
+
+ response = conn.getresponse()
+
+ if response.status != http.client.OK:
+ self.report('ERROR', "Job ID %i not defined on master" % job_id)
+ return {'ERROR'}
+
+ content = response.read()
+
+ job = netrender.model.RenderJob.materialize(json.loads(str(content, encoding='utf8')))
+
+ conn.close()
+
+ finished_frames = []
+
+ nb_error = 0
+ nb_missing = 0
+
for frame in job.frames:
- client.requestResult(conn, job.id, frame.number)
- response = conn.getresponse()
- response.read()
-
- if response.status != http.client.OK:
- print("missing", frame.number)
- continue
-
- print("got back", frame.number)
-
- f = open(os.path.join(netsettings.path, "%06d.exr" % frame.number), "wb")
- buf = response.read(1024)
-
- while buf:
- f.write(buf)
- buf = response.read(1024)
-
- f.close()
-
- conn.close()
+ if frame.status == DONE:
+ finished_frames.append(frame.number)
+ elif frame.status == ERROR:
+ nb_error += 1
+ else:
+ nb_missing += 1
+
+ if not finished_frames:
+ return
+
+ frame_ranges = []
+
+ first = None
+ last = None
+
+ for i in range(len(finished_frames)):
+ current = finished_frames[i]
+
+ if not first:
+ first = current
+ last = current
+ elif last + 1 == current:
+ last = current
+
+ if last + 1 < current or i + 1 == len(finished_frames):
+ if first < last:
+ frame_ranges.append((first, last))
+ else:
+ frame_ranges.append((first,))
+
+ first = current
+ last = current
+
+ getResults(netsettings.server_address, netsettings.server_port, job_id, job.resolution[0], job.resolution[1], job.resolution[2], frame_ranges)
+
+ if nb_error and nb_missing:
+ self.report('ERROR', "Results downloaded but skipped %i frames with errors and %i unfinished frames" % (nb_error, nb_missing))
+ elif nb_error:
+ self.report('ERROR', "Results downloaded but skipped %i frames with errors" % nb_error)
+ elif nb_missing:
+ self.report('WARNING', "Results downloaded but skipped %i unfinished frames" % nb_missing)
+ else:
+ self.report('INFO', "All results downloaded")
return {'FINISHED'}
@@ -464,6 +504,38 @@ class netclientscan(bpy.types.Operator):
def invoke(self, context, event):
return self.execute(context)
+class netclientvcsguess(bpy.types.Operator):
+ '''Guess VCS setting for the current file'''
+ bl_idname = "render.netclientvcsguess"
+ bl_label = "VCS Guess"
+
+ @classmethod
+ def poll(cls, context):
+ return True
+
+ def execute(self, context):
+ netsettings = context.scene.network_render
+
+ system = versioning.SYSTEMS.get(netsettings.vcs_system, None)
+
+ if system:
+ wpath, name = os.path.split(os.path.abspath(bpy.data.filepath))
+
+ rpath = system.path(wpath)
+ revision = system.revision(wpath)
+
+ netsettings.vcs_wpath = wpath
+ netsettings.vcs_rpath = rpath
+ netsettings.vcs_revision = revision
+
+
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ return self.execute(context)
+
+
class netclientweb(bpy.types.Operator):
'''Open new window with information about running rendering jobs'''
bl_idname = "render.netclientweb"
diff --git a/release/scripts/io/netrender/slave.py b/release/scripts/io/netrender/slave.py
index f017fefa4e3..b05de0afeb9 100644
--- a/release/scripts/io/netrender/slave.py
+++ b/release/scripts/io/netrender/slave.py
@@ -21,17 +21,26 @@ import http, http.client, http.server, urllib
import subprocess, time
import json
+import bpy
+
from netrender.utils import *
import netrender.model
import netrender.repath
+import netrender.thumbnail as thumbnail
BLENDER_PATH = sys.argv[0]
CANCEL_POLL_SPEED = 2
MAX_TIMEOUT = 10
INCREMENT_TIMEOUT = 1
-
-if platform.system() == 'Windows' and platform.version() >= '5': # Error mode is only available on Win2k or higher, that's version 5
+MAX_CONNECT_TRY = 10
+try:
+ system = platform.system()
+except UnicodeDecodeError:
+ import sys
+ system = sys.platform
+
+if system in ('Windows', 'win32') and platform.version() >= '5': # Error mode is only available on Win2k or higher, that's version 5
import ctypes
def SetErrorMode():
val = ctypes.windll.kernel32.SetErrorMode(0x0002)
@@ -71,7 +80,7 @@ def testFile(conn, job_id, slave_id, rfile, JOB_PREFIX, main_path = None):
found = os.path.exists(job_full_path)
- if found:
+ if found and rfile.signature != None:
found_signature = hashFile(job_full_path)
found = found_signature == rfile.signature
@@ -104,13 +113,36 @@ def testFile(conn, job_id, slave_id, rfile, JOB_PREFIX, main_path = None):
return job_full_path
+def breakable_timeout(timeout):
+ for i in range(timeout):
+ time.sleep(1)
+ if engine.test_break():
+ break
+
def render_slave(engine, netsettings, threads):
timeout = 1
+
+ bisleep = BreakableIncrementedSleep(INCREMENT_TIMEOUT, 1, MAX_TIMEOUT, engine.test_break)
engine.update_stats("", "Network render node initiation")
conn = clientConnection(netsettings.server_address, netsettings.server_port)
-
+
+ if not conn:
+ timeout = 1
+ print("Connection failed, will try connecting again at most %i times" % MAX_CONNECT_TRY)
+ bisleep.reset()
+
+ for i in range(MAX_CONNECT_TRY):
+ bisleep.sleep()
+
+ conn = clientConnection(netsettings.server_address, netsettings.server_port)
+
+ if conn or engine.test_break():
+ break
+
+ print("Retry %i failed, waiting %is before retrying" % (i + 1, bisleep.current))
+
if conn:
conn.request("POST", "/slave", json.dumps(slave_Info().serialize()))
response = conn.getresponse()
@@ -118,7 +150,7 @@ def render_slave(engine, netsettings, threads):
slave_id = response.getheader("slave-id")
- NODE_PREFIX = os.path.join(netsettings.path, "slave_" + slave_id)
+ NODE_PREFIX = os.path.join(bpy.path.abspath(netsettings.path), "slave_" + slave_id)
if not os.path.exists(NODE_PREFIX):
os.mkdir(NODE_PREFIX)
@@ -129,7 +161,7 @@ def render_slave(engine, netsettings, threads):
response = conn.getresponse()
if response.status == http.client.OK:
- timeout = 1 # reset timeout on new job
+ bisleep.reset()
job = netrender.model.RenderJob.materialize(json.loads(str(response.read(), encoding='utf8')))
engine.update_stats("", "Network render processing job from master")
@@ -138,6 +170,10 @@ def render_slave(engine, netsettings, threads):
if not os.path.exists(JOB_PREFIX):
os.mkdir(JOB_PREFIX)
+ # set tempdir for fsaa temp files
+ # have to set environ var because render is done in a subprocess and that's the easiest way to propagate the setting
+ os.environ["TMP"] = JOB_PREFIX
+
if job.type == netrender.model.JOB_BLENDER:
job_path = job.files[0].filepath # path of main file
@@ -154,6 +190,20 @@ def render_slave(engine, netsettings, threads):
netrender.repath.update(job)
engine.update_stats("", "Render File "+ main_file+ " for job "+ job.id)
+ elif job.type == netrender.model.JOB_VCS:
+ if not job.version_info:
+ # Need to return an error to server, incorrect job type
+ pass
+
+ job_path = job.files[0].filepath # path of main file
+ main_path, main_file = os.path.split(job_path)
+
+ job.version_info.update()
+
+ # For VCS jobs, file path is relative to the working copy path
+ job_full_path = os.path.join(job.version_info.wpath, job_path)
+
+ 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])
@@ -167,7 +217,7 @@ def render_slave(engine, netsettings, threads):
# start render
start_t = time.time()
- if job.type == netrender.model.JOB_BLENDER:
+ if job.rendersWithBlender():
frame_args = []
for frame in job.frames:
@@ -252,20 +302,20 @@ def render_slave(engine, netsettings, threads):
headers["job-result"] = str(DONE)
for frame in job.frames:
headers["job-frame"] = str(frame.number)
- if job.type == netrender.model.JOB_BLENDER:
+ if job.hasRenderResult():
# send image back to server
filename = os.path.join(JOB_PREFIX, "%06d.exr" % frame.number)
# thumbnail first
if netsettings.use_slave_thumb:
- thumbname = thumbnail(filename)
-
- f = open(thumbname, 'rb')
- conn.request("PUT", "/thumb", f, headers=headers)
- f.close()
- responseStatus(conn)
+ thumbname = thumbnail.generate(filename)
+ if thumbname:
+ f = open(thumbname, 'rb')
+ conn.request("PUT", "/thumb", f, headers=headers)
+ f.close()
+ responseStatus(conn)
f = open(filename, 'rb')
conn.request("PUT", "/render", f, headers=headers)
@@ -288,13 +338,7 @@ def render_slave(engine, netsettings, threads):
engine.update_stats("", "Network render connected to master, waiting for jobs")
else:
- if timeout < MAX_TIMEOUT:
- timeout += INCREMENT_TIMEOUT
-
- for i in range(timeout):
- time.sleep(1)
- if engine.test_break():
- break
+ bisleep.sleep()
conn.close()
diff --git a/release/scripts/io/netrender/thumbnail.py b/release/scripts/io/netrender/thumbnail.py
new file mode 100644
index 00000000000..2ead6e82745
--- /dev/null
+++ b/release/scripts/io/netrender/thumbnail.py
@@ -0,0 +1,81 @@
+# ##### 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
+
+def generate(filename, external=True):
+ if external:
+ process = subprocess.Popen([sys.argv[0], "-b", "-noaudio", "-P", __file__, "--", filename], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ while process.poll() is None:
+ process.stdout.read(1024) # empty buffer to be sure
+ process.stdout.read()
+
+ return _thumbname(filename)
+ else:
+ return _internal(filename)
+
+def _thumbname(filename):
+ root = os.path.splitext(filename)[0]
+ return root + ".jpg"
+
+def _internal(filename):
+ imagename = os.path.split(filename)[1]
+ thumbname = _thumbname(filename)
+
+ if os.path.exists(thumbname):
+ return thumbname
+
+ if bpy:
+ scene = bpy.data.scenes[0] # FIXME, this is dodgy!
+ scene.render.file_format = "JPEG"
+ scene.render.file_quality = 90
+
+ # remove existing image, if there's a leftover (otherwise open changes the name)
+ if imagename in bpy.data.images:
+ img = bpy.data.images[imagename]
+ bpy.data.images.remove(img)
+
+ bpy.ops.image.open(filepath=filename)
+ img = bpy.data.images[imagename]
+
+ img.save_render(thumbname, scene=scene)
+
+ img.user_clear()
+ bpy.data.images.remove(img)
+
+ try:
+ process = subprocess.Popen(["convert", thumbname, "-resize", "300x300", thumbname])
+ process.wait()
+ return thumbname
+ except Exception as exp:
+ print("Error while generating thumbnail")
+ print(exp)
+
+ return None
+
+if __name__ == "__main__":
+ import bpy
+ try:
+ start = sys.argv.index("--") + 1
+ except ValueError:
+ start = 0
+ for filename in sys.argv[start:]:
+ generate(filename, external=False)
diff --git a/release/scripts/io/netrender/ui.py b/release/scripts/io/netrender/ui.py
index c065b95b928..343c60e7865 100644
--- a/release/scripts/io/netrender/ui.py
+++ b/release/scripts/io/netrender/ui.py
@@ -36,6 +36,8 @@ DISPATCHED = 1
DONE = 2
ERROR = 3
+LAST_ADDRESS_TEST = 0
+
def base_poll(cls, context):
rd = context.scene.render
return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES)
@@ -45,7 +47,7 @@ def init_file():
if netrender.init_file != bpy.data.filepath:
netrender.init_file = bpy.data.filepath
netrender.init_data = True
- netrender.init_address = True
+ netrender.valid_address = False
def init_data(netsettings):
init_file()
@@ -66,22 +68,31 @@ def init_data(netsettings):
netsettings.jobs.remove(0)
def verify_address(netsettings):
+ global LAST_ADDRESS_TEST
init_file()
- if netrender.init_address:
- netrender.init_address = False
+ if LAST_ADDRESS_TEST + 30 < time.time():
+ LAST_ADDRESS_TEST = time.time()
try:
- conn = clientConnection(netsettings.server_address, netsettings.server_port, scan = False)
+ conn = clientConnection(netsettings.server_address, netsettings.server_port, scan = False, timeout = 1)
except:
conn = None
if conn:
+ netrender.valid_address = True
conn.close()
else:
- netsettings.server_address = "[default]"
+ netrender.valid_address = False
+
+ return netrender.valid_address
+
+class NeedValidAddress():
+ @classmethod
+ def poll(cls, context):
+ return super().poll(context) and verify_address(context.scene.network_render)
-class RenderButtonsPanel():
+class NetRenderButtonsPanel():
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "render"
@@ -90,16 +101,16 @@ class RenderButtonsPanel():
@classmethod
def poll(cls, context):
rd = context.scene.render
- return (rd.use_game_engine==False) and (rd.engine in cls.COMPAT_ENGINES)
+ return rd.engine == 'NET_RENDER' and rd.use_game_engine == False
# Setting panel, use in the scene for now.
-class RENDER_PT_network_settings(bpy.types.Panel, RenderButtonsPanel):
+class RENDER_PT_network_settings(NetRenderButtonsPanel, bpy.types.Panel):
bl_label = "Network Settings"
COMPAT_ENGINES = {'NET_RENDER'}
@classmethod
def poll(cls, context):
- return super(RENDER_PT_network_settings, cls).poll(context)
+ return super().poll(context)
def draw(self, context):
layout = self.layout
@@ -128,17 +139,20 @@ class RENDER_PT_network_settings(bpy.types.Panel, RenderButtonsPanel):
if netsettings.mode != "RENDER_MASTER":
layout.operator("render.netclientscan", icon='FILE_REFRESH', text="")
+
+ if not netrender.valid_address:
+ layout.label(text="No master at specified address")
layout.operator("render.netclientweb", icon='QUESTION')
-class RENDER_PT_network_slave_settings(bpy.types.Panel, RenderButtonsPanel):
+class RENDER_PT_network_slave_settings(NetRenderButtonsPanel, bpy.types.Panel):
bl_label = "Slave Settings"
COMPAT_ENGINES = {'NET_RENDER'}
@classmethod
def poll(cls, context):
scene = context.scene
- return super(RENDER_PT_network_slave_settings, cls).poll(context) and scene.network_render.mode == "RENDER_SLAVE"
+ return super().poll(context) and scene.network_render.mode == "RENDER_SLAVE"
def draw(self, context):
layout = self.layout
@@ -156,14 +170,14 @@ class RENDER_PT_network_slave_settings(bpy.types.Panel, RenderButtonsPanel):
sub.enabled = rd.threads_mode == 'FIXED'
sub.prop(rd, "threads")
-class RENDER_PT_network_master_settings(bpy.types.Panel, RenderButtonsPanel):
+class RENDER_PT_network_master_settings(NetRenderButtonsPanel, bpy.types.Panel):
bl_label = "Master Settings"
COMPAT_ENGINES = {'NET_RENDER'}
@classmethod
def poll(cls, context):
scene = context.scene
- return super(RENDER_PT_network_master_settings, cls).poll(context) and scene.network_render.mode == "RENDER_MASTER"
+ return super().poll(context) and scene.network_render.mode == "RENDER_MASTER"
def draw(self, context):
layout = self.layout
@@ -174,14 +188,14 @@ class RENDER_PT_network_master_settings(bpy.types.Panel, RenderButtonsPanel):
layout.prop(netsettings, "use_master_broadcast")
layout.prop(netsettings, "use_master_clear")
-class RENDER_PT_network_job(bpy.types.Panel, RenderButtonsPanel):
+class RENDER_PT_network_job(NetRenderButtonsPanel, bpy.types.Panel):
bl_label = "Job Settings"
COMPAT_ENGINES = {'NET_RENDER'}
@classmethod
def poll(cls, context):
scene = context.scene
- return super(RENDER_PT_network_job, cls).poll(context) and scene.network_render.mode == "RENDER_CLIENT"
+ return super().poll(context) and scene.network_render.mode == "RENDER_CLIENT"
def draw(self, context):
layout = self.layout
@@ -203,10 +217,12 @@ class RENDER_PT_network_job(bpy.types.Panel, RenderButtonsPanel):
split = layout.split(percentage=0.3)
col = split.column()
+ col.label(text="Type:")
col.label(text="Name:")
col.label(text="Category:")
col = split.column()
+ col.prop(netsettings, "job_type", text="")
col.prop(netsettings, "job_name", text="")
col.prop(netsettings, "job_category", text="")
@@ -214,18 +230,38 @@ class RENDER_PT_network_job(bpy.types.Panel, RenderButtonsPanel):
row.prop(netsettings, "priority")
row.prop(netsettings, "chunks")
-class RENDER_PT_network_slaves(bpy.types.Panel, RenderButtonsPanel):
- bl_label = "Slaves Status"
+class RENDER_PT_network_job_vcs(NetRenderButtonsPanel, bpy.types.Panel):
+ bl_label = "VCS Job Settings"
COMPAT_ENGINES = {'NET_RENDER'}
@classmethod
def poll(cls, context):
scene = context.scene
+ return (super().poll(context)
+ and scene.network_render.mode == "RENDER_CLIENT"
+ and scene.network_render.job_type == "JOB_VCS")
+
+ def draw(self, context):
+ layout = self.layout
+
+ scene = context.scene
netsettings = scene.network_render
- if netsettings.mode != "RENDER_CLIENT":
- return False
- verify_address(netsettings)
- return super(RENDER_PT_network_slaves, cls).poll(context) and netsettings.server_address != "[default]"
+
+ layout.operator("render.netclientvcsguess", icon='FILE_REFRESH', text="")
+
+ layout.prop(netsettings, "vcs_system")
+ layout.prop(netsettings, "vcs_revision")
+ layout.prop(netsettings, "vcs_rpath")
+ layout.prop(netsettings, "vcs_wpath")
+
+class RENDER_PT_network_slaves(NeedValidAddress, NetRenderButtonsPanel, bpy.types.Panel):
+ bl_label = "Slaves Status"
+ COMPAT_ENGINES = {'NET_RENDER'}
+
+ @classmethod
+ def poll(cls, context):
+ netsettings = context.scene.network_render
+ return super().poll(context) and netsettings.mode == "RENDER_CLIENT"
def draw(self, context):
layout = self.layout
@@ -240,9 +276,7 @@ class RENDER_PT_network_slaves(bpy.types.Panel, RenderButtonsPanel):
sub.operator("render.netclientslaves", icon='FILE_REFRESH', text="")
sub.operator("render.netclientblacklistslave", icon='ZOOMOUT', text="")
- init_data(netsettings)
-
- if netsettings.active_slave_index >= 0 and len(netsettings.slaves) > 0:
+ if len(netrender.slaves) > netsettings.active_slave_index >= 0:
layout.separator()
slave = netrender.slaves[netsettings.active_slave_index]
@@ -252,18 +286,14 @@ class RENDER_PT_network_slaves(bpy.types.Panel, RenderButtonsPanel):
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats)
-class RENDER_PT_network_slaves_blacklist(bpy.types.Panel, RenderButtonsPanel):
+class RENDER_PT_network_slaves_blacklist(NeedValidAddress, NetRenderButtonsPanel, bpy.types.Panel):
bl_label = "Slaves Blacklist"
COMPAT_ENGINES = {'NET_RENDER'}
@classmethod
def poll(cls, context):
- scene = context.scene
- netsettings = scene.network_render
- if netsettings.mode != "RENDER_CLIENT":
- return False
- verify_address(netsettings)
- return super(RENDER_PT_network_slaves_blacklist, cls).poll(context) and netsettings.server_address != "[default]"
+ netsettings = context.scene.network_render
+ return super().poll(context) and netsettings.mode == "RENDER_CLIENT"
def draw(self, context):
layout = self.layout
@@ -277,9 +307,7 @@ class RENDER_PT_network_slaves_blacklist(bpy.types.Panel, RenderButtonsPanel):
sub = row.column(align=True)
sub.operator("render.netclientwhitelistslave", icon='ZOOMOUT', text="")
- init_data(netsettings)
-
- if netsettings.active_blacklisted_slave_index >= 0 and len(netsettings.slaves_blacklist) > 0:
+ if len(netrender.blacklist) > netsettings.active_blacklisted_slave_index >= 0:
layout.separator()
slave = netrender.blacklist[netsettings.active_blacklisted_slave_index]
@@ -289,18 +317,14 @@ class RENDER_PT_network_slaves_blacklist(bpy.types.Panel, RenderButtonsPanel):
layout.label(text="Seen: " + time.ctime(slave.last_seen))
layout.label(text="Stats: " + slave.stats)
-class RENDER_PT_network_jobs(bpy.types.Panel, RenderButtonsPanel):
+class RENDER_PT_network_jobs(NeedValidAddress, NetRenderButtonsPanel, bpy.types.Panel):
bl_label = "Jobs"
COMPAT_ENGINES = {'NET_RENDER'}
@classmethod
def poll(cls, context):
- scene = context.scene
- netsettings = scene.network_render
- if netsettings.mode != "RENDER_CLIENT":
- return False
- verify_address(netsettings)
- return super(RENDER_PT_network_jobs, cls).poll(context) and netsettings.server_address != "[default]"
+ netsettings = context.scene.network_render
+ return super().poll(context) and netsettings.mode == "RENDER_CLIENT"
def draw(self, context):
layout = self.layout
@@ -317,9 +341,7 @@ class RENDER_PT_network_jobs(bpy.types.Panel, RenderButtonsPanel):
sub.operator("render.netclientcancelall", icon='PANEL_CLOSE', text="")
sub.operator("render.netclientdownload", icon='RENDER_ANIMATION', text="")
- init_data(netsettings)
-
- if netsettings.active_job_index >= 0 and len(netsettings.jobs) > 0:
+ if len(netrender.jobs) > netsettings.active_job_index >= 0:
layout.separator()
job = netrender.jobs[netsettings.active_job_index]
@@ -329,16 +351,33 @@ class RENDER_PT_network_jobs(bpy.types.Panel, RenderButtonsPanel):
layout.label(text="Done: %04i" % job.results[DONE])
layout.label(text="Error: %04i" % job.results[ERROR])
-class NetRenderSettings(bpy.types.IDPropertyGroup):
- pass
+import properties_render
+class RENDER_PT_network_output(NeedValidAddress, NetRenderButtonsPanel, bpy.types.Panel):
+ bl_label = "Output"
+ COMPAT_ENGINES = {'NET_RENDER'}
-class NetRenderSlave(bpy.types.IDPropertyGroup):
- pass
+ @classmethod
+ def poll(cls, context):
+ netsettings = context.scene.network_render
+ return super().poll(context) and netsettings.mode == "RENDER_CLIENT"
+
+ draw = properties_render.RENDER_PT_output.draw
-class NetRenderJob(bpy.types.IDPropertyGroup):
- pass
def addProperties():
+ class NetRenderSettings(bpy.types.IDPropertyGroup):
+ pass
+
+ class NetRenderSlave(bpy.types.IDPropertyGroup):
+ pass
+
+ class NetRenderJob(bpy.types.IDPropertyGroup):
+ pass
+
+ bpy.utils.register_class(NetRenderSettings)
+ bpy.utils.register_class(NetRenderSlave)
+ bpy.utils.register_class(NetRenderJob)
+
from bpy.props import PointerProperty, StringProperty, BoolProperty, EnumProperty, IntProperty, CollectionProperty
bpy.types.Scene.network_render = PointerProperty(type=NetRenderSettings, name="Network Render", description="Network Render Settings")
@@ -397,6 +436,16 @@ def addProperties():
default = default_path,
subtype='FILE_PATH')
+ NetRenderSettings.job_type = EnumProperty(
+ items=(
+ ("JOB_BLENDER", "Blender", "Standard Blender Job"),
+ ("JOB_PROCESS", "Process", "Custom Process Job"),
+ ("JOB_VCS", "VCS", "Version Control System Managed Job"),
+ ),
+ name="Job Type",
+ description="Type of render job",
+ default="JOB_BLENDER")
+
NetRenderSettings.job_name = StringProperty(
name="Job name",
description="Name of the job",
@@ -423,6 +472,30 @@ def addProperties():
min=1,
max=10)
+ NetRenderSettings.vcs_wpath = StringProperty(
+ name="Working Copy",
+ description="Path of the local working copy",
+ maxlen = 1024,
+ default = "")
+
+ NetRenderSettings.vcs_rpath = StringProperty(
+ name="Remote Path",
+ description="Path of the server copy (protocol specific)",
+ maxlen = 1024,
+ default = "")
+
+ NetRenderSettings.vcs_revision = StringProperty(
+ name="Revision",
+ description="Revision for this job",
+ maxlen = 256,
+ default = "")
+
+ NetRenderSettings.vcs_system = StringProperty(
+ name="VCS",
+ description="Version Control System",
+ maxlen = 64,
+ default = "Subversion")
+
NetRenderSettings.job_id = StringProperty(
name="Network job id",
description="id of the last sent render job",
diff --git a/release/scripts/io/netrender/utils.py b/release/scripts/io/netrender/utils.py
index e2a5051cf64..ed9fb2de812 100644
--- a/release/scripts/io/netrender/utils.py
+++ b/release/scripts/io/netrender/utils.py
@@ -28,7 +28,7 @@ try:
except:
bpy = None
-VERSION = bytes("0.9", encoding='utf8')
+VERSION = bytes("1.3", encoding='utf8')
# Jobs status
JOB_WAITING = 0 # before all data has been entered
@@ -57,6 +57,39 @@ FRAME_STATUS_TEXT = {
ERROR: "Error"
}
+class DirectoryContext:
+ def __init__(self, path):
+ self.path = path
+
+ def __enter__(self):
+ self.curdir = os.path.abspath(os.curdir)
+ os.chdir(self.path)
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ os.chdir(self.curdir)
+
+class BreakableIncrementedSleep:
+ def __init__(self, increment, default_timeout, max_timeout, break_fct):
+ self.increment = increment
+ self.default = default_timeout
+ self.max = max_timeout
+ self.current = self.default
+ self.break_fct = break_fct
+
+ def reset(self):
+ self.current = self.default
+
+ def increase(self):
+ self.current = min(self.current + self.increment, self.max)
+
+ def sleep(self):
+ for i in range(self.current):
+ time.sleep(1)
+ if self.break_fct():
+ break
+
+ self.increase()
+
def responseStatus(conn):
response = conn.getresponse()
response.read()
@@ -97,7 +130,7 @@ def clientScan(report = None):
return ("", 8000) # return default values
-def clientConnection(address, port, report = None, scan = True):
+def clientConnection(address, port, report = None, scan = True, timeout = 5):
if address == "[default]":
# calling operator from python is fucked, scene isn't in context
# if bpy:
@@ -111,7 +144,7 @@ def clientConnection(address, port, report = None, scan = True):
return None
try:
- conn = http.client.HTTPConnection(address, port, timeout = 5)
+ conn = http.client.HTTPConnection(address, port, timeout = timeout)
if conn:
if clientVerifyVersion(conn):
@@ -119,12 +152,13 @@ def clientConnection(address, port, report = None, scan = True):
else:
conn.close()
reporting(report, "Incorrect master version", ValueError)
- except Exception as err:
+ except BaseException as err:
if report:
report('ERROR', str(err))
return None
else:
- raise
+ print(err)
+ return None
def clientVerifyVersion(conn):
conn.request("GET", "/version")
@@ -168,7 +202,10 @@ def hashData(data):
def prefixPath(prefix_directory, file_path, prefix_path, force = False):
- if os.path.isabs(file_path):
+ if (os.path.isabs(file_path) or
+ len(file_path) >= 3 and (file_path[1:3] == ":/" or file_path[1:3] == ":\\") or # Windows absolute path don't count as absolute on unix, have to handle them myself
+ file_path[0] == "/" or file_path[0] == "\\"): # and vice versa
+
# if an absolute path, make sure path exists, if it doesn't, use relative local path
full_path = file_path
if force or not os.path.exists(full_path):
@@ -185,12 +222,69 @@ def prefixPath(prefix_directory, file_path, prefix_path, force = False):
else:
full_path = os.path.join(prefix_directory, n)
else:
- full_path = (prefix_directory, file_path)
+ full_path = os.path.join(prefix_directory, file_path)
return full_path
+def getResults(server_address, server_port, job_id, resolution_x, resolution_y, resolution_percentage, frame_ranges):
+ if bpy.app.debug:
+ print("=============================================")
+ print("============= FETCHING RESULTS ==============")
+
+ frame_arguments = []
+ for r in frame_ranges:
+ if len(r) == 2:
+ frame_arguments.extend(["-s", str(r[0]), "-e", str(r[1]), "-a"])
+ else:
+ frame_arguments.extend(["-f", str(r[0])])
+
+ filepath = os.path.join(bpy.app.tempdir, "netrender_temp.blend")
+ bpy.ops.wm.save_as_mainfile(filepath=filepath, copy=True, check_existing=False)
+
+ arguments = [sys.argv[0], "-b", "-noaudio", filepath, "-o", bpy.path.abspath(bpy.context.scene.render.filepath), "-P", __file__] + frame_arguments + ["--", "GetResults", server_address, str(server_port), job_id, str(resolution_x), str(resolution_y), str(resolution_percentage)]
+ if bpy.app.debug:
+ print("Starting subprocess:")
+ print(" ".join(arguments))
+
+ process = subprocess.Popen(arguments, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ while process.poll() is None:
+ stdout = process.stdout.read(1024)
+ if bpy.app.debug:
+ print(str(stdout, encoding='utf-8'), end="")
+
+
+ # read leftovers if needed
+ stdout = process.stdout.read()
+ if bpy.app.debug:
+ print(str(stdout, encoding='utf-8'))
+
+ os.remove(filepath)
+
+ if bpy.app.debug:
+ print("=============================================")
+ return
+
+def _getResults(server_address, server_port, job_id, resolution_x, resolution_y, resolution_percentage):
+ render = bpy.context.scene.render
+
+ netsettings = bpy.context.scene.network_render
+
+ netsettings.server_address = server_address
+ netsettings.server_port = int(server_port)
+ netsettings.job_id = job_id
+
+ render.engine = 'NET_RENDER'
+ render.resolution_x = int(resolution_x)
+ render.resolution_y = int(resolution_y)
+ render.resolution_percentage = int(resolution_percentage)
+
+ render.use_full_sample = False
+ render.use_compositing = False
+ render.use_border = False
+
+
def getFileInfo(filepath, infos):
- process = subprocess.Popen([sys.argv[0], "-b", "-noaudio", filepath, "-P", __file__, "--"] + infos, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ process = subprocess.Popen([sys.argv[0], "-b", "-noaudio", filepath, "-P", __file__, "--", "FileInfo"] + infos, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout = bytes()
while process.poll() is None:
stdout += process.stdout.read(1024)
@@ -203,33 +297,17 @@ def getFileInfo(filepath, infos):
values = [eval(v[1:].strip()) for v in stdout.split("\n") if v.startswith("$")]
return values
-
-def thumbnail(filename):
- root = os.path.splitext(filename)[0]
- imagename = os.path.split(filename)[1]
- thumbname = root + ".jpg"
-
- if os.path.exists(thumbname):
- return thumbname
-
- if bpy:
- scene = bpy.data.scenes[0] # FIXME, this is dodgy!
- scene.render.file_format = "JPEG"
- scene.render.file_quality = 90
- bpy.ops.image.open(filepath=filename)
- img = bpy.data.images[imagename]
- img.save_render(thumbname, scene=scene)
-
- try:
- process = subprocess.Popen(["convert", thumbname, "-resize", "300x300", thumbname])
- process.wait()
- return thumbname
- except:
- pass
-
- return None
+
if __name__ == "__main__":
- import bpy
- for info in sys.argv[7:]:
- print("$", eval(info))
+ try:
+ start = sys.argv.index("--") + 1
+ except ValueError:
+ start = 0
+ action, *args = sys.argv[start:]
+
+ if action == "FileInfo":
+ for info in args:
+ print("$", eval(info))
+ elif action == "GetResults":
+ _getResults(args[0], args[1], args[2], args[3], args[4], args[5])
diff --git a/release/scripts/io/netrender/versioning.py b/release/scripts/io/netrender/versioning.py
new file mode 100644
index 00000000000..d4f8522cce8
--- /dev/null
+++ b/release/scripts/io/netrender/versioning.py
@@ -0,0 +1,72 @@
+import sys, os
+import re
+import subprocess
+
+from netrender.utils import *
+
+class AbstractVCS:
+ name = "ABSTRACT VCS"
+ def __init__(self):
+ pass
+
+ def update(self, info):
+ """update(info)
+ Update a working copy to the specified revision.
+ If working copy doesn't exist, do a full get from server to create it.
+ [info] model.VersioningInfo instance, specifies the working path, remote path and version number."""
+ pass
+
+ def revision(self, path):
+ """revision(path)
+ return the current revision of the specified working copy path"""
+ pass
+
+ def path(self, path):
+ """path(path)
+ return the remote path of the specified working copy path"""
+ pass
+
+class Subversion(AbstractVCS):
+ name = "Subversion"
+ def __init__(self):
+ super().__init__()
+ self.version_exp = re.compile("([0-9]*)")
+ self.path_exp = re.compile("URL: (.*)")
+
+ def update(self, info):
+ if not os.path.exists(info.wpath):
+ base, folder = os.path.split(info.wpath)
+
+ with DirectoryContext(base):
+ subprocess.call(["svn", "co", "%s@%s" % (info.rpath, str(info.revision)), folder])
+ else:
+ with DirectoryContext(info.wpath):
+ subprocess.call(["svn", "up", "--accept", "theirs-full", "-r", str(info.revision)])
+
+ def revision(self, path):
+ if not os.path.exists(path):
+ return
+
+ with DirectoryContext(path):
+ stdout = subprocess.check_output(["svnversion"])
+
+ match = self.version_exp.match(str(stdout, encoding="utf-8"))
+
+ if match:
+ return match.group(1)
+
+ def path(self, path):
+ if not os.path.exists(path):
+ return
+
+ with DirectoryContext(path):
+ stdout = subprocess.check_output(["svn", "info"])
+
+ match = self.path_exp.search(str(stdout, encoding="utf-8"))
+
+ if match:
+ return match.group(1)
+
+SYSTEMS = {
+ Subversion.name: Subversion()
+ }
diff --git a/release/scripts/keyingsets/keyingsets_builtins.py b/release/scripts/keyingsets/keyingsets_builtins.py
index 73b75057299..cff4aecac54 100644
--- a/release/scripts/keyingsets/keyingsets_builtins.py
+++ b/release/scripts/keyingsets/keyingsets_builtins.py
@@ -1,7 +1,29 @@
-# 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.
+# ##### 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>
+
+"""
+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 *
@@ -9,6 +31,7 @@ from keyingsets_utils import *
###############################
# Built-In KeyingSets
+
# Location
class BUILTIN_KSI_Location(bpy.types.KeyingSetInfo):
bl_label = "Location"
@@ -19,9 +42,10 @@ class BUILTIN_KSI_Location(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator - use callback for location
+ # generator - use callback for location
generate = RKS_GEN_location
+
# Rotation
class BUILTIN_KSI_Rotation(bpy.types.KeyingSetInfo):
bl_label = "Rotation"
@@ -32,9 +56,10 @@ class BUILTIN_KSI_Rotation(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator - use callback for location
+ # generator - use callback for location
generate = RKS_GEN_rotation
+
# Scale
class BUILTIN_KSI_Scaling(bpy.types.KeyingSetInfo):
bl_label = "Scaling"
@@ -45,11 +70,12 @@ class BUILTIN_KSI_Scaling(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator - use callback for location
+ # generator - use callback for location
generate = RKS_GEN_scaling
# ------------
+
# LocRot
class BUILTIN_KSI_LocRot(bpy.types.KeyingSetInfo):
bl_label = "LocRot"
@@ -60,13 +86,14 @@ class BUILTIN_KSI_LocRot(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator - use callback for location
+ # generator
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"
@@ -77,13 +104,14 @@ class BUILTIN_KSI_LocScale(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator - use callback for location
+ # generator
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"
@@ -94,7 +122,7 @@ class BUILTIN_KSI_LocRotScale(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator - use callback for location
+ # generator
def generate(self, context, ks, data):
# location
RKS_GEN_location(self, context, ks, data)
@@ -103,6 +131,7 @@ class BUILTIN_KSI_LocRotScale(bpy.types.KeyingSetInfo):
# scale
RKS_GEN_scaling(self, context, ks, data)
+
# RotScale
class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo):
bl_label = "RotScale"
@@ -113,20 +142,21 @@ class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator - use callback for location
+ # generator
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
+ bl_options = {'INSERTKEY_VISUAL'}
# poll - use predefined callback for selected bones/objects
poll = RKS_POLL_selected_items
@@ -134,9 +164,10 @@ class BUILTIN_KSI_VisualLoc(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator - use callback for location
+ # generator - use callback for location
generate = RKS_GEN_location
+
# Rotation
class BUILTIN_KSI_VisualRot(bpy.types.KeyingSetInfo):
bl_label = "Visual Rotation"
@@ -149,9 +180,10 @@ class BUILTIN_KSI_VisualRot(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator - use callback for location
+ # generator - use callback for rotation
generate = RKS_GEN_rotation
+
# VisualLocRot
class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo):
bl_label = "Visual LocRot"
@@ -164,7 +196,7 @@ class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator - use callback for location
+ # generator
def generate(self, context, ks, data):
# location
RKS_GEN_location(self, context, ks, data)
@@ -173,53 +205,163 @@ class BUILTIN_KSI_VisualLocRot(bpy.types.KeyingSetInfo):
# ------------
+
# 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)
+ # 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
+ # generator - use callback for doing this
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,
-]
+# All properties that are likely to get animated in a character rig
+class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo):
+ bl_label = "Whole Character"
+
+ # these prefixes should be avoided, as they are not really bones
+ # that animators should be touching (or need to touch)
+ badBonePrefixes = (
+ 'DEF',
+ 'GEO',
+ 'MCH',
+ 'ORG',
+ 'COR',
+ 'VIS',
+ # ... more can be added here as you need in your own rigs ...
+ )
+
+ # poll - pose-mode on active object only
+ def poll(ksi, context):
+ return ((context.active_object) and (context.active_object.pose) and
+ (context.active_object.mode == 'POSE'))
+
+ # iterator - all bones regardless of selection
+ def iterator(ksi, context, ks):
+ for bone in context.active_object.pose.bones:
+ if not bone.name.startswith(BUILTIN_KSI_WholeCharacter.badBonePrefixes):
+ ksi.generate(context, ks, bone)
+
+ # generator - all unlocked bone transforms + custom properties
+ def generate(ksi, context, ks, bone):
+ # loc, rot, scale - only include unlocked ones
+ ksi.doLoc(ks, bone)
+
+ if bone.rotation_mode in ('QUATERNION', 'AXIS_ANGLE'):
+ ksi.doRot4d(ks, bone)
+ else:
+ ksi.doRot3d(ks, bone)
+ ksi.doScale(ks, bone)
+
+ # custom props?
+ ksi.doCustomProps(ks, bone)
+
+ # ----------------
+
+ # helper to add some bone's property to the Keying Set
+ def addProp(ksi, ks, bone, prop, index=-1, use_groups=True):
+ # add the property name to the base path
+ id_path = bone.path_from_id()
+ id_block = bone.id_data
+
+ if prop.startswith('['):
+ # custom properties
+ path = id_path + prop
+ else:
+ # standard transforms/properties
+ path = path_add_property(id_path, prop)
+
+ # add Keying Set entry for this...
+ if use_groups:
+ ks.paths.add(id_block, path, index, group_method='NAMED', group_name=bone.name)
+ else:
+ ks.paths.add(id_block, path, index)
+
+ # ----------------
+
+ # location properties
+ def doLoc(ksi, ks, bone):
+ if bone.lock_location == (False, False, False):
+ ksi.addProp(ks, bone, "location")
+ else:
+ for i in range(3):
+ if not bone.lock_location[i]:
+ ksi.addProp(ks, bone, "location", i)
+
+ # rotation properties
+ def doRot4d(ksi, ks, bone):
+ # rotation mode affects the property used
+ if bone.rotation_mode == 'QUATERNION':
+ prop = "rotation_quaternion"
+ elif bone.rotation_mode == 'AXIS_ANGLE':
+ prop = "rotation_axis_angle"
+
+ # add rotation properties if they will
+ if bone.lock_rotations_4d:
+ # can check individually
+ if (bone.lock_rotation == (False, False, False)) and (bone.lock_rotation_w == False):
+ ksi.addProp(ks, bone, prop)
+ else:
+ if bone.lock_rotation_w == False:
+ ksi.addProp(ks, bone, prop, 0) # w = 0
+
+ for i in range(3):
+ if not bone.lock_rotation[i]:
+ ksi.addProp(ks, bone, prop, i + 1) # i + 1, since here x,y,z = 1,2,3, and w=0
+ elif True not in bone.lock_rotation:
+ # if axis-angle rotations get locked as eulers, then it's too messy to allow anything
+ # other than all open unless we keyframe the whole lot
+ ksi.addProp(ks, bone, prop)
+
+ def doRot3d(ksi, ks, bone):
+ if bone.lock_rotation == (False, False, False):
+ ksi.addProp(ks, bone, "rotation_euler")
+ else:
+ for i in range(3):
+ if not bone.lock_rotation[i]:
+ ksi.addProp(ks, bone, "rotation_euler", i)
+
+ # scale properties
+ def doScale(ksi, ks, bone):
+ if bone.lock_scale == (0, 0, 0):
+ ksi.addProp(ks, bone, "scale")
+ else:
+ for i in range(3):
+ if not bone.lock_scale[i]:
+ ksi.addProp(ks, bone, "scale", i)
+
+ # ----------------
+
+ # custom properties
+ def doCustomProps(ksi, ks, bone):
+ # go over all custom properties for bone
+ for prop, val in bone.items():
+ # ignore special "_RNA_UI" used for UI editing
+ if prop == "_RNA_UI":
+ continue
+
+ # for now, just add all of 'em
+ ksi.addProp(ks, bone, '["%s"]' % (prop))
def register():
- register = bpy.types.register
- for cls in classes:
- register(cls)
+ bpy.utils.register_module(__name__)
def unregister():
- unregister = bpy.types.unregister
- for cls in classes:
- unregister(cls)
+ bpy.utils.unregister_module(__name__)
+
if __name__ == "__main__":
register()
-###############################
+###############################
diff --git a/release/scripts/modules/add_object_utils.py b/release/scripts/modules/add_object_utils.py
index 44efc8f2ada..10707734bc4 100644
--- a/release/scripts/modules/add_object_utils.py
+++ b/release/scripts/modules/add_object_utils.py
@@ -23,28 +23,47 @@ import mathutils
def add_object_align_init(context, operator):
+ space_data = context.space_data
+ if space_data.type != 'VIEW_3D':
+ space_data = None
- if operator and operator.properties.is_property_set("location") and operator.properties.is_property_set("rotation"):
+ # location
+ if operator and operator.properties.is_property_set("location"):
location = mathutils.Matrix.Translation(mathutils.Vector(operator.properties.location))
- rotation = mathutils.Euler(operator.properties.rotation).to_matrix().resize4x4()
else:
- # TODO, local view cursor!
- location = mathutils.Matrix.Translation(context.scene.cursor_location)
+ if space_data: # local view cursor is detected below
+ location = mathutils.Matrix.Translation(space_data.cursor_location)
+ else:
+ location = mathutils.Matrix.Translation(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()
+ if operator:
+ operator.properties.location = location.to_translation()
+
+ # rotation
+ view_align = (context.user_preferences.edit.object_align == 'VIEW')
+ view_align_force = False
+ if operator:
+ if operator.properties.is_property_set("view_align"):
+ view_align = view_align_force = operator.view_align
+ else:
+ operator.properties.view_align = view_align
+
+ if operator and operator.properties.is_property_set("rotation") and not view_align_force:
+ rotation = mathutils.Euler(operator.properties.rotation).to_matrix().to_4x4()
+ else:
+ if view_align and space_data:
+ rotation = space_data.region_3d.view_matrix.to_3x3().inverted().to_4x4()
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):
+def object_data_add(context, obdata, operator=None):
scene = context.scene
@@ -65,6 +84,7 @@ def add_object_data(context, obdata, operator=None):
obj_act = scene.objects.active
if obj_act and obj_act.mode == 'EDIT' and obj_act.type == obj_new.type:
+ bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT')
obj_act.select = True
diff --git a/release/scripts/modules/animsys_refactor.py b/release/scripts/modules/animsys_refactor.py
index 8cc91873b0e..464df870e87 100644
--- a/release/scripts/modules/animsys_refactor.py
+++ b/release/scripts/modules/animsys_refactor.py
@@ -22,11 +22,12 @@
This module has utility functions for renaming
rna values in fcurves and drivers.
-The main function to use is: update_data_paths(...)
+The main function to use is: update_data_paths(...)
"""
IS_TESTING = False
+
class DataPathBuilder(object):
__slots__ = ("data_path", )
""" Dummy class used to parse fcurve and driver data paths.
@@ -37,7 +38,7 @@ class DataPathBuilder(object):
def __getattr__(self, attr):
str_value = ".%s" % attr
return DataPathBuilder(self.data_path + (str_value, ))
-
+
def __getitem__(self, key):
str_value = '["%s"]' % key
return DataPathBuilder(self.data_path + (str_value, ))
@@ -51,7 +52,7 @@ class DataPathBuilder(object):
if base is not Ellipsis:
try:
# this only works when running with an old blender
- # where the old path will resolve
+ # where the old path will resolve
base = eval("base" + item)
except:
base_new = Ellipsis
@@ -61,7 +62,7 @@ class DataPathBuilder(object):
try:
print("base." + item_new)
base_new = eval("base." + item_new)
- break # found, dont keep looking
+ break # found, dont keep looking
except:
pass
@@ -77,7 +78,7 @@ import bpy
def id_iter():
type_iter = type(bpy.data.objects)
-
+
for attr in dir(bpy.data):
data_iter = getattr(bpy.data, attr, None)
if type(data_iter) == type_iter:
@@ -111,16 +112,17 @@ def classes_recursive(base_type, clss=None):
def find_path_new(id_data, data_path, rna_update_dict, rna_update_from_map):
+ # note!, id_data can be ID type or a node tree
# ignore ID props for now
if data_path.startswith("["):
return data_path
-
+
# recursive path fixing, likely will be one in most cases.
data_path_builder = eval("DataPathBuilder(tuple())." + data_path)
data_resolve = data_path_builder.resolve(id_data, rna_update_from_map)
path_new = [pair[0] for pair in data_resolve]
-
+
# print(data_resolve)
data_base = id_data
@@ -137,55 +139,60 @@ def find_path_new(id_data, data_path, rna_update_dict, rna_update_from_map):
# set this as the base for further properties
data_base = data
-
- data_path_new = "".join(path_new)[1:] # skip the first "."
+
+ data_path_new = "".join(path_new)[1:] # skip the first "."
return data_path_new
def update_data_paths(rna_update):
''' rna_update triple [(class_name, from, to), ...]
'''
-
+
# make a faster lookup dict
rna_update_dict = {}
for ren_class, ren_from, ren_to in rna_update:
rna_update_dict.setdefault(ren_class, {})[ren_from] = ren_to
-
+
rna_update_from_map = {}
for ren_class, ren_from, ren_to in rna_update:
rna_update_from_map.setdefault(ren_from, []).append(ren_to)
for id_data in id_iter():
- anim_data = getattr(id_data, "animation_data", None)
- if anim_data is None:
- continue
-
- for fcurve in anim_data.drivers:
- for var in fcurve.driver.variables:
- if var.type == 'SINGLE_PROP':
- for tar in var.targets:
- id_data_other = tar.id
- data_path = tar.data_path
-
- if id_data_other and data_path:
- data_path_new = find_path_new(id_data_other, data_path, rna_update_dict, rna_update_from_map)
- # print(data_path_new)
- if data_path_new != data_path:
- if not IS_TESTING:
- tar.data_path = data_path_new
- print("driver (%s): %s -> %s" % (id_data_other.name, data_path, data_path_new))
-
-
-
- for action in anim_data_actions(anim_data):
- for fcu in action.fcurves:
- data_path = fcu.data_path
- data_path_new = find_path_new(id_data, data_path, rna_update_dict, rna_update_from_map)
- # print(data_path_new)
- if data_path_new != data_path:
- if not IS_TESTING:
- fcu.data_path = data_path_new
- print("fcurve (%s): %s -> %s" % (id_data.name, data_path, data_path_new))
+
+ # check node-trees too
+ anim_data_ls = [(id_data, getattr(id_data, "animation_data", None))]
+ node_tree = getattr(id_data, "node_tree", None)
+ if node_tree:
+ anim_data_ls.append((node_tree, node_tree.animation_data))
+
+ for anim_data_base, anim_data in anim_data_ls:
+ if anim_data is None:
+ continue
+
+ for fcurve in anim_data.drivers:
+ for var in fcurve.driver.variables:
+ if var.type == 'SINGLE_PROP':
+ for tar in var.targets:
+ id_data_other = tar.id
+ data_path = tar.data_path
+
+ if id_data_other and data_path:
+ data_path_new = find_path_new(id_data_other, data_path, rna_update_dict, rna_update_from_map)
+ # print(data_path_new)
+ if data_path_new != data_path:
+ if not IS_TESTING:
+ tar.data_path = data_path_new
+ print("driver (%s): %s -> %s" % (id_data_other.name, data_path, data_path_new))
+
+ for action in anim_data_actions(anim_data):
+ for fcu in action.fcurves:
+ data_path = fcu.data_path
+ data_path_new = find_path_new(anim_data_base, data_path, rna_update_dict, rna_update_from_map)
+ # print(data_path_new)
+ if data_path_new != data_path:
+ if not IS_TESTING:
+ fcu.data_path = data_path_new
+ print("fcurve (%s): %s -> %s" % (id_data.name, data_path, data_path_new))
if __name__ == "__main__":
diff --git a/release/scripts/modules/bpy/__init__.py b/release/scripts/modules/bpy/__init__.py
index cba85d935ae..5c636d3a0df 100644
--- a/release/scripts/modules/bpy/__init__.py
+++ b/release/scripts/modules/bpy/__init__.py
@@ -26,9 +26,8 @@ data = _bpy.data
context = _bpy.context
# python modules
-from bpy import utils, path
-
-from bpy import ops as _ops_module
+from . import utils, path
+from . import ops as _ops_module
# fake operator module
ops = _ops_module.ops_fake_module
@@ -50,6 +49,10 @@ def _main():
pydoc.Helper.getline = lambda self, prompt: None
pydoc.TextDoc.use_bold = lambda self, text: text
+ # Possibly temp. addons path
+ from os.path import join, dirname, normpath
+ _sys.path.append(normpath(join(dirname(__file__), "..", "..", "addons", "modules")))
+
# if "-d" in sys.argv: # Enable this to measure startup speed
if 0:
import cProfile
diff --git a/release/scripts/modules/bpy/ops.py b/release/scripts/modules/bpy/ops.py
index 7a824ce2e68..f54b0a1fefc 100644
--- a/release/scripts/modules/bpy/ops.py
+++ b/release/scripts/modules/bpy/ops.py
@@ -115,14 +115,44 @@ class bpy_ops_submodule_op(object):
def _get_doc(self):
return op_as_string(self.idname())
+ @staticmethod
+ def _parse_args(args):
+ C_dict = None
+ C_exec = 'EXEC_DEFAULT'
+
+ if len(args) == 0:
+ pass
+ elif len(args) == 1:
+ if type(args[0]) != str:
+ C_dict = args[0]
+ else:
+ C_exec = args[0]
+ elif len(args) == 2:
+ C_exec, C_dict = args
+ else:
+ raise ValueError("1 or 2 args execution context is supported")
+
+ return C_dict, C_exec
+
+ @staticmethod
+ def _scene_update(context):
+ scene = context.scene
+ if scene: # None in backgroud mode
+ scene.update()
+ else:
+ import bpy
+ for scene in bpy.data.scenes:
+ scene.update()
+
__doc__ = property(_get_doc)
def __init__(self, module, func):
self.module = module
self.func = func
- def poll(self, context=None):
- return op_poll(self.idname_py(), context)
+ def poll(self, *args):
+ C_dict, C_exec = __class__._parse_args(args)
+ return op_poll(self.idname_py(), C_dict, C_exec)
def idname(self):
# submod.foo -> SUBMOD_OT_foo
@@ -133,42 +163,23 @@ class bpy_ops_submodule_op(object):
return self.module + "." + self.func
def __call__(self, *args, **kw):
+ import bpy
+ context = bpy.context
# Get the operator from blender
- if len(args) > 2:
- raise ValueError("1 or 2 args execution context is supported")
+ wm = context.window_manager
- C_dict = None
+ # run to account for any rna values the user changes.
+ __class__._scene_update(context)
if args:
-
- C_exec = 'EXEC_DEFAULT'
-
- if len(args) == 2:
- C_exec = args[0]
- C_dict = args[1]
- else:
- if type(args[0]) != str:
- C_dict = args[0]
- else:
- C_exec = args[0]
-
- if len(args) == 2:
- C_dict = args[1]
-
+ C_dict, C_exec = __class__._parse_args(args)
ret = op_call(self.idname_py(), C_dict, kw, C_exec)
-
else:
- ret = op_call(self.idname_py(), C_dict, kw)
+ ret = op_call(self.idname_py(), None, kw)
- if 'FINISHED' in ret:
- import bpy
- scene = bpy.context.scene
- if scene: # None in backgroud mode
- scene.update()
- else:
- for scene in bpy.data.scenes:
- scene.update()
+ if 'FINISHED' in ret and context.window_manager == wm:
+ __class__._scene_update(context)
return ret
@@ -182,8 +193,16 @@ class bpy_ops_submodule_op(object):
import bpy
idname = self.idname()
as_string = op_as_string(idname)
- descr = getattr(bpy.types, idname).bl_rna.description
- return as_string + "\n" + descr
+ op_class = getattr(bpy.types, idname)
+ descr = op_class.bl_rna.description
+ # XXX, workaround for not registering
+ # every __doc__ to save time on load.
+ if not descr:
+ descr = op_class.__doc__
+ if not descr:
+ descr = ""
+
+ return "# %s\n%s" % (descr, as_string)
def __str__(self): # used for print(...)
return "<function bpy.ops.%s.%s at 0x%x'>" % \
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py
index 92d2533c2c1..9a29b713882 100644
--- a/release/scripts/modules/bpy/path.py
+++ b/release/scripts/modules/bpy/path.py
@@ -27,12 +27,15 @@ import bpy as _bpy
import os as _os
-def abspath(path):
+def abspath(path, start=None):
"""
Returns the absolute 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 path.startswith("//"):
- return _os.path.join(_os.path.dirname(_bpy.data.filepath), path[2:])
+ return _os.path.join(_os.path.dirname(_bpy.data.filepath if start is None else start), path[2:])
return path
@@ -52,6 +55,17 @@ def relpath(path, start=None):
return path
+def is_subdir(path, directory):
+ """
+ Returns true if *path* in a subdirectory of *directory*.
+ Both paths must be absolute.
+ """
+ from os.path import normpath, normcase
+ path = normpath(normcase(path))
+ directory = normpath(normcase(directory))
+ return path.startswith(directory)
+
+
def clean_name(name, replace="_"):
"""
Returns a name with characters replaced that may cause problems under various circumstances, such as writing to a file.
@@ -99,6 +113,13 @@ def display_name(name):
return name_base
+def display_name_from_filepath(name):
+ """
+ Returns the path stripped of directort and extension, ensured to be utf8 compatible.
+ """
+ return _os.path.splitext(_os.path.basename(name))[0].encode("utf8", "replace").decode("utf8")
+
+
def resolve_ncase(path):
"""
Resolve a case insensitive path on a case sensitive system,
@@ -108,7 +129,7 @@ def resolve_ncase(path):
import os
def _ncase_path_found(path):
- if path == "" or os.path.exists(path):
+ if not path or os.path.exists(path):
return path, True
filename = os.path.basename(path) # filename may be a directory or a file
@@ -192,7 +213,9 @@ def module_names(path, recursive=False):
modules = []
for filename in sorted(_os.listdir(path)):
- if filename.endswith(".py") and filename != "__init__.py":
+ if filename == "modules":
+ pass # XXX, hard coded exception.
+ elif filename.endswith(".py") and filename != "__init__.py":
fullpath = join(path, filename)
modules.append((filename[0:-3], fullpath))
elif ("." not in filename):
diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py
index 1792425268b..e3e93203235 100644
--- a/release/scripts/modules/bpy/utils.py
+++ b/release/scripts/modules/bpy/utils.py
@@ -23,12 +23,16 @@ This module contains utility functions specific to blender but
not assosiated with blenders internal data.
"""
-import bpy as _bpy
-import os as _os
-import sys as _sys
+from _bpy import register_class
+from _bpy import unregister_class
from _bpy import blend_paths
from _bpy import script_paths as _bpy_script_paths
+from _bpy import user_resource as _user_resource
+
+import bpy as _bpy
+import os as _os
+import sys as _sys
def _test_import(module_name, loaded_modules):
@@ -99,9 +103,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
import traceback
import time
- # must be set back to True on exits
- _bpy_types._register_immediate = False
-
t_main = time.time()
loaded_modules = set()
@@ -111,7 +112,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
if reload_scripts:
_bpy_types.TypeMap.clear()
- _bpy_types.PropertiesMap.clear()
# just unload, dont change user defaults, this means we can sync to reload.
# note that they will only actually reload of the modification time changes.
@@ -120,7 +120,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
addon_disable(module_name, default_set=False)
def register_module_call(mod):
- _bpy_types._register_module(mod.__name__)
register = getattr(mod, "register", None)
if register:
try:
@@ -131,7 +130,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
print("\nWarning! '%s' has no register function, this is now a requirement for registerable scripts." % mod.__file__)
def unregister_module_call(mod):
- _bpy_types._unregister_module(mod.__name__)
unregister = getattr(mod, "unregister", None)
if unregister:
try:
@@ -140,6 +138,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
traceback.print_exc()
def test_reload(mod):
+ import imp
# reloading this causes internal errors
# because the classes from this module are stored internally
# possibly to refresh internal references too but for now, best not to.
@@ -147,7 +146,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
return mod
try:
- return reload(mod)
+ return imp.reload(mod)
except:
traceback.print_exc()
@@ -197,18 +196,14 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
for mod in modules_from_path(path, loaded_modules):
test_register(mod)
- _bpy_types._register_immediate = True
-
# deal with addons seperately
- addon_reset_all()
-
+ addon_reset_all(reload_scripts)
# run the active integration preset
filepath = preset_find(_bpy.context.user_preferences.inputs.active_keyconfig, "keyconfig")
if filepath:
keyconfig_set(filepath)
-
if reload_scripts:
import gc
print("gc.collect() -> %d" % gc.collect())
@@ -339,7 +334,14 @@ def addon_check(module_name):
loaded_default = module_name in _bpy.context.user_preferences.addons
mod = _sys.modules.get(module_name)
- loaded_state = mod and getattr(mod, "__addon_enabled__")
+ loaded_state = mod and getattr(mod, "__addon_enabled__", Ellipsis)
+
+ if loaded_state is Ellipsis:
+ print("Warning: addon-module %r found module but without"
+ " __addon_enabled__ field, possible name collision from file: %r" %
+ (module_name, getattr(mod, "__file__", "<unknown>")))
+
+ loaded_state = False
return loaded_default, loaded_state
@@ -358,15 +360,11 @@ def addon_enable(module_name, default_set=True):
import os
import sys
import bpy_types as _bpy_types
-
-
- _bpy_types._register_immediate = False
+ import imp
def handle_error():
import traceback
traceback.print_exc()
- _bpy_types._register_immediate = True
-
# reload if the mtime changes
mod = sys.modules.get(module_name)
@@ -378,7 +376,7 @@ def addon_enable(module_name, default_set=True):
print("module changed on disk:", mod.__file__, "reloading...")
try:
- reload(mod)
+ imp.reload(mod)
except:
handle_error()
del sys.modules[module_name]
@@ -396,19 +394,13 @@ def addon_enable(module_name, default_set=True):
return None
# 2) try register collected modules
- try:
- _bpy_types._register_module(module_name)
- except:
- handle_error()
- del sys.modules[module_name]
- return None
+ # removed, addons need to handle own registration now.
# 3) try run the modules register function
try:
mod.register()
except:
handle_error()
- _bpy_types._unregister_module(module_name)
del sys.modules[module_name]
return None
@@ -419,12 +411,11 @@ def addon_enable(module_name, default_set=True):
if not ext:
ext = _bpy.context.user_preferences.addons.new()
ext.module = module_name
-
- _bpy_types._register_immediate = True
mod.__addon_enabled__ = True
- print("\tbpy.utils.addon_enable", mod.__name__)
+ if _bpy.app.debug:
+ print("\tbpy.utils.addon_enable", mod.__name__)
return mod
@@ -447,7 +438,6 @@ def addon_disable(module_name, default_set=True):
mod.__addon_enabled__ = False
try:
- _bpy_types._unregister_module(module_name, free=False) # dont free because we may want to enable again.
mod.unregister()
except:
traceback.print_exc()
@@ -462,21 +452,37 @@ def addon_disable(module_name, default_set=True):
addon = addons.get(module_name)
if addon:
addons.remove(addon)
-
- print("\tbpy.utils.addon_disable", module_name)
+
+ if _bpy.app.debug:
+ print("\tbpy.utils.addon_disable", module_name)
-def addon_reset_all():
+def addon_reset_all(reload_scripts=False):
"""
Sets the addon state based on the user preferences.
"""
+ import imp
- paths = script_paths("addons") + script_paths("addons_contrib")
+ # RELEASE SCRIPTS: official scripts distributed in Blender releases
+ paths = script_paths("addons")
+
+ # CONTRIB SCRIPTS: good for testing but not official scripts yet
+ paths += script_paths("addons_contrib")
+
+ # EXTERN SCRIPTS: external projects scripts
+ paths += script_paths("addons_extern")
for path in paths:
_sys_path_ensure(path)
for mod_name, mod_path in _bpy.path.module_names(path):
is_enabled, is_loaded = addon_check(mod_name)
+
+ # first check if reload is needed before changing state.
+ if reload_scripts:
+ mod = _sys.modules.get(mod_name)
+ if mod:
+ imp.reload(mod)
+
if is_enabled == is_loaded:
pass
elif is_enabled:
@@ -485,12 +491,13 @@ def addon_reset_all():
print("\taddon_reset_all unloading", mod_name)
addon_disable(mod_name)
+
def preset_find(name, preset_path, display_name=False):
if not name:
return None
-
+
for directory in preset_paths(preset_path):
-
+
if display_name:
filename = ""
for fn in _os.listdir(directory):
@@ -533,8 +540,91 @@ def keyconfig_set(filepath):
keyconfigs.remove(kc_dupe)
else:
break
-
+
kc_new.name = name
keyconfigs.active = kc_new
+def user_resource(type, path="", create=False):
+ """
+ Return a user resource path (normally from the users home directory).
+
+ :arg type: Resource type in ['DATAFILES', 'CONFIG', 'SCRIPTS', 'AUTOSAVE'].
+ :type type: string
+ :arg subdir: Optional subdirectory.
+ :type subdir: string
+ :arg create: Treat the path as a directory and create it if its not existing.
+ :type create: boolean
+ :return: a path.
+ :rtype: string
+ """
+
+ target_path = _user_resource(type, path)
+
+ if create:
+ # should always be true.
+ if target_path:
+ # create path if not existing.
+ if not _os.path.exists(target_path):
+ try:
+ _os.makedirs(target_path)
+ except:
+ import traceback
+ traceback.print_exc()
+ target_path = ""
+ elif not _os.path.isdir(target_path):
+ print("Path %r found but isn't a directory!" % target_path)
+ target_path = ""
+
+ return target_path
+
+
+def _bpy_module_classes(module, is_registered=False):
+ typemap_list = _bpy_types.TypeMap.get(module, ())
+ i = 0
+ while i < len(typemap_list):
+ cls_weakref, path, line = typemap_list[i]
+ cls = cls_weakref()
+
+ if cls is None:
+ del typemap_list[i]
+ else:
+ if is_registered == ("bl_rna" in cls.__dict__):
+ yield (cls, path, line)
+ i += 1
+
+
+def register_module(module, verbose=False):
+ import traceback
+ if verbose:
+ print("bpy.utils.register_module(%r): ..." % module)
+ for cls, path, line in _bpy_module_classes(module, is_registered=False):
+ if verbose:
+ print(" %s of %s:%s" % (cls, path, line))
+ try:
+ register_class(cls)
+ except:
+ print("bpy.utils.register_module(): failed to registering class '%s.%s'" % (cls.__module__, cls.__name__))
+ print("\t", path, "line", line)
+ traceback.print_exc()
+ if verbose:
+ print("done.\n")
+ if "cls" not in locals():
+ raise Exception("register_module(%r): defines no classes" % module)
+
+
+def unregister_module(module, verbose=False):
+ import traceback
+ if verbose:
+ print("bpy.utils.unregister_module(%r): ..." % module)
+ for cls, path, line in _bpy_module_classes(module, is_registered=True):
+ if verbose:
+ print(" %s of %s:%s" % (cls, path, line))
+ try:
+ unregister_class(cls)
+ except:
+ print("bpy.utils.unregister_module(): failed to unregistering class '%s.%s'" % (cls.__module__, cls.__name__))
+ print("\t", path, "line", line)
+ traceback.print_exc()
+ if verbose:
+ print("done.\n") \ No newline at end of file
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index 261165d8830..4eb712a65cc 100644
--- a/release/scripts/modules/bpy_types.py
+++ b/release/scripts/modules/bpy_types.py
@@ -142,19 +142,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 Vector((1.0, 0.0, 0.0)) * self.matrix.to_3x3()
@property
def y_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
- return self.matrix.rotation_part() * Vector((0.0, 1.0, 0.0))
+ return Vector((0.0, 1.0, 0.0)) * self.matrix.to_3x3()
@property
def z_axis(self):
""" Vector pointing down the x-axis of the bone.
"""
- return self.matrix.rotation_part() * Vector((0.0, 0.0, 1.0))
+ return Vector((0.0, 0.0, 1.0)) * self.matrix.to_3x3()
@property
def basename(self):
@@ -258,15 +258,15 @@ class _GenericBone:
return bones
-class PoseBone(StructRNA, _GenericBone):
+class PoseBone(StructRNA, _GenericBone, metaclass=StructMetaIDProp):
__slots__ = ()
-class Bone(StructRNA, _GenericBone):
+class Bone(StructRNA, _GenericBone, metaclass=StructMetaIDProp):
__slots__ = ()
-class EditBone(StructRNA, _GenericBone):
+class EditBone(StructRNA, _GenericBone, metaclass=StructMetaIDProp):
__slots__ = ()
def align_orientation(self, other):
@@ -284,13 +284,13 @@ class EditBone(StructRNA, _GenericBone):
Expects a 4x4 or 3x3 matrix.
"""
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
+ z_vec = Vector((0.0, 0.0, 1.0)) * self.matrix.to_3x3()
+ self.tail = self.tail * matrix
+ self.head = self.head * matrix
scalar = matrix.median_scale
self.head_radius *= scalar
self.tail_radius *= scalar
- self.align_roll(matrix * z_vec)
+ self.align_roll(z_vec * matrix)
def ord_ind(i1, i2):
@@ -302,18 +302,25 @@ def ord_ind(i1, i2):
class Mesh(bpy_types.ID):
__slots__ = ()
- def from_pydata(self, verts, edges, faces):
+ def from_pydata(self, vertices, edges, faces):
"""
Make a mesh from a list of verts/edges/faces
Until we have a nicer way to make geometry, use this.
+
+ :arg vertices: float triplets each representing (X, Y, Z) eg: [(0.0, 1.0, 0.5), ...].
+ :type vertices: iterable object
+ :arg edges: int pairs, each pair contains two indices to the *vertices* argument. eg: [(1, 2), ...]
+ :type edges: iterable object
+ :arg faces: iterator of faces, each faces contains three or four indices to the *vertices* argument. eg: [(5, 6, 8, 9), (1, 2, 3), ...]
+ :type faces: iterable object
"""
- self.vertices.add(len(verts))
+ self.vertices.add(len(vertices))
self.edges.add(len(edges))
self.faces.add(len(faces))
- verts_flat = [f for v in verts for f in v]
- self.vertices.foreach_set("co", verts_flat)
- del verts_flat
+ vertices_flat = [f for v in vertices for f in v]
+ self.vertices.foreach_set("co", vertices_flat)
+ del vertices_flat
edges_flat = [i for e in edges for i in e]
self.edges.foreach_set("vertices", edges_flat)
@@ -326,7 +333,7 @@ class Mesh(bpy_types.ID):
else:
return f[0], f[1], f[2], 0
elif f[2] == 0 or f[3] == 0:
- return f[3], f[0], f[1], f[2]
+ return f[2], f[3], f[0], f[1]
return f
faces_flat = [v for f in faces for v in treat_face(f)]
@@ -543,85 +550,34 @@ class Text(bpy_types.ID):
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
-
+# values are module: [(cls, path, line), ...]
TypeMap = {}
-# Properties (IDPropertyGroup) are different from types because they need to be registered
-# before adding sub properties to them, so they are registered on definition
-# and unregistered on unload
-PropertiesMap = {}
-
-# Using our own loading function we set this to false
-# so when running a script directly in the text editor
-# registers moduals instantly.
-_register_immediate = True
-
-
-def _unregister_module(module, free=True):
- for t in TypeMap.get(module, ()):
- try:
- bpy_types.unregister(t)
- except:
- import traceback
- print("bpy.utils._unregister_module(): Module '%s' failed to unregister class '%s.%s'" % (module, t.__module__, t.__name__))
- traceback.print_exc()
-
- if free == True and module in TypeMap:
- del TypeMap[module]
-
- for t in PropertiesMap.get(module, ()):
- try:
- bpy_types.unregister(t)
- except:
- import traceback
- print("bpy.utils._unload_module(): Module '%s' failed to unregister class '%s.%s'" % (module, t.__module__, t.__name__))
- traceback.print_exc()
-
- if free == True and module in PropertiesMap:
- del PropertiesMap[module]
-
-
-def _register_module(module):
- for t in TypeMap.get(module, ()):
- try:
- bpy_types.register(t)
- except:
- import traceback
- import sys
- print("bpy.utils._register_module(): '%s' failed to register class '%s.%s'" % (sys.modules[module].__file__, t.__module__, t.__name__))
- traceback.print_exc()
class RNAMeta(type):
- @classmethod
- def _register_immediate(cls):
- return _register_immediate
-
def __new__(cls, name, bases, classdict, **args):
result = type.__new__(cls, name, bases, classdict)
if bases and bases[0] != StructRNA:
+ import traceback
+ import weakref
module = result.__module__
- ClassMap = TypeMap
-
- # Register right away if needed
- if cls._register_immediate():
- bpy_types.register(result)
- ClassMap = PropertiesMap
-
# first part of packages only
if "." in module:
module = module[:module.index(".")]
- ClassMap.setdefault(module, []).append(result)
+ sf = traceback.extract_stack(limit=2)[0]
+
+ TypeMap.setdefault(module, []).append((weakref.ref(result), sf[0], sf[1]))
return result
-class RNAMetaRegister(RNAMeta, StructMetaIDProp):
- @classmethod
- def _register_immediate(cls):
- return True
+import collections
+
+
+class RNAMetaIDProp(RNAMeta, StructMetaIDProp):
+ pass
class OrderedMeta(RNAMeta):
@@ -638,7 +594,7 @@ class OrderedMeta(RNAMeta):
# with doc generation 'self.properties.bl_rna.properties' can fail
class Operator(StructRNA, metaclass=OrderedMeta):
__slots__ = ()
-
+
def __getattribute__(self, attr):
properties = StructRNA.path_resolve(self, "properties")
bl_rna = getattr(properties, "bl_rna", None)
@@ -650,16 +606,22 @@ class Operator(StructRNA, metaclass=OrderedMeta):
properties = StructRNA.path_resolve(self, "properties")
bl_rna = getattr(properties, "bl_rna", None)
if bl_rna and attr in bl_rna.properties:
- setattr(properties, attr, value)
+ return setattr(properties, attr, value)
return super().__setattr__(attr, value)
def __delattr__(self, attr):
properties = StructRNA.path_resolve(self, "properties")
bl_rna = getattr(properties, "bl_rna", None)
if bl_rna and attr in bl_rna.properties:
- delattr(properties, attr)
+ return delattr(properties, attr)
return super().__delattr__(attr)
+ def as_keywords(self, ignore=()):
+ """ Return a copy of the properties as a dictionary.
+ """
+ ignore = ignore + ("rna_type",)
+ return {attr: getattr(self, attr) for attr in self.properties.rna_type.properties.keys() if attr not in ignore}
+
class Macro(StructRNA, metaclass=OrderedMeta):
# bpy_types is imported before ops is defined
@@ -672,7 +634,7 @@ class Macro(StructRNA, metaclass=OrderedMeta):
return ops.macro_define(self, opname)
-class IDPropertyGroup(StructRNA, metaclass=RNAMetaRegister):
+class IDPropertyGroup(StructRNA, metaclass=RNAMetaIDProp):
__slots__ = ()
@@ -680,6 +642,10 @@ class RenderEngine(StructRNA, metaclass=RNAMeta):
__slots__ = ()
+class KeyingSetInfo(StructRNA, metaclass=RNAMeta):
+ __slots__ = ()
+
+
class _GenericUI:
__slots__ = ()
@@ -691,7 +657,12 @@ class _GenericUI:
def draw_ls(self, context):
for func in draw_ls._draw_funcs:
- func(self, context)
+ # so bad menu functions dont stop the entire menu from drawing.
+ try:
+ func(self, context)
+ except:
+ import traceback
+ traceback.print_exc()
draw_funcs = draw_ls._draw_funcs = [cls.draw]
cls.draw = draw_ls
@@ -739,7 +710,7 @@ class Menu(StructRNA, _GenericUI, metaclass=RNAMeta):
import bpy.utils
layout = self.layout
-
+
if not searchpaths:
layout.label("* Missing Paths *")
diff --git a/release/scripts/modules/console/__init__.py b/release/scripts/modules/console/__init__.py
index efd2ed85acc..97cb14822c4 100644
--- a/release/scripts/modules/console/__init__.py
+++ b/release/scripts/modules/console/__init__.py
@@ -1,17 +1,22 @@
# Copyright (c) 2009 www.stani.be (GPL license)
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# ##### BEGIN GPL LICENSE BLOCK #####
#
-# 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 Lesser General Public License for more details.
+# 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.
#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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>
diff --git a/release/scripts/modules/console/complete_calltip.py b/release/scripts/modules/console/complete_calltip.py
index 87fac9f4c07..29187297707 100644
--- a/release/scripts/modules/console/complete_calltip.py
+++ b/release/scripts/modules/console/complete_calltip.py
@@ -1,17 +1,22 @@
# Copyright (c) 2009 www.stani.be (GPL license)
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# ##### BEGIN GPL LICENSE BLOCK #####
#
-# 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 Lesser General Public License for more details.
+# 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.
#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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-80 compliant>
@@ -168,7 +173,10 @@ def complete(line, cursor, namespace):
'abs(number) -> number\\nReturn the absolute value of the argument.'
"""
matches = []
+ word = ''
+ scrollback = ''
match = RE_DEF_COMPLETE.search(line[:cursor])
+
if match:
word = match.group(1)
func_word = match.group(2)
@@ -176,7 +184,7 @@ def complete(line, cursor, namespace):
func = eval(func_word, namespace)
except Exception:
func = None
- scrollback = ''
+
if func:
doc = get_doc(func)
argspec = get_argspec(func, doc=doc)
@@ -186,7 +194,5 @@ def complete(line, cursor, namespace):
elif doc:
scrollback += '\n' + doc
scrollback = reduce_newlines(scrollback)
- else:
- word = ''
- scrollback = ''
+
return matches, word, scrollback
diff --git a/release/scripts/modules/console/complete_import.py b/release/scripts/modules/console/complete_import.py
index 4b50cf6deb8..63f15d9cf77 100644
--- a/release/scripts/modules/console/complete_import.py
+++ b/release/scripts/modules/console/complete_import.py
@@ -1,17 +1,22 @@
# Copyright (c) 2009 Fernando Perez, www.stani.be (GPL license)
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# ##### BEGIN GPL LICENSE BLOCK #####
#
-# 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 Lesser General Public License for more details.
+# 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.
#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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 #####
# Original copyright (see docstring):
#*****************************************************************************
diff --git a/release/scripts/modules/console/complete_namespace.py b/release/scripts/modules/console/complete_namespace.py
index 7a9fd331e49..a31280ebff0 100644
--- a/release/scripts/modules/console/complete_namespace.py
+++ b/release/scripts/modules/console/complete_namespace.py
@@ -1,17 +1,22 @@
# Copyright (c) 2009 www.stani.be (GPL license)
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# ##### BEGIN GPL LICENSE BLOCK #####
#
-# 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 Lesser General Public License for more details.
+# 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.
#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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-80 compliant>
diff --git a/release/scripts/modules/console/intellisense.py b/release/scripts/modules/console/intellisense.py
index 0f9acf9b6a9..9352d7c14e1 100644
--- a/release/scripts/modules/console/intellisense.py
+++ b/release/scripts/modules/console/intellisense.py
@@ -1,17 +1,22 @@
# Copyright (c) 2009 www.stani.be (GPL license)
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# ##### BEGIN GPL LICENSE BLOCK #####
#
-# 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 Lesser General Public License for more details.
+# 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.
#
-# You should have received a copy of the GNU Lesser General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# 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-80 compliant>
@@ -75,10 +80,10 @@ def complete(line, cursor, namespace, private=True):
# unquoted word -> module or attribute completion
word = re_unquoted_word.group(1)
if RE_MODULE.match(line):
- import complete_import
+ from . import complete_import
matches = complete_import.complete(line)
else:
- import complete_namespace
+ from . import complete_namespace
matches = complete_namespace.complete(word, namespace, private)
else:
# for now we don't have completers for strings
@@ -112,7 +117,7 @@ def expand(line, cursor, namespace, private=True):
'abs(number) -> number\\nReturn the absolute value of the argument.'
"""
if line[:cursor].strip().endswith('('):
- import complete_calltip
+ from . import complete_calltip
matches, word, scrollback = complete_calltip.complete(line,
cursor, namespace)
no_calltip = False
diff --git a/release/scripts/modules/image_utils.py b/release/scripts/modules/image_utils.py
new file mode 100644
index 00000000000..d74c89ac173
--- /dev/null
+++ b/release/scripts/modules/image_utils.py
@@ -0,0 +1,27 @@
+# ##### 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>
+
+
+def image_load(filepath, dirpath, place_holder=False, recursive=False, convert_callback=None):
+ import bpy
+ try:
+ return bpy.data.images.load(filepath)
+ except SystemError:
+ return bpy.data.images.new("Untitled", 128, 128)
diff --git a/release/scripts/modules/io_utils.py b/release/scripts/modules/io_utils.py
index eb9b2eaa90b..39b38669188 100644
--- a/release/scripts/modules/io_utils.py
+++ b/release/scripts/modules/io_utils.py
@@ -37,7 +37,7 @@ class ExportHelper:
self.filepath = blend_filepath + self.filename_ext
- context.window_manager.add_fileselect(self)
+ context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
def check(self, context):
@@ -53,7 +53,7 @@ class ImportHelper:
filepath = StringProperty(name="File Path", description="Filepath used for importing the file", maxlen=1024, default="", subtype='FILE_PATH')
def invoke(self, context, event):
- context.window_manager.add_fileselect(self)
+ context.window_manager.fileselect_add(self)
return {'RUNNING_MODAL'}
diff --git a/release/scripts/keyingsets/keyingsets_utils.py b/release/scripts/modules/keyingsets_utils.py
index 901aa715296..00ad45cf9bb 100644
--- a/release/scripts/keyingsets/keyingsets_utils.py
+++ b/release/scripts/modules/keyingsets_utils.py
@@ -1,45 +1,81 @@
-# This file defines a set of methods that are useful for various
+# ##### 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 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.
+# for polling, iterator callbacks, and also generate callbacks.
+# All of these can be used in conjunction with the others.
+
+__all__ = [
+ "path_add_property",
+ "RKS_POLL_selected_objects",
+ "RKS_POLL_selected_bones",
+ "RKS_POLL_selected_items",
+ "RKS_ITER_selected_item",
+ "RKS_GEN_available",
+ "RKS_GEN_location",
+ "RKS_GEN_rotation",
+ "RKS_GEN_scaling",
+]
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;
+ return path + "." + prop
else:
- return prop;
+ return prop
###########################
# Poll Callbacks
+
# selected objects
def RKS_POLL_selected_objects(ksi, context):
- return context.active_object or len(context.selected_objects);
-
+ 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
+ # 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;
+ 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);
+ 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'):
@@ -52,34 +88,49 @@ def RKS_ITER_selected_item(ksi, context, ks):
###########################
# Generate Callbacks
+
# 'Available' F-Curves
def RKS_GEN_available(ksi, context, ks, data):
- # try to get the animation data associated with the closest
+ # 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
+ return
+
+ # if we haven't got an ID-block as 'data', try to restrict
+ # paths added to only those which branch off from here
+ # i.e. for bones
+ if id_block != data:
+ basePath = data.path_from_id()
+ else:
+ basePath = None # this is not needed...
+
+ # for each F-Curve, include a 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)
-
+ if basePath:
+ if basePath in fcu.data_path:
+ ks.paths.add(id_block, fcu.data_path, index=fcu.array_index)
+ else:
+ ks.paths.add(id_block, fcu.data_path, index=fcu.array_index)
+
# ------
+
# get ID block and based ID path for transform generators
+# private function
def get_transform_generators_base_info(data):
- # ID-block for the 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:
@@ -89,29 +140,31 @@ def get_transform_generators_base_info(data):
# 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
+
+# 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, group_method='NAMED', group_name=grouping)
else:
ks.paths.add(id_block, path)
-# Rotation
+
+# 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)
-
+ 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':
@@ -120,40 +173,24 @@ def RKS_GEN_rotation(ksi, context, ks, data):
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, group_method='NAMED', group_name=grouping)
else:
ks.paths.add(id_block, path)
-# Scaling
+
+# 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)
-
+ 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, group_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():
- pass
-
-
-def unregister():
- pass
-
-if __name__ == "__main__":
- register()
-
-###########################
diff --git a/release/scripts/modules/rigify/__init__.py b/release/scripts/modules/rigify/__init__.py
deleted file mode 100644
index 98d9bb235a2..00000000000
--- a/release/scripts/modules/rigify/__init__.py
+++ /dev/null
@@ -1,560 +0,0 @@
-# ##### 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 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_PREFIX = "ORG-"
-MCH_PREFIX = "MCH-"
-DEF_PREFIX = "DEF-"
-
-WGT_PREFIX = "WGT-"
-
-
-class RigifyError(Exception):
- """Exception raised for errors in the metarig.
- """
-
- def __init__(self, message):
- self.message = message
-
- def __str__(self):
- return repr(self.message)
-
-
-def submodule_func_from_type(bone_type):
- type_pair = bone_type.split(".")
-
- # 'leg.ik' will look for an ik function in the leg module
- # 'leg' will look up leg.main
- if len(type_pair) == 1:
- type_pair = type_pair[0], "main"
-
- type_name, func_name = type_pair
-
- # from rigify import leg
- try:
- submod = __import__(name="%s.%s" % (__package__, type_name), fromlist=[type_name])
- except ImportError:
- raise RigifyError("python module for type '%s' not found" % type_name)
-
- reload(submod)
- return type_name, submod, getattr(submod, func_name)
-
-
-def get_submodule_types():
- import os
- submodules = []
- files = os.listdir(os.path.dirname(__file__))
- for f in files:
- if not f.startswith("_") and f.endswith(".py"):
- submodules.append(f[:-3])
-
- return sorted(submodules)
-
-
-def get_bone_type_options(pbone, type_name):
- options = {}
- bone_name = pbone.name
- for key, value in pbone.items():
- key_pair = key.rsplit(".")
- # get all bone properties
- """"
- if key_pair[0] == type_name:
- if len(key_pair) != 2:
- raise RigifyError("option error for bone '%s', property name was not a pair '%s'" % (bone_name, key_pair))
- options[key_pair[1]] = value
- """
- options[key] = value
-
- return options
-
-
-def get_layer_dict(options):
- '''
- Extracts layer info from a bone options dict
- defaulting to the layer index if not set.
- '''
- layer_default = [False] * 32
- result = {}
- for i, layer_type in enumerate(LAYER_TYPES):
- # no matter if its not defined
- layer_index = options.get("layer_" + layer_type, i + 2)
- layer = layer_default[:]
- layer[layer_index-1] = True
- result[layer_type] = layer
- return result
-
-
-def validate_rig(context, obj):
- '''
- Makes no changes
- only runs the metarig definitions and reports errors
- '''
- type_found = False
-
- for pbone in obj.pose.bones:
- bone_name = pbone.name
- bone_type = pbone.get("type", "")
-
- if bone_type:
- bone_type_list = [bt for bt in bone_type.replace(",", " ").split()]
- else:
- bone_type_list = []
-
- for bone_type in bone_type_list:
- if bone_type.split(".")[0] in SPECIAL_TYPES:
- continue
-
- type_name, submod, type_func = submodule_func_from_type(bone_type)
- reload(submod)
- submod.metarig_definition(obj, bone_name)
- type_found = True
-
- get_bone_type_options(pbone, bone_type)
-
- # missing, - check for duplicate root bone.
-
- if not type_found:
- raise RigifyError("This rig has no 'type' properties defined on any pose bones, nothing to do")
-
-
-def generate_rig(context, obj_orig, prefix="ORG-", META_DEF=True):
- '''
- Main function for generating
- '''
- from collections import OrderedDict
- import rigify_utils
- reload(rigify_utils)
-
- print("Begin...")
-
- # Not needed but catches any errors before duplicating
- validate_rig(context, obj_orig)
-
- use_global_undo = context.user_preferences.edit.use_global_undo
- context.user_preferences.edit.use_global_undo = False
- mode_orig = context.mode
- rest_backup = obj_orig.data.pose_position
- obj_orig.data.pose_position = 'REST'
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- scene = context.scene
-
- # Check if the generated rig already exists, so we can
- # regenerate in the same object. If not, create a new
- # object to generate the rig in.
- print("Fetch rig.")
- try:
- name = obj_orig["rig_object_name"]
- except KeyError:
- name = "rig"
-
- try:
- obj = scene.objects[name]
- except KeyError:
- obj = bpy.data.objects.new(name, bpy.data.armatures.new(name))
- scene.objects.link(obj)
-
- obj.data.pose_position = 'POSE'
-
- # Get rid of anim data in case the rig already existed
- print("Clear rig animation data.")
- obj.animation_data_clear()
-
- # Select generated rig object
- obj_orig.select = False
- obj.select = True
- scene.objects.active = obj
-
- # Remove all bones from the generated rig armature.
- bpy.ops.object.mode_set(mode='EDIT')
- for bone in obj.data.edit_bones:
- obj.data.edit_bones.remove(bone)
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Create temporary duplicates for merging
- temp_rig_1 = obj_orig.copy()
- temp_rig_1.data = obj_orig.data.copy()
- scene.objects.link(temp_rig_1)
-
- temp_rig_2 = obj_orig.copy()
- temp_rig_2.data = obj.data
- scene.objects.link(temp_rig_2)
-
- # Select the temp rigs for merging
- for objt in scene.objects:
- objt.select = False # deselect all objects
- temp_rig_1.select = True
- temp_rig_2.select = True
- scene.objects.active = temp_rig_2
-
- # Merge the temporary rigs
- bpy.ops.object.join(context)
-
- # Delete the second temp rig
- bpy.ops.object.delete()
-
- # Select the generated rig
- for objt in scene.objects:
- objt.select = False # deselect all objects
- obj.select = True
- scene.objects.active = obj
-
- # Copy over the pose_bone properties
- for bone in obj_orig.pose.bones:
- 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.lock_rotations_4d = bone.lock_rotations_4d
- bone_gen.lock_location = tuple(bone.lock_location)
- bone_gen.lock_scale = tuple(bone.lock_scale)
-
- # Custom properties
- for prop in bone.keys():
- bone_gen[prop] = bone[prop]
-
- # Copy over bone properties
- for bone in obj_orig.data.bones:
- bone_gen = obj.data.bones[bone.name]
-
- # B-bone stuff
- bone_gen.bbone_segments = bone.bbone_segments
- bone_gen.bbone_in = bone.bbone_in
- bone_gen.bbone_out = bone.bbone_out
-
-
- # Create proxy deformation rig
- # TODO: remove this
- if META_DEF:
- obj_def = obj_orig.copy()
- obj_def.data = obj_orig.data.copy()
- scene.objects.link(obj_def)
-
- scene.update()
- print("On to the real work.")
-
- arm = obj.data
-
- # prepend the ORG prefix to the bones, and create the base_names mapping
- base_names = {}
- bpy.ops.object.mode_set(mode='EDIT')
- for bone in arm.edit_bones:
- bone_name = bone.name
- bone.name = ORG_PREFIX + bone_name
- base_names[bone.name] = bone_name
-
- # create root_bone
- bpy.ops.object.mode_set(mode='EDIT')
- edit_bone = obj.data.edit_bones.new("root")
- root_bone = edit_bone.name
- edit_bone.head = (0.0, 0.0, 0.0)
- edit_bone.tail = (0.0, 1.0, 0.0)
- edit_bone.roll = 0.0
- edit_bone.layers = ROOT_LAYERS
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # key: bone name
- # value: {type:definition, ...}
- # where type is the submodule name - leg, arm etc
- # and definition is a list of bone names
- bone_definitions = {}
-
- # key: bone name
- # value: [functions, ...]
- # each function is from the module. eg leg.ik, arm.main
- bone_typeinfos = {}
-
- # key: bone name
- # value: [new_bone_name, ...]
- # where each bone with a 'type' stores a list of bones that it created
- # ...needed so we can override the root parent
- bone_genesis = {}
-
-
- # inspect all bones and assign their definitions before modifying
- for pbone in obj.pose.bones:
- bone_name = pbone.name
- bone_type = pbone.get("type", "")
- if bone_type:
- bone_type_list = [bt for bt in bone_type.replace(",", " ").split()]
-
- # not essential but means running autorig again wont do anything
- del pbone["type"]
- else:
- bone_type_list = []
-
- for bone_type in bone_type_list:
- type_name, submod, type_func = submodule_func_from_type(bone_type)
- reload(submod)
-
- bone_def_dict = bone_definitions.setdefault(bone_name, {})
-
- # Only calculate bone definitions once
- if type_name not in bone_def_dict:
- bone_def_dict[type_name] = submod.metarig_definition(obj, bone_name)
-
- bone_typeinfo = bone_typeinfos.setdefault(bone_name, [])
- bone_typeinfo.append((type_name, type_func))
-
-
- # sort bones, not needed but gives more pradictable execution which may be useful in rare cases
- bones_sorted = obj.pose.bones.values()
- bones_sorted.sort(key=lambda pbone: pbone.name) # first sort by names
- bones_sorted.sort(key=lambda pbone: len(pbone.parent_recursive)) # parents before children
-
- # now we have all the info about bones we can start operating on them
- # for pbone in obj.pose.bones:
- for pbone in bones_sorted:
- bone_name = pbone.name
- print(bone_name)
- if bone_name not in bone_typeinfos:
- continue
-
- bone_def_dict = bone_definitions[bone_name]
-
- # Only blend results from the same submodule, eg.
- # leg.ik and arm.fk could not be blended.
- results = OrderedDict()
-
- bone_names_pre = {bone.name for bone in arm.bones}
-
- for type_name, type_func in bone_typeinfos[bone_name]:
- print(" " + type_name)
- # this bones definition of the current typeinfo
- definition = bone_def_dict[type_name]
- options = get_bone_type_options(pbone, type_name)
-
- bpy.ops.object.mode_set(mode='EDIT')
- ret = type_func(obj, definition, base_names, options)
- bpy.ops.object.mode_set(mode='OBJECT')
-
- if ret:
- result_submod = results.setdefault(type_name, [])
-
- if result_submod and len(result_submod[-1]) != len(ret):
- raise RigifyError("bone lists not compatible: %s, %s" % (result_submod[-1], ret))
-
- result_submod.append(ret)
-
- for result_submod in results.values():
- # blend 2 chains
- definition = bone_def_dict[type_name]
-
- if len(result_submod) == 2:
- blend_bone_list(obj, definition, result_submod[0], result_submod[1], target_bone=bone_name)
-
-
- bone_names_post = {bone.name for bone in arm.bones}
-
- # Store which bones were created from this one
- bone_genesis[bone_name] = list(bone_names_post - bone_names_pre)
-
- # need a reverse lookup on bone_genesis so as to know immediately
- # where a bone comes from
- bone_genesis_reverse = {}
- '''
- for bone_name, bone_children in bone_genesis.items():
- for bone_child_name in bone_children:
- bone_genesis_reverse[bone_child_name] = bone_name
- '''
-
-
- if root_bone:
- # assign all new parentless bones to this
-
- bpy.ops.object.mode_set(mode='EDIT')
- root_ebone = arm.edit_bones[root_bone]
- for ebone in arm.edit_bones:
- bone_name = ebone.name
- if ebone.parent is None:
- ebone.parent = root_ebone
- '''
- if ebone.parent is None and bone_name not in base_names:
- # check for override
- bone_creator = bone_genesis_reverse[bone_name]
- pbone_creator = obj.pose.bones[bone_creator]
- root_bone_override = pbone_creator.get("root", "")
-
- if root_bone_override:
- root_ebone_tmp = arm.edit_bones[root_bone_override]
- else:
- root_ebone_tmp = root_ebone
-
- ebone.use_connect = False
- ebone.parent = root_ebone_tmp
- '''
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
-
- if META_DEF:
- # for pbone in obj_def.pose.bones:
- for bone_name, bone_name_new in base_names.items():
- #pbone_from = bone_name
- pbone = obj_def.pose.bones[bone_name_new]
-
- con = pbone.constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = bone_name
-
- if not pbone.bone.use_connect:
- con = pbone.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = bone_name
-
- # would be 'REST' from when copied
- obj_def.data.pose_position = 'POSE'
-
- # todo - make a more generic system?
- layer_tot = [False] * 32
- layer_last = layer_tot[:]
- layer_last[31] = True
- layer_second_last = layer_tot[:]
- layer_second_last[30] = True
-
- for bone_name, bone in arm.bones.items():
- bone.use_deform = False # Non DEF bones shouldn't deform
- if bone_name.startswith(ORG_PREFIX):
- bone.layers = ORG_LAYERS
- elif bone_name.startswith(MCH_PREFIX): # XXX fixme
- bone.layers = MCH_LAYERS
- elif bone_name.startswith(DEF_PREFIX): # XXX fixme
- bone.layers = DEF_LAYERS
- bone.use_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)
-
- layer_tot[:] = [max(lay) for lay in zip(layer_tot, bone.layers)]
-
- # 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)]
- arm.layers = layer_show
-
-
- # obj.hide = True
- obj.data.show_axes = False
-
- bpy.ops.object.mode_set(mode=mode_orig)
- obj_orig.data.pose_position = rest_backup
- obj.data.pose_position = 'POSE'
- obj_orig.data.pose_position = 'POSE'
- context.user_preferences.edit.use_global_undo = use_global_undo
-
- print("Done.\n")
-
- return obj
-
-
-def generate_test(context, metarig_type="", GENERATE_FINAL=True):
- import os
- new_objects = []
-
- scene = context.scene
-
- def create_empty_armature(name):
- armature = bpy.data.armatures.new(name)
- obj_new = bpy.data.objects.new(name, armature)
- scene.objects.link(obj_new)
- scene.objects.active = obj_new
- for obj in scene.objects:
- obj.select = False
- obj_new.select = True
-
- for module_name in get_submodule_types():
- if (metarig_type and module_name != metarig_type):
- continue
-
- # XXX workaround!, problem with updating the pose matrix.
- if module_name == "delta":
- continue
-
- type_name, submodule, func = submodule_func_from_type(module_name)
-
- metarig_template = getattr(submodule, "metarig_template", None)
-
- if metarig_template:
- create_empty_armature("meta_" + module_name) # sets active
- metarig_template()
- obj = context.active_object
- obj.location = scene.cursor_location
-
- if GENERATE_FINAL:
- obj_new = generate_rig(context, obj)
- new_objects.append((obj, obj_new))
- else:
- new_objects.append((obj, None))
- else:
- print("note: rig type '%s' has no metarig_template(), can't test this" % module_name)
-
- return new_objects
-
-
-def generate_test_all(context, GRAPH=False):
- import rigify
- import rigify_utils
- import graphviz_export
- import os
- reload(rigify)
- reload(rigify_utils)
- reload(graphviz_export)
-
- new_objects = rigify.generate_test(context)
-
- if GRAPH:
- 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.path.clean_name(obj.name)
-
- path_dot = fn + ".dot"
- path_png = fn + ".png"
- saved = graphviz_export.graph_armature(obj, path_dot, CONSTRAINTS=True, DRIVERS=True)
-
- #if saved:
- # os.system("dot -Tpng %s > %s; eog %s" % (path_dot, path_png, path_png))
-
- i = 0
- for obj, obj_new in new_objects:
- obj.data.draw_type = 'STICK'
- obj.location[1] += i
- obj_new.location[1] += i
- obj_new.select = False
- obj.select = True
- i += 4
-
-
-if __name__ == "__main__":
- generate_rig(bpy.context, bpy.context.active_object)
diff --git a/release/scripts/modules/rigify/arm_biped.py b/release/scripts/modules/rigify/arm_biped.py
deleted file mode 100644
index ac878c3c076..00000000000
--- a/release/scripts/modules/rigify/arm_biped.py
+++ /dev/null
@@ -1,396 +0,0 @@
-# ##### 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 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
-
-METARIG_NAMES = "shoulder", "arm", "forearm", "hand"
-
-
-def metarig_template():
- # 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('shoulder')
- bone.head[:] = 0.0000, -0.0425, 0.0000
- bone.tail[:] = 0.0942, -0.0075, 0.0333
- bone.roll = -0.2227
- bone.use_connect = False
- bone = arm.edit_bones.new('upper_arm')
- bone.head[:] = 0.1066, -0.0076, -0.0010
- bone.tail[:] = 0.2855, 0.0206, -0.0104
- bone.roll = 1.6152
- bone.use_connect = False
- bone.parent = arm.edit_bones['shoulder']
- bone = arm.edit_bones.new('forearm')
- bone.head[:] = 0.2855, 0.0206, -0.0104
- bone.tail[:] = 0.4550, -0.0076, -0.0023
- bone.roll = 1.5153
- bone.use_connect = True
- bone.parent = arm.edit_bones['upper_arm']
- bone = arm.edit_bones.new('hand')
- bone.head[:] = 0.4550, -0.0076, -0.0023
- bone.tail[:] = 0.5423, -0.0146, -0.0131
- bone.roll = -3.0083
- bone.use_connect = True
- bone.parent = arm.edit_bones['forearm']
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['upper_arm']
- pbone['type'] = 'arm_biped'
-
-
-def metarig_definition(obj, orig_bone_name):
- mt = bone_class_instance(obj, METARIG_NAMES) # meta
- mt.arm = orig_bone_name
- mt.update()
-
- mt.shoulder_p = mt.arm_p.parent
-
- if not mt.shoulder_p:
- raise RigifyError("could not find '%s' parent, skipping:" % orig_bone_name)
-
- mt.shoulder = mt.shoulder_p.name
-
- # We could have some bones attached, find the bone that has this as its 2nd parent
- hands = []
- for pbone in obj.pose.bones:
- index = pbone.parent_index(mt.arm_p)
- if index == 2 and pbone.bone.use_connect and pbone.bone.parent.use_connect:
- hands.append(pbone)
-
- if len(hands) != 1:
- raise RigifyError("Found %s possible hands attached to this arm, expected 1 from bone: %s" % ([pbone.name for pbone in hands], orig_bone_name))
-
- # first add the 2 new bones
- mt.hand_p = hands[0]
- mt.hand = mt.hand_p.name
-
- mt.forearm_p = mt.hand_p.parent
- mt.forearm = mt.forearm_p.name
-
- return mt.names()
-
-
-def ik(obj, definitions, base_names, options):
-
- arm = obj.data
-
- mt = bone_class_instance(obj, METARIG_NAMES)
- mt.shoulder, mt.arm, mt.forearm, mt.hand = definitions
- mt.update()
-
- ik = bone_class_instance(obj, ["pole", "pole_vis", "hand_vis"])
- ik_chain = mt.copy(to_fmt="MCH-%s_ik", base_names=base_names, exclude_attrs=["shoulder"])
-
- # IK needs no parent_index
- ik_chain.hand_e.use_connect = False
- ik_chain.hand_e.parent = None
- ik_chain.hand_e.use_local_location = False
- ik_chain.rename("hand", get_base_name(base_names[mt.hand]) + "_ik" + get_side_name(mt.hand))
-
- ik_chain.arm_e.use_connect = False
- ik_chain.arm_e.parent = mt.shoulder_e
-
- # Add the bone used for the arms poll target
- #ik.pole = add_pole_target_bone(obj, mt.forearm, get_base_name(base_names[mt.forearm]) + "_target" + get_side_name(mt.forearm), mode='ZAVERAGE')
- ik.pole = add_pole_target_bone(obj, mt.forearm, "elbow_target" + get_side_name(mt.forearm), mode='ZAVERAGE')
-
- ik.update()
- ik.pole_e.use_local_location = False
-
- # option: elbow_parent
- elbow_parent_name = options.get("elbow_parent", "")
-
- if elbow_parent_name:
- try:
- elbow_parent_e = arm.edit_bones[ORG_PREFIX + elbow_parent_name]
- except:
- # TODO, old/new parent mapping
- raise RigifyError("parent bone from property 'arm_biped_generic.elbow_parent' not found '%s'" % elbow_parent_name)
- ik.pole_e.parent = elbow_parent_e
-
- # update bones after this!
- ik.hand_vis = add_stretch_to(obj, mt.hand, ik_chain.hand, "VIS-%s_ik" % base_names[mt.hand])
- ik.pole_vis = add_stretch_to(obj, mt.forearm, ik.pole, "VIS-%s_ik" % base_names[mt.forearm])
-
- ik.update()
- ik.hand_vis_e.hide_select = True
- ik.pole_vis_e.hide_select = True
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- mt.update()
- ik.update()
- ik_chain.update()
-
- # Set IK dof
- ik_chain.forearm_p.lock_ik_x = False
- ik_chain.forearm_p.lock_ik_y = True
- ik_chain.forearm_p.lock_ik_z = True
-
- con = ik_chain.forearm_p.constraints.new('IK')
- con.target = obj
- con.subtarget = ik_chain.hand
- con.pole_target = obj
- con.pole_subtarget = ik.pole
-
- con.use_tail = True
- con.use_stretch = True
- con.use_target = True
- con.use_rotation = False
- con.chain_count = 2
- con.pole_angle = -pi/2
-
- # last step setup layers
- if "ik_layer" in options:
- layer = [n==options["ik_layer"] for n in range(0,32)]
- else:
- layer = list(mt.arm_b.layers)
- ik_chain.hand_b.layers = layer
- ik.hand_vis_b.layers = layer
- ik.pole_b.layers = layer
- ik.pole_vis_b.layers = layer
-
- bpy.ops.object.mode_set(mode='EDIT')
- # don't blend the shoulder
- return [None] + ik_chain.names()
-
-
-def fk(obj, definitions, base_names, options):
-
- arm = obj.data
-
- mt = bone_class_instance(obj, METARIG_NAMES)
- mt.shoulder, mt.arm, mt.forearm, mt.hand = definitions
- mt.update()
-
- ex = bone_class_instance(obj, ["socket", "hand_delta"])
- fk_chain = mt.copy(base_names=base_names)
-
- # 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)))
-
- # upper arm constrains to this.
- ex.socket_e = copy_bone_simple(arm, mt.arm, "MCH-%s_socket" % base_names[mt.arm])
- ex.socket = ex.socket_e.name
- ex.socket_e.use_connect = False
- ex.socket_e.parent = mt.shoulder_e
- ex.socket_e.length *= 0.5
-
- # insert the 'MCH-delta_hand', between the forearm and the hand
- # copies forarm rotation
- ex.hand_delta_e = copy_bone_simple(arm, fk_chain.hand, "MCH-delta_%s" % base_names[mt.hand], parent=True)
- ex.hand_delta = ex.hand_delta_e.name
- ex.hand_delta_e.length *= 0.5
- ex.hand_delta_e.use_connect = False
- if "hand_roll" in options:
- ex.hand_delta_e.roll += radians(options["hand_roll"])
-
- fk_chain.hand_e.use_connect = False
- fk_chain.hand_e.parent = ex.hand_delta_e
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- mt.update()
- ex.update()
- fk_chain.update()
-
- # Set rotation modes and axis locks
- fk_chain.forearm_p.rotation_mode = 'XYZ'
- fk_chain.forearm_p.lock_rotation = (False, True, True)
- fk_chain.hand_p.rotation_mode = 'ZXY'
- fk_chain.arm_p.lock_location = True, True, True
-
- con = fk_chain.arm_p.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = ex.socket
-
- fk_chain.hand_p.lock_location = True, True, True
- con = ex.hand_delta_p.constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = fk_chain.forearm
-
- def hinge_setup():
- # Hinge constraint & driver
- con = fk_chain.shoulder_p.constraints.new('COPY_ROTATION')
- con.name = "hinge"
- con.target = obj
- con.subtarget = mt.shoulder
- driver_fcurve = con.driver_add("influence")
- driver = driver_fcurve.driver
-
-
- 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)
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
-
- # *****
- driver = driver_fcurve.driver
- driver.type = 'AVERAGE'
-
- var = driver.variables.new()
- var.name = "hinge"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = controller_path + '["hinge"]'
-
- mod = driver_fcurve.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = 1.0
- mod.coefficients[1] = -1.0
-
- hinge_setup()
-
- # last step setup layers
- if "fk_layer" in options:
- layer = [n==options["fk_layer"] for n in range(0,32)]
- else:
- layer = list(mt.arm_b.layers)
- fk_chain.arm_b.layers = layer
- fk_chain.forearm_b.layers = layer
- fk_chain.hand_b.layers = layer
-
- # Forearm was getting wrong roll somehow. Hack to fix that.
- bpy.ops.object.mode_set(mode='EDIT')
- fk_chain.update()
- mt.update()
- fk_chain.forearm_e.roll = mt.forearm_e.roll
- bpy.ops.object.mode_set(mode='OBJECT')
-
- bpy.ops.object.mode_set(mode='EDIT')
- return None, fk_chain.arm, fk_chain.forearm, fk_chain.hand
-
-
-def deform(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- # Create upper arm bones: two bones, each half of the upper arm.
- uarm1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True)
- uarm2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True)
- uarm1.use_connect = False
- uarm2.use_connect = False
- uarm2.parent = uarm1
- center = uarm1.center
- uarm1.tail = center
- uarm2.head = center
-
- # Create forearm bones: two bones, each half of the forearm.
- farm1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True)
- farm2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True)
- farm1.use_connect = False
- farm2.use_connect = False
- farm2.parent = farm1
- center = farm1.center
- farm1.tail = center
- farm2.head = center
-
- # Create twist bone
- twist = copy_bone_simple(obj.data, definitions[2], "MCH-arm_twist")
- twist.use_connect = False
- twist.parent = obj.data.edit_bones[definitions[3]]
- twist.length /= 2
-
- # Create hand bone
- hand = copy_bone_simple(obj.data, definitions[3], "DEF-%s" % base_names[definitions[3]], parent=True)
-
- # Store names before leaving edit mode
- uarm1_name = uarm1.name
- uarm2_name = uarm2.name
- farm1_name = farm1.name
- farm2_name = farm2.name
- twist_name = twist.name
- hand_name = hand.name
-
- # Leave edit mode
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Get the pose bones
- uarm1 = obj.pose.bones[uarm1_name]
- uarm2 = obj.pose.bones[uarm2_name]
- farm1 = obj.pose.bones[farm1_name]
- farm2 = obj.pose.bones[farm2_name]
- twist = obj.pose.bones[twist_name]
- hand = obj.pose.bones[hand_name]
-
- # Upper arm constraints
- con = uarm1.constraints.new('DAMPED_TRACK')
- con.name = "trackto"
- con.target = obj
- con.subtarget = definitions[2]
-
- con = uarm1.constraints.new('COPY_SCALE')
- con.name = "trackto"
- con.target = obj
- con.subtarget = definitions[1]
-
- con = uarm2.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[1]
-
- # Forearm constraints
- con = farm1.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[2]
-
- con = farm1.constraints.new('COPY_SCALE')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[2]
-
- con = farm2.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = twist.name
-
- con = farm2.constraints.new('DAMPED_TRACK')
- con.name = "trackto"
- con.target = obj
- con.subtarget = definitions[3]
-
- # Hand constraint
- con = hand.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[3]
-
- bpy.ops.object.mode_set(mode='EDIT')
- return (uarm1_name, uarm2_name, farm1_name, farm2_name, hand_name)
-
-
-def main(obj, bone_definition, base_names, options):
- bones_fk = fk(obj, bone_definition, base_names, options)
- bones_ik = ik(obj, bone_definition, base_names, options)
- bones_deform = deform(obj, bone_definition, base_names, options)
-
- bpy.ops.object.mode_set(mode='OBJECT')
- blend_bone_list(obj, bone_definition, bones_fk, bones_ik, target_bone=bones_ik[3], target_prop="ik", blend_default=0.0)
diff --git a/release/scripts/modules/rigify/copy.py b/release/scripts/modules/rigify/copy.py
deleted file mode 100644
index c051e5bb7f6..00000000000
--- a/release/scripts/modules/rigify/copy.py
+++ /dev/null
@@ -1,112 +0,0 @@
-# ##### 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_utils import bone_class_instance, copy_bone_simple
-
-METARIG_NAMES = ("cpy",)
-
-
-def metarig_template():
- # 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('Bone')
- bone.head[:] = 0.0000, 0.0000, 0.0000
- bone.tail[:] = 0.0000, 0.0000, 1.0000
- bone.roll = 0.0000
- bone.use_connect = False
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['Bone']
- pbone['type'] = 'copy'
-
-
-def metarig_definition(obj, orig_bone_name):
- return (orig_bone_name,)
-
-
-def deform(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- # Create deform bone.
- bone = copy_bone_simple(obj.data, definitions[0], "DEF-%s" % base_names[definitions[0]], 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
- con = bone.constraints.new('COPY_TRANSFORMS')
- con.name = "copy_loc"
- con.target = obj
- con.subtarget = definitions[0]
-
- return (bone_name,)
-
-
-def control(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- arm = obj.data
- mt = bone_class_instance(obj, METARIG_NAMES)
- mt.cpy = definitions[0]
- mt.update()
- cp = bone_class_instance(obj, ["cpy"])
- cp.cpy_e = copy_bone_simple(arm, mt.cpy, base_names[mt.cpy], parent=True)
- cp.cpy = cp.cpy_e.name
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- cp.update()
- mt.update()
-
- con = mt.cpy_p.constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = cp.cpy
-
-
- # Rotation mode and axis locks
- cp.cpy_p.rotation_mode = mt.cpy_p.rotation_mode
- cp.cpy_p.lock_location = tuple(mt.cpy_p.lock_location)
- cp.cpy_p.lock_rotations_4d = mt.cpy_p.lock_rotations_4d
- cp.cpy_p.lock_rotation = tuple(mt.cpy_p.lock_rotation)
- cp.cpy_p.lock_rotation_w = mt.cpy_p.lock_rotation_w
- cp.cpy_p.lock_scale = tuple(mt.cpy_p.lock_scale)
-
- # Layers
- cp.cpy_b.layers = list(mt.cpy_b.layers)
-
- return (mt.cpy,)
-
-
-def main(obj, bone_definition, base_names, options):
- # Create control bone
- cpy = control(obj, bone_definition, base_names, options)[0]
- # Create deform bone
- deform(obj, bone_definition, base_names, options)
-
- return (cpy,)
diff --git a/release/scripts/modules/rigify/delta.py b/release/scripts/modules/rigify/delta.py
deleted file mode 100644
index d0b4fbccce9..00000000000
--- a/release/scripts/modules/rigify/delta.py
+++ /dev/null
@@ -1,162 +0,0 @@
-# ##### 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
-
-# not used, defined for completeness
-METARIG_NAMES = tuple()
-
-
-def metarig_template():
- # 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('bonesker')
- bone.head[:] = 0.0000, 0.0000, 0.0000
- bone.tail[:] = -0.0000, 0.7382, 0.1895
- bone.roll = -0.0000
- bone.use_connect = False
- bone = arm.edit_bones.new('delta')
- bone.head[:] = -0.0497, 0.8414, 0.3530
- bone.tail[:] = -0.2511, 1.1588, 0.9653
- bone.roll = 2.6044
- bone.use_connect = False
- bone.parent = arm.edit_bones['bonesker']
- bone = arm.edit_bones.new('boney')
- bone.head[:] = 0.7940, 2.5592, 0.4134
- bone.tail[:] = 0.7940, 3.3975, 0.4890
- bone.roll = 3.1416
- bone.use_connect = False
- bone.parent = arm.edit_bones['delta']
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['delta']
- pbone['type'] = 'delta'
-
-
-def metarig_definition(obj, orig_bone_name):
- '''
- The bone given is the head, its parent is the body,
- # its only child the first of a chain with matching basenames.
- eg.
- body -> head -> neck_01 -> neck_02 -> neck_03.... etc
- '''
- arm = obj.data
- delta = arm.bones[orig_bone_name]
- children = delta.children
-
- if len(children) != 1:
- raise RigifyError("only 1 child supported for delta on bone '%s'" % delta.name)
-
- if delta.use_connect:
- raise RigifyError("bone cannot be connected to its parent '%s'" % delta.name)
-
- bone_definition = [delta.name, children[0].name]
-
- return bone_definition
-
-
-def main(obj, bone_definition, base_names, options):
- '''
- Use this bone to define a delta thats applied to its child in pose mode.
- '''
- mode_orig = obj.mode
- bpy.ops.object.mode_set(mode='OBJECT')
-
- delta_name, child_name = bone_definition
-
- delta_pbone = obj.pose.bones[delta_name]
-
- arm = obj.data
- child_pbone = obj.pose.bones[child_name]
-
- delta_phead = delta_pbone.head.copy()
- delta_ptail = delta_pbone.tail.copy()
- delta_pmatrix = delta_pbone.matrix.copy()
-
- child_phead = child_pbone.head.copy()
- child_ptail = child_pbone.tail.copy()
- child_pmatrix = child_pbone.matrix.copy()
-
-
- children = delta_pbone.children
-
- bpy.ops.object.mode_set(mode='EDIT')
-
- delta_ebone = arm.edit_bones[delta_name]
- child_ebone = arm.edit_bones[child_name]
-
- delta_head = delta_ebone.head.copy()
- delta_tail = delta_ebone.tail.copy()
-
- child_head = child_ebone.head.copy()
- child_tail = child_ebone.tail.copy()
-
- #arm.edit_bones.remove(delta_ebone)
- #del delta_ebone # cant use this
- del child_pbone
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
-
- # Move the child bone to the deltas location
- obj.animation_data_create()
- delta_pbone = obj.pose.bones[delta_name]
- # child_pbone = obj.pose.bones[child_name]
-
- # ------------------- drivers
-
- delta_pbone.rotation_mode = 'XYZ'
-
- rot = delta_pmatrix.invert().rotation_part() * child_pmatrix.rotation_part()
- rot = rot.invert().to_euler()
-
- fcurve_drivers = delta_pbone.driver_add("rotation_euler", -1)
- for i, fcurve_driver in enumerate(fcurve_drivers):
- driver = fcurve_driver.driver
- driver.type = 'AVERAGE'
- #mod = fcurve_driver.modifiers.new('GENERATOR')
- mod = fcurve_driver.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = rot[i]
- mod.coefficients[1] = 0.0
-
- # tricky, find the transform to drive the bone to this location.
- delta_head_offset = child_pmatrix.rotation_part() * (delta_phead - child_phead)
-
- fcurve_drivers = delta_pbone.driver_add("location", -1)
- for i, fcurve_driver in enumerate(fcurve_drivers):
- driver = fcurve_driver.driver
- driver.type = 'AVERAGE'
- #mod = fcurve_driver.modifiers.new('GENERATOR')
- mod = fcurve_driver.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = delta_head_offset[i]
- mod.coefficients[1] = 0.0
-
-
- bpy.ops.object.mode_set(mode='EDIT')
-
- bpy.ops.object.mode_set(mode=mode_orig)
-
- # no blendeing
- return None
diff --git a/release/scripts/modules/rigify/eye_balls.py b/release/scripts/modules/rigify/eye_balls.py
deleted file mode 100644
index 127ee87123f..00000000000
--- a/release/scripts/modules/rigify/eye_balls.py
+++ /dev/null
@@ -1,405 +0,0 @@
-# ##### 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 rna_prop_ui import rna_idprop_ui_prop_get
-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 is 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
-
-def get_unmarked_action():
- for action in bpy.data.actions:
- if action.tag != True:
- return action
- return None
-
-def add_action(name=None):
- mark_actions()
- bpy.ops.action.new()
- action = get_unmarked_action()
- if name is not None:
- action.name = name
- return action
-
-
-def metarig_template():
- # 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('Bone')
- bone.head[:] = 0.0000, 0.0000, 0.0000
- bone.tail[:] = 0.0000, 0.0000, 1.0000
- bone.roll = 0.0000
- bone.use_connect = False
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['Bone']
- pbone['type'] = 'copy'
-
-
-def metarig_definition(obj, orig_bone_name):
- bone = obj.data.bones[orig_bone_name]
- chain = []
-
- try:
- chain += [bone.parent.name, bone.name]
- except AttributeError:
- raise RigifyError("'%s' rig type requires a parent (bone: %s)" % (RIG_TYPE, orig_bone_name))
-
- return chain
-
-
-def deform(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- eb = obj.data.edit_bones
- pb = obj.pose.bones
-
- # Get list of eyes
- if "eyes" in options:
- eye_base_names = options["eyes"].replace(" ", "").split(",")
- else:
- eye_base_names = []
-
- # Get their ORG- names
- eyes = []
- for name in eye_base_names:
- eyes += ["ORG-"+name]
-
- # Duplicate the eyes to make deformation bones
- def_eyes = [] # def/org pairs
- for eye in eyes:
- def_eyes += [(copy_bone_simple(obj.data, eye, "DEF-"+base_names[eye], parent=True).name, eye)]
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Constraints
- for eye in def_eyes:
- con = pb[eye[0]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = eye[1]
-
- return (None,)
-
-
-
-
-def control(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- eb = obj.data.edit_bones
- bb = obj.data.bones
- pb = obj.pose.bones
-
- 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(",")
- else:
- eye_base_names = []
-
- # Get their ORG- names
- eyes = []
- for name in eye_base_names:
- eyes += ["ORG-"+name]
-
- # Get the average position of the eyes
- center = Vector((0, 0, 0))
- for eye in eyes:
- center += eb[eye].head
- if len(eyes) != 0:
- center /= len(eyes)
-
- # Get the average length of the eyes
- length = 0.0
- for eye in eyes:
- length += eb[eye].length
- if len(eyes) == 0:
- length = 1.0
- else:
- length /= len(eyes)
-
-
- # Make the mind's eye
- minds_eye = copy_bone_simple(obj.data, eye_target, "MCH-"+base_names[eye_target]+".mind", parent=True).name
- eb[minds_eye].head = center
- eb[minds_eye].tail = eb[eye_target].head
- eb[minds_eye].roll = 0.0
- eb[minds_eye].length = length
-
- # Create org/copy/control eye sets
- eye_sets = []
- for eye in eyes:
- copy = copy_bone_simple(obj.data, minds_eye, "MCH-"+base_names[eye]+".cpy", parent=True).name
- eb[copy].translate(eb[eye].head - eb[copy].head)
- eb[copy].parent = eb[eye].parent
-
- control = copy_bone_simple(obj.data, eye, base_names[eye], parent=True).name
- eb[control].parent = eb[copy]
-
- eye_sets += [(eye, copy, control)]
-
- # Bones for parent/free switch for eye target
- target_ctrl = copy_bone_simple(obj.data, eye_target, base_names[eye_target], parent=True).name
- parent = copy_bone_simple(obj.data, head, "MCH-eye_target_parent", parent=False).name
-
- eb[target_ctrl].parent = eb[parent]
-
-
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Axis locks
- pb[target_ctrl].lock_scale = False, True, True
-
- # Add eye_spread action if it doesn't already exist
- action_name = "eye_spread"
- if action_name in bpy.data.actions:
- spread_action = bpy.data.actions[action_name]
- else:
- spread_action = add_action(name=action_name)
-
- # Add free property
- prop_name = "free"
- prop = rna_idprop_ui_prop_get(pb[target_ctrl], prop_name, create=True)
- pb[target_ctrl][prop_name] = 0.0
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
- prop["min"] = 0.0
- prop["max"] = 1.0
-
- free_driver_path = pb[target_ctrl].path_from_id() + '["free"]'
-
- # Constraints
- # Mind's eye tracks eye target control
- con = pb[minds_eye].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = target_ctrl
-
- # Parent copies transforms of head
- con = pb[parent].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = head
-
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- mod = fcurve.modifiers[0]
- mod.coefficients[0] = 1.0
- mod.coefficients[1] = -1.0
-
- var = driver.variables.new()
- var.name = "free"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = free_driver_path
-
- # Eye set's constraints
- for eye in eye_sets:
- # Org copies transforms of control
- con = pb[eye[0]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = eye[2]
-
- # Copy copies rotation of mind's eye
- con = pb[eye[1]].constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = minds_eye
-
- # Control gets action constraint for eye spread
- con = pb[eye[2]].constraints.new('ACTION')
- con.target = obj
- con.subtarget = target_ctrl
- con.action = spread_action
- con.transform_channel = 'SCALE_X'
- con.frame_start = -20
- con.frame_end = 20
- con.min = 0.0
- con.max = 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)
-
-
-
- # Set layers
- #layer = list(bb[definitions[2]].layers)
- #bb[lid1].layers = layer
- #bb[lid2].layers = layer
- #bb[lid3].layers = layer
- #bb[lid4].layers = layer
- #bb[lid5].layers = layer
- #bb[lid6].layers = layer
- #bb[lid7].layers = layer
- #bb[lid8].layers = layer
-
-
- return (None,)
-
-
-
-
-def main(obj, bone_definition, base_names, options):
- # Create control rig
- control(obj, bone_definition, base_names, options)
- # Create deform rig
- deform(obj, bone_definition, base_names, options)
-
- return (None,)
-
diff --git a/release/scripts/modules/rigify/eye_lid.py b/release/scripts/modules/rigify/eye_lid.py
deleted file mode 100644
index 3f336e268c6..00000000000
--- a/release/scripts/modules/rigify/eye_lid.py
+++ /dev/null
@@ -1,687 +0,0 @@
-# ##### 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 rna_prop_ui import rna_idprop_ui_prop_get
-from math import acos
-from mathutils import Vector
-from rigify import RigifyError
-from rigify_utils import copy_bone_simple
-
-#METARIG_NAMES = ("cpy",)
-RIG_TYPE = "eye_lid"
-
-def mark_actions():
- for action in bpy.data.actions:
- action.tag = True
-
-def get_unmarked_action():
- for action in bpy.data.actions:
- if action.tag != True:
- return action
- return None
-
-def add_action(name=None):
- mark_actions()
- bpy.ops.action.new()
- action = get_unmarked_action()
- if name is not None:
- action.name = name
- return action
-
-
-def metarig_template():
- # 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('Bone')
- bone.head[:] = 0.0000, 0.0000, 0.0000
- bone.tail[:] = 0.0000, 0.0000, 1.0000
- bone.roll = 0.0000
- bone.use_connect = False
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['Bone']
- pbone['type'] = 'copy'
-
-
-def metarig_definition(obj, orig_bone_name):
- bb = obj.data.bones
- bone = bb[orig_bone_name]
- chain = []
-
- try:
- chain += [bone.parent.parent.name, bone.parent.name, bone.name]
- except AttributeError:
- raise RigifyError("'%s' rig type requires a chain of two parents (bone: %s)" % (RIG_TYPE, orig_bone_name))
-
- chain += [child.name for child in bone.children_recursive_basename]
-
- if len(chain) < 10:
- raise RigifyError("'%s' rig type requires a chain of 10 bones (bone: %s)" % (RIG_TYPE, orig_bone_name))
-
- chain = chain[:10]
-
- try:
- chain += [bb[chain[9]].children[0].name]
- chain += [bb[chain[10]].children[0].name]
- except IndexError:
- raise RigifyError("'%s' rig type requires a chain of 10 bones (bone: %s)" % (RIG_TYPE, orig_bone_name))
-
- return chain
-
-
-def deform(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- eb = obj.data.edit_bones
- pb = obj.pose.bones
-
-
- # Upper lid MCH
- lid1 = make_lid_stretch_bone(obj, "MCH-lid", definitions[2], definitions[3], 1.0)
- lid2 = make_lid_stretch_bone(obj, "MCH-lid", definitions[3], definitions[4], 1.0)
- lid22 = make_lid_stretch_bone(obj, "MCH-lid", definitions[4], definitions[5], 1.0)
- lid33 = make_lid_stretch_bone(obj, "MCH-lid", definitions[4], definitions[3], 1.0)
- lid3 = make_lid_stretch_bone(obj, "MCH-lid", definitions[5], definitions[4], 1.0)
- lid4 = make_lid_stretch_bone(obj, "MCH-lid", definitions[6], definitions[5], 1.0)
-
- dlid22 = copy_bone_simple(obj.data, lid22, "MCH-lid", parent=True).name
- dlid33 = copy_bone_simple(obj.data, lid33, "MCH-lid", parent=True).name
- eb[dlid22].bbone_segments = 8
- eb[dlid33].bbone_segments = 8
-
- eb[lid1].parent = eb[definitions[2]]
- eb[lid2].parent = eb[definitions[3]]
- eb[lid22].parent = eb[definitions[4]]
- eb[lid33].parent = eb[definitions[4]]
- eb[lid3].parent = eb[definitions[5]]
- eb[lid4].parent = eb[definitions[6]]
-
- # Lower lid MCH
- lid5 = make_lid_stretch_bone(obj, "MCH-lid", definitions[6], definitions[7], 1.0)
- lid6 = make_lid_stretch_bone(obj, "MCH-lid", definitions[7], definitions[8], 1.0)
- lid66 = make_lid_stretch_bone(obj, "MCH-lid", definitions[8], definitions[9], 1.0)
- lid77 = make_lid_stretch_bone(obj, "MCH-lid", definitions[8], definitions[7], 1.0)
- lid7 = make_lid_stretch_bone(obj, "MCH-lid", definitions[9], definitions[8], 1.0)
- lid8 = make_lid_stretch_bone(obj, "MCH-lid", definitions[2], definitions[9], 1.0)
-
- dlid66 = copy_bone_simple(obj.data, lid66, "MCH-lid", parent=True).name
- dlid77 = copy_bone_simple(obj.data, lid77, "MCH-lid", parent=True).name
- eb[dlid66].bbone_segments = 8
- eb[dlid77].bbone_segments = 8
-
- eb[lid5].parent = eb[definitions[6]]
- eb[lid6].parent = eb[definitions[7]]
- eb[lid66].parent = eb[definitions[8]]
- eb[lid77].parent = eb[definitions[8]]
- eb[lid7].parent = eb[definitions[9]]
- eb[lid8].parent = eb[definitions[2]]
-
- # Upper lid DEF
- dlid1 = copy_bone_simple(obj.data, lid1, "DEF-" + base_names[definitions[2]], parent=True).name
- dlid2 = copy_bone_simple(obj.data, lid2, "DEF-" + base_names[definitions[3]], parent=True).name
- dlid3 = copy_bone_simple(obj.data, lid3, "DEF-" + base_names[definitions[4]], parent=True).name
- dlid4 = copy_bone_simple(obj.data, lid4, "DEF-" + base_names[definitions[5]], parent=True).name
-
- eb[dlid2].parent = eb[dlid1]
- eb[dlid22].parent = eb[dlid2]
-
- eb[dlid3].parent = eb[dlid4]
- eb[dlid33].parent = eb[dlid3]
-
- eb[dlid2].use_connect = True
- eb[dlid22].use_connect = True
- eb[dlid3].use_connect = True
- eb[dlid33].use_connect = True
-
- eb[dlid1].bbone_segments = 8
- eb[dlid2].bbone_segments = 8
- eb[dlid3].bbone_segments = 8
- eb[dlid4].bbone_segments = 8
-
- # Lower lid DEF
- dlid5 = copy_bone_simple(obj.data, lid5, "DEF-" + base_names[definitions[6]], parent=True).name
- dlid6 = copy_bone_simple(obj.data, lid6, "DEF-" + base_names[definitions[7]], parent=True).name
- dlid7 = copy_bone_simple(obj.data, lid7, "DEF-" + base_names[definitions[8]], parent=True).name
- dlid8 = copy_bone_simple(obj.data, lid8, "DEF-" + base_names[definitions[9]], parent=True).name
-
- eb[dlid6].parent = eb[dlid5]
- eb[dlid66].parent = eb[dlid6]
-
- eb[dlid7].parent = eb[dlid8]
- eb[dlid77].parent = eb[dlid7]
-
- eb[dlid6].use_connect = True
- eb[dlid66].use_connect = True
- eb[dlid7].use_connect = True
- eb[dlid77].use_connect = True
-
- eb[dlid5].bbone_segments = 8
- eb[dlid6].bbone_segments = 8
- eb[dlid7].bbone_segments = 8
- eb[dlid8].bbone_segments = 8
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Constraints
- con = pb[dlid1].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid1
-
- con = pb[dlid22].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid22
-
- con = pb[dlid33].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid33
-
- con = pb[dlid2].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid2
-
- con = pb[dlid3].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid3
-
- con = pb[dlid4].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid4
-
- con = pb[dlid5].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid5
-
- con = pb[dlid6].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid6
-
- con = pb[dlid66].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid66
-
- con = pb[dlid77].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid77
-
- con = pb[dlid7].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid7
-
- con = pb[dlid8].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lid8
-
- return (None,)
-
-
-
-
-def control(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- eb = obj.data.edit_bones
- bb = obj.data.bones
- pb = obj.pose.bones
-
- head_e = eb[definitions[0]]
- eye_e = eb[definitions[1]]
-
-
- # Make eye "flower"
- flo1 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[2]]+".flower", parent=True).name
- flo2 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[3]]+".flower", parent=True).name
- flo3 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[4]]+".flower", parent=True).name
- flo4 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[5]]+".flower", parent=True).name
- flo5 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[6]]+".flower", parent=True).name
- flo6 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[7]]+".flower", parent=True).name
- flo7 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[8]]+".flower", parent=True).name
- flo8 = copy_bone_simple(obj.data, definitions[1], "MCH-"+base_names[definitions[9]]+".flower", parent=True).name
-
- eb[flo1].tail = eb[definitions[2]].head
- eb[flo2].tail = eb[definitions[3]].head
- eb[flo3].tail = eb[definitions[4]].head
- eb[flo4].tail = eb[definitions[5]].head
- eb[flo5].tail = eb[definitions[6]].head
- eb[flo6].tail = eb[definitions[7]].head
- eb[flo7].tail = eb[definitions[8]].head
- eb[flo8].tail = eb[definitions[9]].head
-
-
- # Make eye lids on tips of flowers
- flid1 = copy_bone_simple(obj.data, definitions[2], "MCH-"+base_names[definitions[2]]).name
- flid2 = copy_bone_simple(obj.data, definitions[3], "MCH-"+base_names[definitions[3]]).name
- flid3 = copy_bone_simple(obj.data, definitions[4], "MCH-"+base_names[definitions[4]]).name
- flid4 = copy_bone_simple(obj.data, definitions[5], "MCH-"+base_names[definitions[5]]).name
- flid5 = copy_bone_simple(obj.data, definitions[6], "MCH-"+base_names[definitions[6]]).name
- flid6 = copy_bone_simple(obj.data, definitions[7], "MCH-"+base_names[definitions[7]]).name
- flid7 = copy_bone_simple(obj.data, definitions[8], "MCH-"+base_names[definitions[8]]).name
- flid8 = copy_bone_simple(obj.data, definitions[9], "MCH-"+base_names[definitions[9]]).name
-
- eb[flid1].parent = eb[flo1]
- eb[flid2].parent = eb[flo2]
- eb[flid3].parent = eb[flo3]
- eb[flid4].parent = eb[flo4]
- eb[flid5].parent = eb[flo5]
- eb[flid6].parent = eb[flo6]
- eb[flid7].parent = eb[flo7]
- eb[flid8].parent = eb[flo8]
-
-
- # Make eye lid controls
- lid1 = copy_bone_simple(obj.data, definitions[2], base_names[definitions[2]]).name
- lid2 = copy_bone_simple(obj.data, definitions[3], base_names[definitions[3]]).name
- lid3 = copy_bone_simple(obj.data, definitions[4], base_names[definitions[4]]).name
- lid4 = copy_bone_simple(obj.data, definitions[5], base_names[definitions[5]]).name
- lid5 = copy_bone_simple(obj.data, definitions[6], base_names[definitions[6]]).name
- lid6 = copy_bone_simple(obj.data, definitions[7], base_names[definitions[7]]).name
- lid7 = copy_bone_simple(obj.data, definitions[8], base_names[definitions[8]]).name
- lid8 = copy_bone_simple(obj.data, definitions[9], base_names[definitions[9]]).name
-
- size = eb[lid1].length
- 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
- eb[lid3].roll = 0
- eb[lid4].roll = 0
- eb[lid5].roll = 0
- eb[lid6].roll = 0
- eb[lid7].roll = 0
- eb[lid8].roll = 0
-
- eb[lid1].parent = head_e
- eb[lid2].parent = head_e
- eb[lid3].parent = head_e
- eb[lid4].parent = head_e
- eb[lid5].parent = head_e
- eb[lid6].parent = head_e
- eb[lid7].parent = head_e
- eb[lid8].parent = head_e
-
- lower_lid_ctrl = copy_bone_simple(obj.data, definitions[10], base_names[definitions[10]]).name
- upper_lid_ctrl = copy_bone_simple(obj.data, definitions[11], base_names[definitions[11]]).name
- eb[lower_lid_ctrl].parent = head_e
- eb[upper_lid_ctrl].parent = head_e
- distance = (eb[lower_lid_ctrl].head - eb[upper_lid_ctrl].head).length
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Axis locks
- pb[lower_lid_ctrl].lock_location = True, False, True
- pb[upper_lid_ctrl].lock_location = True, False, True
-
- # Add eye close action if it doesn't already exist
- action_name = "eye_close"
- if action_name in bpy.data.actions:
- close_action = bpy.data.actions[action_name]
- else:
- close_action = add_action(name=action_name)
-
- # Add close property (useful when making the animation in the action)
- prop_name = "close_action"
- prop = rna_idprop_ui_prop_get(pb[upper_lid_ctrl], prop_name, create=True)
- pb[upper_lid_ctrl][prop_name] = 1.0
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
- prop["min"] = 0.0
- prop["max"] = 1.0
-
- close_driver_path = pb[upper_lid_ctrl].path_from_id() + '["close_action"]'
-
- # Constraints
-
- # Flowers track lid controls
- con = pb[flo1].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lid1
-
- con = pb[flo2].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lid2
-
- con = pb[flo3].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lid3
-
- con = pb[flo4].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lid4
-
- con = pb[flo5].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lid5
-
- con = pb[flo6].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lid6
-
- con = pb[flo7].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lid7
-
- con = pb[flo8].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lid8
-
-
- # ORG bones to flower lids
- con = pb[definitions[2]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = flid1
-
- con = pb[definitions[3]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = flid2
-
- con = pb[definitions[4]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = flid3
-
- con = pb[definitions[5]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = flid4
-
- con = pb[definitions[6]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = flid5
-
- con = pb[definitions[7]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = flid6
-
- con = pb[definitions[8]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = flid7
-
- con = pb[definitions[9]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = flid8
-
-
- # Action constraints, upper lid
- con = pb[lid1].constraints.new('ACTION')
- con.target = obj
- con.subtarget = upper_lid_ctrl
- con.action = close_action
- con.transform_channel = 'LOCATION_Y'
- con.frame_start = -30
- con.frame_end = 30
- con.min = -distance*2
- con.max = distance
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = close_driver_path
-
-
- con = pb[lid2].constraints.new('ACTION')
- con.target = obj
- con.subtarget = upper_lid_ctrl
- con.action = close_action
- con.transform_channel = 'LOCATION_Y'
- con.frame_start = -30
- con.frame_end = 30
- con.min = -distance*2
- con.max = distance
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = close_driver_path
-
- con = pb[lid3].constraints.new('ACTION')
- con.target = obj
- con.subtarget = upper_lid_ctrl
- con.action = close_action
- con.transform_channel = 'LOCATION_Y'
- con.frame_start = -30
- con.frame_end = 30
- con.min = -distance*2
- con.max = distance
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = close_driver_path
-
- con = pb[lid4].constraints.new('ACTION')
- con.target = obj
- con.subtarget = upper_lid_ctrl
- con.action = close_action
- con.transform_channel = 'LOCATION_Y'
- con.frame_start = -30
- con.frame_end = 30
- con.min = -distance*2
- con.max = distance
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = close_driver_path
-
- con = pb[lid5].constraints.new('ACTION')
- con.target = obj
- con.subtarget = upper_lid_ctrl
- con.action = close_action
- con.transform_channel = 'LOCATION_Y'
- con.frame_start = -30
- con.frame_end = 30
- con.min = -distance*2
- con.max = distance
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = close_driver_path
-
- # Action constraints, lower lid
- con = pb[lid5].constraints.new('ACTION')
- con.target = obj
- con.subtarget = lower_lid_ctrl
- con.action = close_action
- con.transform_channel = 'LOCATION_Y'
- con.frame_start = -30
- con.frame_end = 30
- con.min = -distance
- con.max = distance*2
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = close_driver_path
-
- con = pb[lid6].constraints.new('ACTION')
- con.target = obj
- con.subtarget = lower_lid_ctrl
- con.action = close_action
- con.transform_channel = 'LOCATION_Y'
- con.frame_start = -30
- con.frame_end = 30
- con.min = -distance
- con.max = distance*2
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = close_driver_path
-
- con = pb[lid7].constraints.new('ACTION')
- con.target = obj
- con.subtarget = lower_lid_ctrl
- con.action = close_action
- con.transform_channel = 'LOCATION_Y'
- con.frame_start = -30
- con.frame_end = 30
- con.min = -distance
- con.max = distance*2
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = close_driver_path
-
- con = pb[lid8].constraints.new('ACTION')
- con.target = obj
- con.subtarget = lower_lid_ctrl
- con.action = close_action
- con.transform_channel = 'LOCATION_Y'
- con.frame_start = -30
- con.frame_end = 30
- con.min = -distance
- con.max = distance*2
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = close_driver_path
-
- con = pb[lid1].constraints.new('ACTION')
- con.target = obj
- con.subtarget = lower_lid_ctrl
- con.action = close_action
- con.transform_channel = 'LOCATION_Y'
- con.frame_start = -30
- con.frame_end = 30
- con.min = -distance
- con.max = distance*2
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = close_driver_path
-
-
-
-
- # Set layers
- layer = list(bb[definitions[2]].layers)
- bb[lid1].layers = layer
- bb[lid2].layers = layer
- bb[lid3].layers = layer
- bb[lid4].layers = layer
- bb[lid5].layers = layer
- bb[lid6].layers = layer
- bb[lid7].layers = layer
- bb[lid8].layers = layer
-
-
- return (None,)
-
-
-
-
-def main(obj, bone_definition, base_names, options):
- # Create control rig
- control(obj, bone_definition, base_names, options)
- # Create deform rig
- deform(obj, bone_definition, base_names, options)
-
- return (None,)
-
-
-
-
-def make_lid_stretch_bone(obj, name, bone1, bone2, roll_alpha):
- eb = obj.data.edit_bones
- pb = obj.pose.bones
-
- # Create the bone, pointing from bone1 to bone2
- bone_e = copy_bone_simple(obj.data, bone1, name, parent=True)
- bone_e.use_connect = False
- bone_e.tail = eb[bone2].head
- bone = bone_e.name
-
- # Align the bone roll with the average direction of bone1 and bone2
- vec = bone_e.y_axis.cross(((1.0-roll_alpha)*eb[bone1].y_axis) + (roll_alpha*eb[bone2].y_axis)).normalize()
-
- ang = acos(vec * bone_e.x_axis)
-
- bone_e.roll += ang
- c1 = vec * bone_e.x_axis
- bone_e.roll -= (ang*2)
- c2 = vec * bone_e.x_axis
-
- if c1 > c2:
- bone_e.roll += (ang*2)
-
- bpy.ops.object.mode_set(mode='OBJECT')
- bone_p = pb[bone]
-
- # Constrains
- con = bone_p.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = bone1
-
- con = bone_p.constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = bone2
-
- con = bone_p.constraints.new('STRETCH_TO')
- con.target = obj
- con.subtarget = bone2
- con.volume = 'NO_VOLUME'
-
- bpy.ops.object.mode_set(mode='EDIT')
-
- return bone
diff --git a/release/scripts/modules/rigify/finger_curl.py b/release/scripts/modules/rigify/finger_curl.py
deleted file mode 100644
index 947ec75c9f8..00000000000
--- a/release/scripts/modules/rigify/finger_curl.py
+++ /dev/null
@@ -1,378 +0,0 @@
-# ##### 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 copy_bone_simple, get_side_name
-from rna_prop_ui import rna_idprop_ui_prop_get
-
-METARIG_NAMES = "finger_01", "finger_02", "finger_03"
-
-
-def metarig_template():
- # 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('finger.01')
- bone.head[:] = 0.0000, 0.0000, 0.0000
- bone.tail[:] = 0.0353, -0.0184, -0.0053
- bone.roll = -2.8722
- bone.use_connect = False
- bone = arm.edit_bones.new('finger.02')
- bone.head[:] = 0.0353, -0.0184, -0.0053
- bone.tail[:] = 0.0702, -0.0364, -0.0146
- bone.roll = -2.7099
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger.01']
- bone = arm.edit_bones.new('finger.03')
- bone.head[:] = 0.0702, -0.0364, -0.0146
- bone.tail[:] = 0.0903, -0.0461, -0.0298
- bone.roll = -2.1709
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger.02']
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['finger.01']
- pbone['type'] = 'finger_curl'
-
-
-def metarig_definition(obj, orig_bone_name):
- '''
- The bone given is the first in a chain
- Expects a chain with at least 1 child of the same base name.
- eg.
- finger_01 -> finger_02
- '''
-
- orig_bone = obj.data.bones[orig_bone_name]
-
- 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
-
-
-def deform(obj, definitions, base_names, options):
- """ Creates the deform rig.
- """
- 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)
- f1a.use_connect = False
- f1b.use_connect = False
- f1b.parent = f1a
- center = f1a.center
- f1a.tail = center
- f1b.head = center
-
- # Create the other deform bones.
- f2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s" % base_names[definitions[1]], 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
- if three_digits:
- f3_name = f3.name
-
- # Leave edit mode
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Get the pose bones
- f1a = obj.pose.bones[f1a_name]
- f1b = obj.pose.bones[f1b_name]
- f2 = obj.pose.bones[f2_name]
- if three_digits:
- f3 = obj.pose.bones[f3_name]
-
- # Constrain the base digit's bones
- con = f1a.constraints.new('DAMPED_TRACK')
- con.name = "trackto"
- con.target = obj
- con.subtarget = definitions[1]
-
- con = f1a.constraints.new('COPY_SCALE')
- con.name = "copy_scale"
- con.target = obj
- con.subtarget = definitions[0]
-
- con = f1b.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[0]
-
- # Constrain the other digit's bones
- con = f2.constraints.new('COPY_TRANSFORMS')
- con.name = "copy_transforms"
- con.target = obj
- con.subtarget = definitions[1]
-
- 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
- bb = obj.data.bones
- eb = obj.data.edit_bones
- pb = obj.pose.bones
-
- org_f1 = bone_definition[0] # Original finger bone 01
- org_f2 = bone_definition[1] # Original finger bone 02
- if three_digits:
- org_f3 = bone_definition[2] # Original finger bone 03
-
- # Check options
- if "bend_ratio" in options:
- bend_ratio = options["bend_ratio"]
- else:
- bend_ratio = 0.4
-
- yes = [1, 1.0, True, "True", "true", "Yes", "yes"]
- make_hinge = False
- if ("hinge" in options) and (eb[org_f1].parent is not None):
- if options["hinge"] in yes:
- make_hinge = True
-
-
- # Needed if its a new armature with no keys
- obj.animation_data_create()
-
- # Create the control bone
- base_name = base_names[bone_definition[0]].split(".", 1)[0]
- 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].use_connect = eb[org_f1].use_connect
- eb[control].parent = eb[org_f1].parent
- eb[control].length = tot_len
-
- # 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
- 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
- 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
- if three_digits:
- eb[f3].use_connect = False
- eb[df3].use_connect = False
- eb[f2].use_connect = False
- eb[df2].use_connect = False
- eb[f1].use_connect = False
- eb[df1].use_connect = eb[org_f1].use_connect
-
- 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]
- eb[df1].parent = eb[org_f1].parent
-
- # Set up bones for hinge
- if make_hinge:
- socket = copy_bone_simple(arm, org_f1, "MCH-socket_"+control, parent=True).name
- hinge = copy_bone_simple(arm, eb[org_f1].parent.name, "MCH-hinge_"+control).name
-
- eb[control].use_connect = False
- eb[control].parent = eb[hinge]
-
- # Create the deform rig while we're still in edit mode
- deform(obj, bone_definition, base_names, options)
-
-
- # *** POSEMODE
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Set rotation modes and axis locks
- pb[control].rotation_mode = obj.pose.bones[bone_definition[0]].rotation_mode
- pb[control].lock_location = True, True, True
- pb[control].lock_scale = True, False, True
- pb[f1].rotation_mode = 'YZX'
- pb[f2].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
- if three_digits:
- pb[f3].lock_location = True, True, True
- pb[df2].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
- prop = rna_idprop_ui_prop_get(pb[control], "bend_ratio", create=True)
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- # Add hinge property to the control bone
- if make_hinge:
- pb[control]["hinge"] = 0.0
- prop = rna_idprop_ui_prop_get(pb[control], "hinge", create=True)
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- # Constraints
- con = pb[df1].constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = control
-
- con = pb[df1].constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = control
-
- con = pb[org_f1].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = f1
-
- con = pb[org_f2].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = f2
-
- 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_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
-
- con = pb[control].constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = socket
-
- # Create the drivers for the driver bones (control bone scale rotates driver bones)
- 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 finger_digits:
-
- # XXX - todo, any number
- if i == 2:
- break
-
- pbone = pb[bone]
-
- pbone.rotation_mode = 'YZX'
- fcurve_driver = pbone.driver_add("rotation_euler", 0)
-
- #obj.driver_add('pose.bones["%s"].scale', 1)
- #obj.animation_data.drivers[-1] # XXX, WATCH THIS
- driver = fcurve_driver.driver
-
- # scale target
- var = driver.variables.new()
- var.name = "scale"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = controller_path + '.scale[1]'
-
- # bend target
- var = driver.variables.new()
- var.name = "br"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = controller_path + '["bend_ratio"]'
-
- # XXX - todo, any number
- 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
-
- # 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[0]].layers)
- #for bone_name in [f1, f2, f3]:
- # arm.bones[bone_name].layers = layer
- arm.bones[f1].layers = layer
- arm.bones[f2].layers = layer
- if three_digits:
- arm.bones[f3].layers = layer
-
- layer = list(arm.bones[bone_definition[0]].layers)
- bb[control].layers = 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
deleted file mode 100644
index d2ddba9f549..00000000000
--- a/release/scripts/modules/rigify/leg_biped.py
+++ /dev/null
@@ -1,501 +0,0 @@
-# ##### 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 math import pi
-from rigify import RigifyError
-from rigify_utils import bone_class_instance, copy_bone_simple, blend_bone_list, get_side_name, get_base_name
-from rna_prop_ui import rna_idprop_ui_prop_get
-
-METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe", "heel"
-
-
-def metarig_template():
- # 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('hips')
- bone.head[:] = 0.0000, 0.0000, 0.0000
- bone.tail[:] = 0.0000, 0.0000, 0.2506
- bone.roll = 0.0000
- bone.use_connect = False
- bone = arm.edit_bones.new('thigh')
- bone.head[:] = 0.1253, 0.0000, -0.0000
- bone.tail[:] = 0.0752, -0.0251, -0.4260
- bone.roll = 0.1171
- bone.use_connect = False
- bone.parent = arm.edit_bones['hips']
- bone = arm.edit_bones.new('shin')
- bone.head[:] = 0.0752, -0.0251, -0.4260
- bone.tail[:] = 0.0752, 0.0000, -0.8771
- bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['thigh']
- bone = arm.edit_bones.new('foot')
- bone.head[:] = 0.0752, 0.0000, -0.8771
- bone.tail[:] = 0.1013, -0.1481, -0.9773
- bone.roll = -0.4662
- bone.use_connect = True
- bone.parent = arm.edit_bones['shin']
- bone = arm.edit_bones.new('toe')
- bone.head[:] = 0.1013, -0.1481, -0.9773
- bone.tail[:] = 0.1100, -0.2479, -0.9773
- bone.roll = 3.1416
- bone.use_connect = True
- bone.parent = arm.edit_bones['foot']
- bone = arm.edit_bones.new('heel')
- bone.head[:] = 0.0652, 0.0501, -1.0024
- bone.tail[:] = 0.0927, -0.1002, -1.0024
- bone.roll = 0.0000
- bone.use_connect = False
- bone.parent = arm.edit_bones['foot']
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['thigh']
- pbone['type'] = 'leg_biped'
-
-
-def metarig_definition(obj, orig_bone_name):
- '''
- The bone given is the first in a chain
- Expects a chain of at least 3 children.
- eg.
- thigh -> shin -> foot -> [toe, heel]
- '''
-
- bone_definition = []
-
- orig_bone = obj.data.bones[orig_bone_name]
- orig_bone_parent = orig_bone.parent
-
- if orig_bone_parent is None:
- raise RigifyError("expected the thigh bone to have a parent hip bone")
-
- bone_definition.append(orig_bone_parent.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 thigh bone to have 3 children without a fork")
- bone = children[0]
- bone_definition.append(bone.name) # shin, foot
- chain += 1
-
- children = bone.children
- # Now there must be 2 children, only one connected
- if len(children) != 2:
- raise RigifyError("expected the foot bone:'%s' to have 2 children" % bone.name)
-
- if children[0].use_connect == children[1].use_connect:
- raise RigifyError("expected one bone to be connected")
-
- toe, heel = children
- if heel.use_connect:
- toe, heel = heel, toe
-
-
- bone_definition.append(toe.name)
- bone_definition.append(heel.name)
-
- if len(bone_definition) != len(METARIG_NAMES):
- raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
-
- return bone_definition
-
-
-def ik(obj, bone_definition, base_names, options):
- arm = obj.data
-
- # setup the existing bones, use names from METARIG_NAMES
- mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
- mt = bone_class_instance(obj, ["hips", "heel"])
-
- mt.attr_initialize(METARIG_NAMES, bone_definition)
- mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
-
- # children of ik_foot
- ik = bone_class_instance(obj, ["foot", "foot_roll", "foot_roll_01", "foot_roll_02", "knee_target"])
-
- # Make a new chain
- ik_chain = mt_chain.copy(to_fmt="MCH-%s", base_names=base_names)
-
- # simple rename
- ik_chain.rename("thigh", ik_chain.thigh + "_ik")
- ik_chain.rename("shin", ik_chain.shin + "_ik")
-
- # make sure leg is child of hips
- ik_chain.thigh_e.parent = mt.hips_e
-
- # ik foot: no parents
- base_foot_name = get_base_name(base_names[mt_chain.foot])
- ik.foot_e = copy_bone_simple(arm, mt.heel, base_foot_name + "_ik" + get_side_name(base_names[mt_chain.foot]))
- ik.foot = ik.foot_e.name
- ik.foot_e.translate(mt_chain.foot_e.head - ik.foot_e.head)
- ik.foot_e.use_local_location = False
-
- # foot roll: heel pointing backwards, half length
- ik.foot_roll_e = copy_bone_simple(arm, mt.heel, base_foot_name + "_roll" + get_side_name(base_names[mt_chain.foot]))
- ik.foot_roll = ik.foot_roll_e.name
- ik.foot_roll_e.tail = ik.foot_roll_e.head - ik.foot_roll_e.vector / 2.0
- ik.foot_roll_e.parent = ik.foot_e # heel is disconnected
-
- # heel pointing forwards to the toe base, parent of the following 2 bones
- ik.foot_roll_01_e = copy_bone_simple(arm, mt.heel, "MCH-%s_roll.01" % base_foot_name)
- ik.foot_roll_01 = ik.foot_roll_01_e.name
- ik.foot_roll_01_e.tail = mt_chain.foot_e.tail
- ik.foot_roll_01_e.parent = ik.foot_e # heel is disconnected
-
- # same as above but reverse direction
- ik.foot_roll_02_e = copy_bone_simple(arm, mt.heel, "MCH-%s_roll.02" % base_foot_name)
- ik.foot_roll_02 = ik.foot_roll_02_e.name
- ik.foot_roll_02_e.parent = ik.foot_roll_01_e # heel is disconnected
- ik.foot_roll_02_e.head = mt_chain.foot_e.tail
- ik.foot_roll_02_e.tail = mt.heel_e.head
-
- del base_foot_name
-
- # rename 'MCH-toe' --> to 'toe_ik' and make the child of ik.foot_roll_01
- # ------------------ FK or IK?
- ik_chain.rename("toe", get_base_name(base_names[mt_chain.toe]) + "_ik" + get_side_name(base_names[mt_chain.toe]))
- ik_chain.toe_e.use_connect = False
- ik_chain.toe_e.parent = ik.foot_roll_01_e
-
- # re-parent ik_chain.foot to the
- ik_chain.foot_e.use_connect = False
- ik_chain.foot_e.parent = ik.foot_roll_02_e
-
-
- # knee target is the heel moved up and forward on its local axis
- ik.knee_target_e = copy_bone_simple(arm, mt.heel, "knee_target" + get_side_name(mt.heel))
- ik.knee_target = ik.knee_target_e.name
- offset = ik.knee_target_e.tail - ik.knee_target_e.head
- offset.z = 0
- offset.length = mt_chain.shin_e.head.z - mt.heel_e.head.z
- offset.z += offset.length
- ik.knee_target_e.translate(offset)
- ik.knee_target_e.length *= 0.5
- ik.knee_target_e.parent = ik.foot_e
- ik.knee_target_e.use_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_01_e.align_roll((0.0, 0.0, -1.0))
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- ik.update()
- mt_chain.update()
- ik_chain.update()
-
- # Set IK dof
- ik_chain.shin_p.lock_ik_x = False
- ik_chain.shin_p.lock_ik_y = True
- ik_chain.shin_p.lock_ik_z = True
-
- # Set rotation modes and axis locks
- ik.foot_roll_p.rotation_mode = 'XYZ'
- ik.foot_roll_p.lock_rotation = False, True, True
- ik_chain.toe_p.rotation_mode = 'YXZ'
- ik_chain.toe_p.lock_rotation = False, True, True
- ik_chain.toe_p.lock_location = True, True, True
- ik.foot_roll_p.lock_location = True, True, True
-
- # IK
- con = ik_chain.shin_p.constraints.new('IK')
- con.chain_count = 2
- con.iterations = 500
- con.pole_angle = -pi / 2.0
- con.use_tail = True
- con.use_stretch = True
- con.use_target = True
- con.use_rotation = False
- con.weight = 1.0
-
- con.target = obj
- con.subtarget = ik_chain.foot
-
- con.pole_target = obj
- con.pole_subtarget = ik.knee_target
-
- # foot roll
- cons = [ \
- (ik.foot_roll_01_p.constraints.new('COPY_ROTATION'), ik.foot_roll_01_p.constraints.new('LIMIT_ROTATION')), \
- (ik.foot_roll_02_p.constraints.new('COPY_ROTATION'), ik.foot_roll_02_p.constraints.new('LIMIT_ROTATION'))]
-
- for con, con_l in cons:
- con.target = obj
- con.subtarget = ik.foot_roll
- con.use_x, con.use_y, con.use_z = True, False, False
- con.target_space = con.owner_space = 'LOCAL'
-
- con = con_l
- con.use_limit_x, con.use_limit_y, con.use_limit_z = True, False, False
- con.owner_space = 'LOCAL'
-
- if con_l is cons[-1][-1]:
- con.min_x = 0.0
- con.max_x = 180.0 # XXX -deg
- else:
- con.min_x = -180.0 # XXX -deg
- con.max_x = 0.0
-
-
- # last step setup layers
- if "ik_layer" in options:
- layer = [n == options["ik_layer"] for n in range(0, 32)]
- else:
- layer = list(mt_chain.thigh_b.layers)
- for attr in ik_chain.attr_names:
- getattr(ik_chain, attr + "_b").layers = layer
- for attr in ik.attr_names:
- getattr(ik, attr + "_b").layers = layer
-
- bpy.ops.object.mode_set(mode='EDIT')
-
- return (None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe, None, ik.foot)
-
-
-def fk(obj, bone_definition, base_names, options):
- from mathutils import Vector
- arm = obj.data
-
- # these account for all bones in METARIG_NAMES
- mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
- mt = bone_class_instance(obj, ["hips", "heel"])
-
- # new bones
- ex = bone_class_instance(obj, ["thigh_socket", "thigh_hinge"])
-
- for bone_class in (mt, mt_chain):
- for attr in bone_class.attr_names:
- i = METARIG_NAMES.index(attr)
- ebone = arm.edit_bones[bone_definition[i]]
- setattr(bone_class, attr, ebone.name)
- bone_class.update()
-
- 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_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
-
- fk_chain = mt_chain.copy(base_names=base_names) # fk has no prefix!
- fk_chain.foot_e.name = "MCH-" + fk_chain.foot
- fk_chain.foot = fk_chain.foot_e.name
-
- # Set up fk foot control
- foot_e = copy_bone_simple(arm, mt.heel, base_names[mt_chain.foot])
- foot = foot_e.name
- foot_e.translate(mt_chain.foot_e.head - foot_e.head)
- foot_e.parent = fk_chain.shin_e
- foot_e.use_connect = fk_chain.foot_e.use_connect
- fk_chain.foot_e.use_connect = False
- fk_chain.foot_e.parent = foot_e
-
- fk_chain.thigh_e.use_connect = False
- fk_chain.thigh_e.parent = ex.thigh_hinge_e
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- ex.update()
- mt_chain.update()
- fk_chain.update()
- foot_p = obj.pose.bones[foot]
-
- # Set rotation modes and axis locks
- fk_chain.shin_p.rotation_mode = 'XYZ'
- fk_chain.shin_p.lock_rotation = False, True, True
- foot_p.rotation_mode = 'YXZ'
- fk_chain.toe_p.rotation_mode = 'YXZ'
- fk_chain.toe_p.lock_rotation = False, True, True
- fk_chain.thigh_p.lock_location = True, True, True
-
- con = fk_chain.thigh_p.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = ex.thigh_socket
-
- # hinge
- prop = rna_idprop_ui_prop_get(fk_chain.thigh_p, "hinge", create=True)
- fk_chain.thigh_p["hinge"] = 0.0
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- con = ex.thigh_hinge_p.constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = mt.hips
-
- # add driver
- hinge_driver_path = fk_chain.thigh_p.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
-
-
- # last step setup layers
- if "fk_layer" in options:
- layer = [n == options["fk_layer"] for n in range(0, 32)]
- else:
- layer = list(mt_chain.thigh_b.layers)
- for attr in fk_chain.attr_names:
- getattr(fk_chain, attr + "_b").layers = layer
- for attr in ex.attr_names:
- getattr(ex, attr + "_b").layers = layer
- arm.bones[foot].layers = layer
-
-
- bpy.ops.object.mode_set(mode='EDIT')
-
- # dont blend the hips or heel
- return (None, fk_chain.thigh, fk_chain.shin, fk_chain.foot, fk_chain.toe, None, None)
-
-
-def deform(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- # Create upper leg bones: two bones, each half of the upper leg.
- uleg1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True)
- uleg2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True)
- uleg1.use_connect = False
- uleg2.use_connect = False
- uleg2.parent = uleg1
- center = uleg1.center
- uleg1.tail = center
- uleg2.head = center
-
- # Create lower leg bones: two bones, each half of the lower leg.
- lleg1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True)
- lleg2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True)
- lleg1.use_connect = False
- lleg2.use_connect = False
- lleg2.parent = lleg1
- center = lleg1.center
- lleg1.tail = center
- lleg2.head = center
-
- # Create a bone for the second lower leg deform bone to twist with
- twist = copy_bone_simple(obj.data, lleg2.name, "MCH-leg_twist")
- twist.length /= 4
- twist.use_connect = False
- twist.parent = obj.data.edit_bones[definitions[3]]
-
- # Create foot bone
- foot = copy_bone_simple(obj.data, definitions[3], "DEF-%s" % base_names[definitions[3]], parent=True)
-
- # Create toe bone
- toe = copy_bone_simple(obj.data, definitions[4], "DEF-%s" % base_names[definitions[4]], parent=True)
-
- # Store names before leaving edit mode
- uleg1_name = uleg1.name
- uleg2_name = uleg2.name
- lleg1_name = lleg1.name
- lleg2_name = lleg2.name
- twist_name = twist.name
- foot_name = foot.name
- toe_name = toe.name
-
- # Leave edit mode
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Get the pose bones
- uleg1 = obj.pose.bones[uleg1_name]
- uleg2 = obj.pose.bones[uleg2_name]
- lleg1 = obj.pose.bones[lleg1_name]
- lleg2 = obj.pose.bones[lleg2_name]
- foot = obj.pose.bones[foot_name]
- toe = obj.pose.bones[toe_name]
-
- # Upper leg constraints
- con = uleg1.constraints.new('DAMPED_TRACK')
- con.name = "trackto"
- con.target = obj
- con.subtarget = definitions[2]
-
- con = uleg1.constraints.new('COPY_SCALE')
- con.name = "scale"
- con.target = obj
- con.subtarget = definitions[1]
-
- con = uleg2.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[1]
-
- # Lower leg constraints
- con = lleg1.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[2]
-
- con = lleg1.constraints.new('COPY_SCALE')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[2]
-
- con = lleg2.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = twist_name
-
- con = lleg2.constraints.new('DAMPED_TRACK')
- con.name = "trackto"
- con.target = obj
- con.subtarget = definitions[3]
-
- # Foot constraint
- con = foot.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[3]
-
- # Toe constraint
- con = toe.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[4]
-
- bpy.ops.object.mode_set(mode='EDIT')
- return (uleg1_name, uleg2_name, lleg1_name, lleg2_name, foot_name, toe_name, None)
-
-
-def main(obj, bone_definition, base_names, options):
- bones_fk = fk(obj, bone_definition, base_names, options)
- bones_ik = ik(obj, bone_definition, base_names, options)
- deform(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
deleted file mode 100644
index 739a6402c4b..00000000000
--- a/release/scripts/modules/rigify/leg_quadruped.py
+++ /dev/null
@@ -1,497 +0,0 @@
-# ##### 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 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
-
-METARIG_NAMES = "hips", "thigh", "shin", "foot", "toe"
-
-
-def metarig_template():
- # 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.0728, -0.2427, 0.0000
- bone.tail[:] = -0.0728, -0.2427, 0.2427
- bone.roll = 0.0000
- bone.use_connect = False
- bone = arm.edit_bones.new('thigh')
- bone.head[:] = 0.0000, 0.0000, -0.0000
- bone.tail[:] = 0.0813, -0.2109, -0.3374
- bone.roll = -0.4656
- bone.use_connect = False
- bone.parent = arm.edit_bones['body']
- bone = arm.edit_bones.new('shin')
- bone.head[:] = 0.0813, -0.2109, -0.3374
- bone.tail[:] = 0.0714, -0.0043, -0.5830
- bone.roll = -0.2024
- bone.use_connect = True
- bone.parent = arm.edit_bones['thigh']
- bone = arm.edit_bones.new('foot')
- bone.head[:] = 0.0714, -0.0043, -0.5830
- bone.tail[:] = 0.0929, -0.0484, -0.7652
- bone.roll = -0.3766
- bone.use_connect = True
- bone.parent = arm.edit_bones['shin']
- bone = arm.edit_bones.new('toe')
- bone.head[:] = 0.0929, -0.0484, -0.7652
- bone.tail[:] = 0.1146, -0.1244, -0.7652
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['foot']
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['thigh']
- pbone['type'] = 'leg_quadruped'
-
-
-def metarig_definition(obj, orig_bone_name):
- '''
- The bone given is the first in a chain
- Expects a chain of at least 3 children.
- eg.
- thigh -> shin -> foot -> [toe, heel]
- '''
-
- bone_definition = []
-
- orig_bone = obj.data.bones[orig_bone_name]
- orig_bone_parent = orig_bone.parent
-
- if orig_bone_parent is None:
- raise RigifyError("expected the thigh bone to have a parent hip bone")
-
- bone_definition.append(orig_bone_parent.name)
- bone_definition.append(orig_bone.name)
-
-
- bone = orig_bone
- chain = 0
- while chain < 3: # first 2 bones only have 1 child
- children = bone.children
-
- if len(children) != 1:
- raise RigifyError("expected the thigh bone to have 3 children without a fork")
- bone = children[0]
- bone_definition.append(bone.name) # shin, foot
- chain += 1
-
- if len(bone_definition) != len(METARIG_NAMES):
- raise RigifyError("internal problem, expected %d bones" % len(METARIG_NAMES))
-
- return bone_definition
-
-
-def ik(obj, bone_definition, base_names, options):
- eb = obj.data.edit_bones
- pb = obj.pose.bones
- arm = obj.data
- bpy.ops.object.mode_set(mode='EDIT')
-
- # setup the existing bones, use names from METARIG_NAMES
- mt = bone_class_instance(obj, ["hips"])
- mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
-
- mt.attr_initialize(METARIG_NAMES, bone_definition)
- mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
-
- ik_chain = mt_chain.copy(to_fmt="MCH-%s.ik", base_names=base_names)
-
- ik_chain.thigh_e.use_connect = False
- ik_chain.thigh_e.parent = mt.hips_e
-
- ik_chain.foot_e.parent = None
- ik_chain.rename("foot", get_base_name(base_names[bone_definition[3]]) + "_ik" + get_side_name(base_names[bone_definition[3]]))
- ik_chain.rename("toe", get_base_name(base_names[bone_definition[4]]) + "_ik" + get_side_name(base_names[bone_definition[4]]))
-
- # keep the foot_ik as the parent
- ik_chain.toe_e.use_connect = False
-
- # Foot uses pose space, not local space, for translation
- ik_chain.foot_e.use_local_location = False
-
- # must be after disconnecting the toe
- ik_chain.foot_e.align_orientation(mt_chain.toe_e)
-
- # children of ik_foot
- ik = bone_class_instance(obj, ["foot_roll", "foot_roll_01", "foot_roll_02", "foot_target"])
-
- # knee rotator
- knee_rotator = copy_bone_simple(arm, mt_chain.toe, "knee_rotator" + get_side_name(base_names[mt_chain.foot]), parent=True).name
- eb[knee_rotator].use_connect = False
- eb[knee_rotator].parent = eb[mt.hips]
- eb[knee_rotator].head = eb[ik_chain.thigh].head
- eb[knee_rotator].tail = eb[knee_rotator].head + eb[mt_chain.toe].vector
- eb[knee_rotator].length = eb[ik_chain.thigh].length / 2
- eb[knee_rotator].roll += pi/2
-
- # parent ik leg to the knee rotator
- eb[ik_chain.thigh].parent = eb[knee_rotator]
-
- # foot roll is an interesting one!
- # plot a vector from the toe bones head, bactwards to the length of the foot
- # then align it with the foot but reverse direction.
- ik.foot_roll_e = copy_bone_simple(arm, mt_chain.toe, get_base_name(base_names[mt_chain.foot]) + "_roll" + get_side_name(base_names[mt_chain.foot]))
- ik.foot_roll = ik.foot_roll_e.name
- ik.foot_roll_e.use_connect = False
- 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)))
-
- # MCH-foot
- ik.foot_roll_01_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + base_names[mt_chain.foot])
- ik.foot_roll_01 = ik.foot_roll_01_e.name
- ik.foot_roll_01_e.parent = ik_chain.foot_e
- ik.foot_roll_01_e.head, ik.foot_roll_01_e.tail = mt_chain.foot_e.tail, mt_chain.foot_e.head
- ik.foot_roll_01_e.roll = ik.foot_roll_e.roll
-
- # ik_target, child of MCH-foot
- ik.foot_target_e = copy_bone_simple(arm, mt_chain.foot, "MCH-" + base_names[mt_chain.foot] + "_ik_target")
- ik.foot_target = ik.foot_target_e.name
- ik.foot_target_e.parent = ik.foot_roll_01_e
- ik.foot_target_e.align_orientation(ik_chain.foot_e)
- ik.foot_target_e.length = ik_chain.foot_e.length / 2.0
- ik.foot_target_e.use_connect = True
-
- # MCH-foot.02 child of MCH-foot
- ik.foot_roll_02_e = copy_bone_simple(arm, mt_chain.foot, "MCH-%s_02" % base_names[mt_chain.foot])
- ik.foot_roll_02 = ik.foot_roll_02_e.name
- ik.foot_roll_02_e.parent = ik.foot_roll_01_e
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- mt.update()
- mt_chain.update()
- ik.update()
- ik_chain.update()
-
- # Set rotation modes and axis locks
- #pb[knee_rotator].rotation_mode = 'YXZ'
- #pb[knee_rotator].lock_rotation = False, True, False
- pb[knee_rotator].lock_location = True, True, True
- pb[ik.foot_roll].rotation_mode = 'XYZ'
- pb[ik.foot_roll].lock_rotation = False, True, True
- pb[ik_chain.toe].rotation_mode = 'XYZ'
- pb[ik_chain.toe].lock_rotation = False, True, True
-
- # IK switch property
- prop = rna_idprop_ui_prop_get(pb[ik_chain.foot], "ik", create=True)
- pb[ik_chain.foot]["ik"] = 1.0
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
- prop["min"] = 0.0
- prop["max"] = 1.0
-
- 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")
- 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 = ik_driver_path
-
- con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = ik_chain.shin
- 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 = ik_driver_path
-
- con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = ik.foot_roll_02
- 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 = ik_driver_path
-
- con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = ik_chain.toe
- 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 = ik_driver_path
-
- # others...
- con = ik.foot_roll_01_p.constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = ik.foot_roll
- con.target_space = 'LOCAL'
- con.owner_space = 'LOCAL'
-
-
- # IK
- con = ik_chain.shin_p.constraints.new('IK')
- con.chain_count = 2
- con.iterations = 500
- con.pole_angle = -90.0 # XXX - in deg!
- con.use_tail = True
- con.use_stretch = True
- con.use_target = True
- con.use_rotation = False
- con.weight = 1.0
-
- con.target = obj
- con.subtarget = ik.foot_target
-
- con.pole_target = None
-
- ik.update()
- ik_chain.update()
-
- # Set layers of the bones.
- if "ik_layer" in options:
- layer = [n==options["ik_layer"] for n in range(0,32)]
- else:
- layer = list(mt_chain.thigh_b.layers)
- for attr in ik_chain.attr_names:
- obj.data.bones[getattr(ik_chain, attr)].layers = layer
- for attr in ik.attr_names:
- obj.data.bones[getattr(ik, attr)].layers = layer
- obj.data.bones[knee_rotator].layers = layer
-
- return None, ik_chain.thigh, ik_chain.shin, ik_chain.foot, ik_chain.toe
-
-
-
-def fk(obj, bone_definition, base_names, options):
- eb = obj.data.edit_bones
- pb = obj.pose.bones
- arm = obj.data
- bpy.ops.object.mode_set(mode='EDIT')
-
- # setup the existing bones, use names from METARIG_NAMES
- mt = bone_class_instance(obj, ["hips"])
- mt_chain = bone_class_instance(obj, ["thigh", "shin", "foot", "toe"])
-
- mt.attr_initialize(METARIG_NAMES, bone_definition)
- mt_chain.attr_initialize(METARIG_NAMES, bone_definition)
-
- fk_chain = mt_chain.copy(to_fmt="%s", base_names=base_names)
-
- # Create the socket
- socket = copy_bone_simple(arm, mt_chain.thigh, "MCH-leg_socket").name
- eb[socket].parent = eb[mt.hips]
- eb[socket].length = eb[mt_chain.thigh].length / 4
-
- # Create the hinge
- hinge = copy_bone_simple(arm, mt.hips, "MCH-leg_hinge").name
- eb[hinge].length = eb[mt.hips].length / 2
-
- # Make leg child of hinge
- eb[fk_chain.thigh].use_connect = False
- eb[fk_chain.thigh].parent = eb[hinge]
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Set rotation modes and axis locks
- pb[fk_chain.shin].rotation_mode = 'XYZ'
- pb[fk_chain.shin].lock_rotation = False, True, True
-
- # Constrain original bones to control bones
- con = mt_chain.thigh_p.constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = fk_chain.thigh
-
- con = mt_chain.shin_p.constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = fk_chain.shin
-
- con = mt_chain.foot_p.constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = fk_chain.foot
-
- con = mt_chain.toe_p.constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = fk_chain.toe
-
- # Socket constraint
- con = pb[fk_chain.thigh].constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = socket
-
- # Hinge constraint
- con = pb[hinge].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = mt.hips
-
- prop = rna_idprop_ui_prop_get(pb[fk_chain.thigh], "hinge", create=True)
- pb[fk_chain.thigh]["hinge"] = 0.0
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
- prop["min"] = 0.0
- prop["max"] = 1.0
-
- hinge_driver_path = pb[fk_chain.thigh].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
-
- return None, fk_chain.thigh, fk_chain.shin, fk_chain.foot, fk_chain.toe
-
-
-
-
-def deform(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- # Create upper leg bones: two bones, each half of the upper leg.
- uleg1 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.01" % base_names[definitions[1]], parent=True)
- uleg2 = copy_bone_simple(obj.data, definitions[1], "DEF-%s.02" % base_names[definitions[1]], parent=True)
- uleg1.use_connect = False
- uleg2.use_connect = False
- uleg2.parent = uleg1
- center = uleg1.center
- uleg1.tail = center
- uleg2.head = center
-
- # Create lower leg bones: two bones, each half of the lower leg.
- lleg1 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.01" % base_names[definitions[2]], parent=True)
- lleg2 = copy_bone_simple(obj.data, definitions[2], "DEF-%s.02" % base_names[definitions[2]], parent=True)
- lleg1.use_connect = False
- lleg2.use_connect = False
- lleg2.parent = lleg1
- center = lleg1.center
- lleg1.tail = center
- lleg2.head = center
-
- # Create a bone for the second lower leg deform bone to twist with
- twist = copy_bone_simple(obj.data, lleg2.name, "MCH-leg_twist")
- twist.length /= 4
- twist.use_connect = False
- twist.parent = obj.data.edit_bones[definitions[3]]
-
- # Create foot bone
- foot = copy_bone_simple(obj.data, definitions[3], "DEF-%s" % base_names[definitions[3]], parent=True)
-
- # Create toe bone
- toe = copy_bone_simple(obj.data, definitions[4], "DEF-%s" % base_names[definitions[4]], parent=True)
-
- # Store names before leaving edit mode
- uleg1_name = uleg1.name
- uleg2_name = uleg2.name
- lleg1_name = lleg1.name
- lleg2_name = lleg2.name
- twist_name = twist.name
- foot_name = foot.name
- toe_name = toe.name
-
- # Leave edit mode
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Get the pose bones
- uleg1 = obj.pose.bones[uleg1_name]
- uleg2 = obj.pose.bones[uleg2_name]
- lleg1 = obj.pose.bones[lleg1_name]
- lleg2 = obj.pose.bones[lleg2_name]
- foot = obj.pose.bones[foot_name]
- toe = obj.pose.bones[toe_name]
-
- # Upper leg constraints
- con = uleg1.constraints.new('DAMPED_TRACK')
- con.name = "trackto"
- con.target = obj
- con.subtarget = definitions[2]
-
- con = uleg2.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[1]
-
- # Lower leg constraints
- con = lleg1.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[2]
-
- con = lleg2.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = twist_name
-
- con = lleg2.constraints.new('DAMPED_TRACK')
- con.name = "trackto"
- con.target = obj
- con.subtarget = definitions[3]
-
- # Foot constraint
- con = foot.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[3]
-
- # Toe constraint
- con = toe.constraints.new('COPY_ROTATION')
- con.name = "copy_rot"
- con.target = obj
- con.subtarget = definitions[4]
-
- bpy.ops.object.mode_set(mode='EDIT')
- return (uleg1_name, uleg2_name, lleg1_name, lleg2_name, foot_name, toe_name, None)
-
-
-
-
-def main(obj, bone_definition, base_names, options):
- bones_fk = fk(obj, bone_definition, base_names, options)
- bones_ik = ik(obj, bone_definition, base_names, options)
- deform(obj, bone_definition, base_names, options)
- return bones_ik
diff --git a/release/scripts/modules/rigify/mouth.py b/release/scripts/modules/rigify/mouth.py
deleted file mode 100644
index ef3875222d3..00000000000
--- a/release/scripts/modules/rigify/mouth.py
+++ /dev/null
@@ -1,756 +0,0 @@
-# ##### 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 rna_prop_ui import rna_idprop_ui_prop_get
-from math import acos, pi
-from mathutils import Vector
-from rigify import RigifyError
-from rigify_utils import copy_bone_simple
-
-#METARIG_NAMES = ("cpy",)
-RIG_TYPE = "mouth"
-
-
-def mark_actions():
- for action in bpy.data.actions:
- action.tag = True
-
-def get_unmarked_action():
- for action in bpy.data.actions:
- if action.tag != True:
- return action
- return None
-
-def add_action(name=None):
- mark_actions()
- bpy.ops.action.new()
- action = get_unmarked_action()
- if name is not None:
- action.name = name
- return action
-
-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 is None:
- fcurve = obj.data.shape_keys.keys[name].driver_add("value")
- fcurve.driver.type = 'AVERAGE'
- new = True
-
- return fcurve, new
-
-
-def metarig_template():
- # 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('Bone')
- bone.head[:] = 0.0000, 0.0000, 0.0000
- bone.tail[:] = 0.0000, 0.0000, 1.0000
- bone.roll = 0.0000
- bone.use_connect = False
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['Bone']
- pbone['type'] = 'copy'
-
-
-def metarig_definition(obj, orig_bone_name):
- bone = obj.data.bones[orig_bone_name]
- chain = []
-
- try:
- chain += [bone.parent.parent.name, bone.parent.name, bone.name]
- except AttributeError:
- raise RigifyError("'%s' rig type requires a chain of two parents (bone: %s)" % (RIG_TYPE, orig_bone_name))
-
- chain += [child.name for child in bone.children_recursive_basename]
-
- if len(chain) < 10:
- raise RigifyError("'%s' rig type requires a chain of 8 bones (bone: %s)" % (RIG_TYPE, orig_bone_name))
-
- return chain[:10]
-
-
-def deform(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- eb = obj.data.edit_bones
- bb = obj.data.bones
- pb = obj.pose.bones
-
- jaw = definitions[1]
-
- # Options
- req_options = ["mesh"]
- for option in req_options:
- if option not in options:
- raise RigifyError("'%s' rig type requires a '%s' option (bone: %s)" % (RIG_TYPE, option, base_names[definitions[0]]))
-
- meshes = options["mesh"].replace(" ", "").split(",")
-
- # Lip DEF
- lip1 = copy_bone_simple(obj.data, definitions[2], "DEF-" + base_names[definitions[2]]).name
- lip2 = copy_bone_simple(obj.data, definitions[3], "DEF-" + base_names[definitions[3]]).name
- lip3 = copy_bone_simple(obj.data, definitions[4], "DEF-" + base_names[definitions[4]]).name
- lip4 = copy_bone_simple(obj.data, definitions[5], "DEF-" + base_names[definitions[5]]).name
- lip5 = copy_bone_simple(obj.data, definitions[6], "DEF-" + base_names[definitions[6]]).name
- lip6 = copy_bone_simple(obj.data, definitions[7], "DEF-" + base_names[definitions[7]]).name
- lip7 = copy_bone_simple(obj.data, definitions[8], "DEF-" + base_names[definitions[8]]).name
- lip8 = copy_bone_simple(obj.data, definitions[9], "DEF-" + base_names[definitions[9]]).name
-
- # Mouth corner spread bones (for driving corrective shape keys)
- spread_l_1 = copy_bone_simple(obj.data, definitions[6], "MCH-" + base_names[definitions[6]] + ".spread_1").name
- spread_l_2 = copy_bone_simple(obj.data, definitions[6], "MCH-" + base_names[definitions[6]] + ".spread_2").name
- eb[spread_l_1].tail = eb[definitions[5]].head
- eb[spread_l_2].tail = eb[definitions[5]].head
- eb[spread_l_1].roll = 0
- eb[spread_l_2].roll = 0
- eb[spread_l_1].use_connect = False
- eb[spread_l_2].use_connect = False
- eb[spread_l_1].parent = eb[definitions[6]]
- eb[spread_l_2].parent = eb[definitions[6]]
-
- spread_r_1 = copy_bone_simple(obj.data, definitions[2], "MCH-" + base_names[definitions[2]] + ".spread_1").name
- spread_r_2 = copy_bone_simple(obj.data, definitions[2], "MCH-" + base_names[definitions[2]] + ".spread_2").name
- eb[spread_r_1].tail = eb[definitions[3]].head
- eb[spread_r_2].tail = eb[definitions[3]].head
- eb[spread_r_1].roll = 0
- eb[spread_r_2].roll = 0
- eb[spread_r_1].use_connect = False
- eb[spread_r_2].use_connect = False
- eb[spread_r_1].parent = eb[definitions[2]]
- eb[spread_r_2].parent = eb[definitions[2]]
-
-
-
- # Jaw open bones (for driving corrective shape keys)
- jopen1 = copy_bone_simple(obj.data, jaw, "MCH-"+base_names[jaw]+".track1", parent=True).name
- eb[jopen1].use_connect = False
- eb[jopen1].head = eb[jaw].tail
- 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]
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Constrain DEF bones to ORG bones
- con = pb[lip1].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = definitions[2]
-
- con = pb[lip2].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = definitions[3]
-
- con = pb[lip3].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = definitions[4]
-
- con = pb[lip4].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = definitions[5]
-
- con = pb[lip5].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = definitions[6]
-
- con = pb[lip6].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = definitions[7]
-
- con = pb[lip7].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = definitions[8]
-
- con = pb[lip8].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = definitions[9]
-
- # Constraint mouth corner spread bones
- con = pb[spread_l_1].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lip4
-
- con = pb[spread_l_2].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = spread_l_1
-
- con = pb[spread_l_2].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lip6
-
- con = pb[spread_r_1].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lip2
-
- con = pb[spread_r_2].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = spread_r_1
-
- con = pb[spread_r_2].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = lip8
-
-
- # Corrective shape keys for the corners of the mouth.
- bpy.ops.object.mode_set(mode='EDIT')
-
- # Calculate the rotation difference between the bones
- rotdiff_l = acos((eb[lip5].head - eb[lip4].head).normalize().dot((eb[lip5].head - eb[lip6].head).normalize()))
- rotdiff_r = acos((eb[lip1].head - eb[lip2].head).normalize().dot((eb[lip1].head - eb[lip8].head).normalize()))
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
-
- # Left side shape key
- for mesh_name in meshes:
- mesh_obj = bpy.data.objects[mesh_name]
- shape_key_name = "COR-" + base_names[definitions[6]] + ".spread"
-
- # Add/get the shape key
- shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
-
- # Add/get the shape key driver
- fcurve, is_new_driver = addget_shape_key_driver(mesh_obj, name=shape_key_name)
- driver = fcurve.driver
-
- # Get the variable, or create it if it doesn't already exist
- var_name = base_names[definitions[6]]
- 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 = "ROTATION_DIFF"
- var.targets[0].id = obj
- var.targets[0].bone_target = spread_l_1
- var.targets[1].id = obj
- var.targets[1].bone_target = spread_l_2
-
- # Set fcurve offset
- if is_new_driver:
- mod = fcurve.modifiers[0]
- if rotdiff_l != pi:
- mod.coefficients[0] = -rotdiff_l / (pi-rotdiff_l)
- mod.coefficients[1] = 1 / (pi-rotdiff_l)
-
- # Right side shape key
- for mesh_name in meshes:
- mesh_obj = bpy.data.objects[mesh_name]
- shape_key_name = "COR-" + base_names[definitions[2]] + ".spread"
-
- # Add/get the shape key
- shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
-
- # Add/get the shape key driver
- fcurve, is_new_driver = addget_shape_key_driver(mesh_obj, name=shape_key_name)
- driver = fcurve.driver
-
- # Get the variable, or create it if it doesn't already exist
- var_name = base_names[definitions[2]]
- 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 = "ROTATION_DIFF"
- var.targets[0].id = obj
- var.targets[0].bone_target = spread_r_1
- var.targets[1].id = obj
- var.targets[1].bone_target = spread_r_2
-
- # Set fcurve offset
- if is_new_driver:
- mod = fcurve.modifiers[0]
- if rotdiff_r != pi:
- mod.coefficients[0] = -rotdiff_r / (pi-rotdiff_r)
- mod.coefficients[1] = 1 / (pi-rotdiff_r)
-
- # Jaw open corrective shape key
- for mesh_name in meshes:
- mesh_obj = bpy.data.objects[mesh_name]
- shape_key_name = "COR-" + base_names[definitions[4]] + ".jaw_open"
-
- # Add/get the shape key
- shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
-
- # Add/get the shape key driver
- fcurve, is_new_driver = addget_shape_key_driver(mesh_obj, name=shape_key_name)
- driver = fcurve.driver
-
- # Get the variable, or create it if it doesn't already exist
- var_name = base_names[definitions[4]]
- 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 = "LOC_DIFF"
- var.targets[0].id = obj
- var.targets[0].bone_target = jopen1
- var.targets[1].id = obj
- var.targets[1].bone_target = jopen2
-
- # Set fcurve offset
- if is_new_driver:
- mod = fcurve.modifiers[0]
- mod.coefficients[0] = 0.0
- mod.coefficients[1] = 1.0 / bb[jaw].length
-
- return (None,)
-
-
-
-
-def control(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
-
- eb = obj.data.edit_bones
- bb = obj.data.bones
- pb = obj.pose.bones
-
- head_e = eb[definitions[0]]
- jaw_e = eb[definitions[1]]
- jaw = definitions[1]
-
- # Head lips
- hlip1 = copy_bone_simple(obj.data, definitions[2], "MCH-"+base_names[definitions[2]]+".head").name
- hlip2 = copy_bone_simple(obj.data, definitions[3], "MCH-"+base_names[definitions[3]]+".head").name
- hlip3 = copy_bone_simple(obj.data, definitions[4], "MCH-"+base_names[definitions[4]]+".head").name
- hlip4 = copy_bone_simple(obj.data, definitions[5], "MCH-"+base_names[definitions[5]]+".head").name
- hlip5 = copy_bone_simple(obj.data, definitions[6], "MCH-"+base_names[definitions[6]]+".head").name
- hlip6 = copy_bone_simple(obj.data, definitions[7], "MCH-"+base_names[definitions[7]]+".head").name
- hlip7 = copy_bone_simple(obj.data, definitions[8], "MCH-"+base_names[definitions[8]]+".head").name
- hlip8 = copy_bone_simple(obj.data, definitions[9], "MCH-"+base_names[definitions[9]]+".head").name
-
- eb[hlip1].parent = head_e
- eb[hlip2].parent = head_e
- eb[hlip3].parent = head_e
- eb[hlip4].parent = head_e
- eb[hlip5].parent = head_e
- eb[hlip6].parent = head_e
- eb[hlip7].parent = head_e
- eb[hlip8].parent = head_e
-
- # Jaw lips
- jlip1 = copy_bone_simple(obj.data, definitions[2], "MCH-"+base_names[definitions[2]]+".jaw").name
- jlip2 = copy_bone_simple(obj.data, definitions[3], "MCH-"+base_names[definitions[3]]+".jaw").name
- jlip3 = copy_bone_simple(obj.data, definitions[4], "MCH-"+base_names[definitions[4]]+".jaw").name
- jlip4 = copy_bone_simple(obj.data, definitions[5], "MCH-"+base_names[definitions[5]]+".jaw").name
- jlip5 = copy_bone_simple(obj.data, definitions[6], "MCH-"+base_names[definitions[6]]+".jaw").name
- jlip6 = copy_bone_simple(obj.data, definitions[7], "MCH-"+base_names[definitions[7]]+".jaw").name
- jlip7 = copy_bone_simple(obj.data, definitions[8], "MCH-"+base_names[definitions[8]]+".jaw").name
- jlip8 = copy_bone_simple(obj.data, definitions[9], "MCH-"+base_names[definitions[9]]+".jaw").name
-
- eb[jlip1].parent = jaw_e
- eb[jlip2].parent = jaw_e
- eb[jlip3].parent = jaw_e
- eb[jlip4].parent = jaw_e
- eb[jlip5].parent = jaw_e
- eb[jlip6].parent = jaw_e
- eb[jlip7].parent = jaw_e
- eb[jlip8].parent = jaw_e
-
- # Control lips
- lip1 = copy_bone_simple(obj.data, definitions[2], base_names[definitions[2]]).name
- lip2 = copy_bone_simple(obj.data, definitions[3], base_names[definitions[3]]).name
- lip3 = copy_bone_simple(obj.data, definitions[4], base_names[definitions[4]]).name
- lip4 = copy_bone_simple(obj.data, definitions[5], base_names[definitions[5]]).name
- lip5 = copy_bone_simple(obj.data, definitions[6], base_names[definitions[6]]).name
- lip6 = copy_bone_simple(obj.data, definitions[7], base_names[definitions[7]]).name
- lip7 = copy_bone_simple(obj.data, definitions[8], base_names[definitions[8]]).name
- lip8 = copy_bone_simple(obj.data, definitions[9], base_names[definitions[9]]).name
-
- eb[lip1].parent = eb[hlip1]
- eb[lip2].parent = eb[hlip2]
- eb[lip3].parent = eb[hlip3]
- eb[lip4].parent = eb[hlip4]
- eb[lip5].parent = eb[hlip5]
- eb[lip6].parent = eb[hlip6]
- eb[lip7].parent = eb[hlip7]
- eb[lip8].parent = eb[hlip8]
-
- # Jaw open tracker
- jopent = copy_bone_simple(obj.data, jaw_e.name, "MCH-"+base_names[jaw_e.name]+".track", parent=True).name
- eb[jopent].use_connect = False
- 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')
-
- # Add mouth open action if it doesn't already exist
- action_name = "mouth_open"
- if action_name in bpy.data.actions:
- open_action = bpy.data.actions[action_name]
- else:
- open_action = add_action(name=action_name)
-
- # Add close property (useful when making the animation in the action)
- prop_name = "open_action"
- prop = rna_idprop_ui_prop_get(pb[lip1], prop_name, create=True)
- pb[lip1][prop_name] = 1.0
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
- prop["min"] = 0.0
- prop["max"] = 1.0
-
- open_driver_path = pb[lip1].path_from_id() + '["open_action"]'
-
-
- # Constraints
-
- # Jaw open tracker stretches to jaw tip
- con = pb[jopent].constraints.new('STRETCH_TO')
- con.target = obj
- con.subtarget = jaw
- con.head_tail = 1.0
- con.rest_length = bb[jopent].length
- con.volume = 'NO_VOLUME'
-
- # Head lips to jaw lips
- influence = [0.02, 0.1, 0.35, 0.25, 0.0]
-
- con = pb[hlip1].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = jlip1
- con.influence = influence[2]
-
- con = pb[hlip2].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = jlip2
- con.influence = influence[1]
-
- con = pb[hlip3].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = jlip3
- con.influence = influence[0]
-
- con = pb[hlip4].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = jlip4
- con.influence = influence[1]
-
- con = pb[hlip5].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = jlip5
- con.influence = influence[2]
-
- con = pb[hlip6].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = jlip6
- con.influence = 1.0 - influence[3]
-
- con = pb[hlip7].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = jlip7
- con.influence = 1.0 - influence[4]
-
- con = pb[hlip8].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = jlip8
- con.influence = 1.0 - influence[3]
-
- # ORG bones to lips
- con = pb[definitions[2]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lip1
-
- con = pb[definitions[3]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lip2
-
- con = pb[definitions[4]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lip3
-
- con = pb[definitions[5]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lip4
-
- con = pb[definitions[6]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lip5
-
- con = pb[definitions[7]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lip6
-
- con = pb[definitions[8]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lip7
-
- con = pb[definitions[9]].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = lip8
-
- # Action constraints for open mouth
- con = pb[lip1].constraints.new('ACTION')
- con.target = obj
- con.subtarget = jopent
- con.action = open_action
- con.transform_channel = 'SCALE_Y'
- con.frame_start = 0
- con.frame_end = 60
- con.min = 0.0
- con.max = 1.0
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = open_driver_path
-
- con = pb[lip2].constraints.new('ACTION')
- con.target = obj
- con.subtarget = jopent
- con.action = open_action
- con.transform_channel = 'SCALE_Y'
- con.frame_start = 0
- con.frame_end = 60
- con.min = 0.0
- con.max = 1.0
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = open_driver_path
-
- con = pb[lip3].constraints.new('ACTION')
- con.target = obj
- con.subtarget = jopent
- con.action = open_action
- con.transform_channel = 'SCALE_Y'
- con.frame_start = 0
- con.frame_end = 60
- con.min = 0.0
- con.max = 1.0
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = open_driver_path
-
- con = pb[lip4].constraints.new('ACTION')
- con.target = obj
- con.subtarget = jopent
- con.action = open_action
- con.transform_channel = 'SCALE_Y'
- con.frame_start = 0
- con.frame_end = 60
- con.min = 0.0
- con.max = 1.0
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = open_driver_path
-
- con = pb[lip5].constraints.new('ACTION')
- con.target = obj
- con.subtarget = jopent
- con.action = open_action
- con.transform_channel = 'SCALE_Y'
- con.frame_start = 0
- con.frame_end = 60
- con.min = 0.0
- con.max = 1.0
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = open_driver_path
-
- con = pb[lip6].constraints.new('ACTION')
- con.target = obj
- con.subtarget = jopent
- con.action = open_action
- con.transform_channel = 'SCALE_Y'
- con.frame_start = 0
- con.frame_end = 60
- con.min = 0.0
- con.max = 1.0
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = open_driver_path
-
- con = pb[lip7].constraints.new('ACTION')
- con.target = obj
- con.subtarget = jopent
- con.action = open_action
- con.transform_channel = 'SCALE_Y'
- con.frame_start = 0
- con.frame_end = 60
- con.min = 0.0
- con.max = 1.0
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = open_driver_path
-
- con = pb[lip8].constraints.new('ACTION')
- con.target = obj
- con.subtarget = jopent
- con.action = open_action
- con.transform_channel = 'SCALE_Y'
- con.frame_start = 0
- con.frame_end = 60
- con.min = 0.0
- con.max = 1.0
- con.target_space = 'LOCAL'
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = open_driver_path
-
-
- # Set layers
- layer = list(bb[definitions[2]].layers)
- bb[lip1].layers = layer
- bb[lip2].layers = layer
- bb[lip3].layers = layer
- bb[lip4].layers = layer
- bb[lip5].layers = layer
- bb[lip6].layers = layer
- bb[lip7].layers = layer
- bb[lip8].layers = layer
-
-
- return (None,)
-
-
-
-
-def main(obj, bone_definition, base_names, options):
- # Create control rig
- control(obj, bone_definition, base_names, options)
- # Create deform rig
- deform(obj, bone_definition, base_names, options)
-
- return (None,)
-
-
-
-
-def make_lip_stretch_bone(obj, name, bone1, bone2, roll_alpha):
- eb = obj.data.edit_bones
- pb = obj.pose.bones
-
- # Create the bone, pointing from bone1 to bone2
- bone_e = copy_bone_simple(obj.data, bone1, name, parent=True)
- bone_e.use_connect = False
- bone_e.tail = eb[bone2].head
- bone = bone_e.name
-
- # Align the bone roll with the average direction of bone1 and bone2
- vec = bone_e.y_axis.cross(((1.0-roll_alpha)*eb[bone1].y_axis) + (roll_alpha*eb[bone2].y_axis)).normalize()
-
- ang = acos(vec * bone_e.x_axis)
-
- bone_e.roll += ang
- c1 = vec * bone_e.x_axis
- bone_e.roll -= (ang*2)
- c2 = vec * bone_e.x_axis
-
- if c1 > c2:
- bone_e.roll += (ang*2)
-
- bpy.ops.object.mode_set(mode='OBJECT')
- bone_p = pb[bone]
-
- # Constrains
- con = bone_p.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = bone1
-
- con = bone_p.constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = bone2
-
- con = bone_p.constraints.new('STRETCH_TO')
- con.target = obj
- con.subtarget = bone2
- con.volume = 'NO_VOLUME'
-
- bpy.ops.object.mode_set(mode='EDIT')
-
- return bone
diff --git a/release/scripts/modules/rigify/neck.py b/release/scripts/modules/rigify/neck.py
deleted file mode 100644
index 56717f0ebb0..00000000000
--- a/release/scripts/modules/rigify/neck.py
+++ /dev/null
@@ -1,344 +0,0 @@
-# ##### 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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]].layers)
- for bone in neck:
- bb[bone].layers = layer
-
- layer = list(arm.bones[bone_definition[1]].layers)
- bb[neck_ctrl].layers = layer
- bb[head_ctrl].layers = 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
deleted file mode 100644
index 7daf3d3bb4b..00000000000
--- a/release/scripts/modules/rigify/neck_flex.py
+++ /dev/null
@@ -1,348 +0,0 @@
-# ##### 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():
- # 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = True
- bone.parent = arm.edit_bones['neck.04']
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['head']
- pbone['type'] = 'neck_flex'
-
-
-def metarig_definition(obj, orig_bone_name):
- '''
- The bone given is the head, its parent is the body,
- # its only child the first of a chain with matching basenames.
- eg.
- body -> head -> neck_01 -> neck_02 -> neck_03.... etc
- '''
- arm = obj.data
- head = arm.bones[orig_bone_name]
- body = head.parent
-
- children = head.children
- if len(children) != 1:
- raise RigifyError("expected the head bone '%s' to have only 1 child." % orig_bone_name)
-
- child = children[0]
- bone_definition = [body.name, head.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
-
-
-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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = False
- neck_e.parent = neck_e_parent
- neck_e_parent.use_connect = 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
-
- # 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_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_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_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"]')
- driver = fcurve.driver
- driver.type = 'SUM'
- fcurve.modifiers.remove(fcurve.modifiers[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 constraint
- 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(fcurve.modifiers[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_ROTATION')
- 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]].layers)
- for attr in ex_chain.attr_names:
- getattr(ex_chain, attr + "_b").layers = layer
- for attr in ex.attr_names:
- getattr(ex, attr + "_b").layers = layer
-
- layer = list(arm.bones[bone_definition[1]].layers)
- ex.head_ctrl_b.layers = layer
-
-
- # 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
deleted file mode 100644
index c063e2b31c9..00000000000
--- a/release/scripts/modules/rigify/palm_curl.py
+++ /dev/null
@@ -1,270 +0,0 @@
-# ##### 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_utils import copy_bone_simple, get_side_name
-from rna_prop_ui import rna_idprop_ui_prop_get
-
-# not used, defined for completeness
-METARIG_NAMES = tuple()
-
-
-def metarig_template():
- # 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('hand')
- bone.head[:] = 0.0004, -0.0629, 0.0000
- bone.tail[:] = 0.0021, -0.0209, 0.0000
- bone.roll = 0.0000
- bone.use_connect = False
- bone = arm.edit_bones.new('palm.03')
- bone.head[:] = -0.0000, 0.0000, 0.0000
- bone.tail[:] = 0.0025, 0.0644, -0.0065
- bone.roll = -3.1396
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand']
- bone = arm.edit_bones.new('palm.02')
- bone.head[:] = 0.0252, -0.0000, 0.0000
- bone.tail[:] = 0.0324, 0.0627, -0.0065
- bone.roll = -3.1357
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand']
- bone = arm.edit_bones.new('palm.01')
- bone.head[:] = 0.0504, 0.0000, 0.0000
- bone.tail[:] = 0.0703, 0.0508, -0.0065
- bone.roll = -3.1190
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand']
- bone = arm.edit_bones.new('palm.04')
- bone.head[:] = -0.0252, 0.0000, 0.0000
- bone.tail[:] = -0.0286, 0.0606, -0.0065
- bone.roll = 3.1386
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand']
- bone = arm.edit_bones.new('palm.05')
- bone.head[:] = -0.0504, 0.0000, 0.0000
- bone.tail[:] = -0.0669, 0.0534, -0.0065
- bone.roll = 3.1239
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand']
- bone = arm.edit_bones.new('thumb')
- bone.head[:] = 0.0682, -0.0148, 0.0000
- bone.tail[:] = 0.1063, 0.0242, -0.0065
- bone.roll = -3.0929
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand']
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['palm.01']
- pbone['type'] = 'palm_curl'
-
-
-def metarig_definition(obj, orig_bone_name):
- '''
- The bone given is the first in an array of siblings with a matching basename
- sorted with pointer first, little finger last.
- eg.
- [pointer, middle, ring, pinky... ] # any number of fingers
- '''
- arm = obj.data
-
- palm_bone = arm.bones[orig_bone_name]
- palm_parent = palm_bone.parent
- palm_base = palm_bone.basename
- bone_definition = [bone.name for bone in palm_parent.children if bone.basename == palm_base]
- bone_definition.sort()
- bone_definition.reverse()
-
- return [palm_parent.name] + 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):
- arm = obj.data
-
- children = bone_definition[1:]
-
- # Make a copy of the pinky
- # simply assume the pinky has the lowest name
- pinky_ebone = arm.edit_bones[children[0]]
- ring_ebone = arm.edit_bones[children[1]]
-
- # FIXME, why split the second one?
- base_name = base_names[pinky_ebone.name].rsplit('.', 2)[0]
-
- control_ebone = copy_bone_simple(arm, pinky_ebone.name, base_name + get_side_name(base_names[pinky_ebone.name]), parent=True)
- control_name = control_ebone.name
-
- offset = (pinky_ebone.head - ring_ebone.head)
-
- control_ebone.translate(offset)
-
- deform(obj, bone_definition, base_names, options)
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- arm = obj.data
- control_pbone = obj.pose.bones[control_name]
- pinky_pbone = obj.pose.bones[children[0]]
-
- control_pbone.rotation_mode = 'YZX'
- control_pbone.lock_rotation = False, True, True
- control_pbone.lock_location = True, True, True
-
- driver_fcurves = pinky_pbone.driver_add("rotation_euler")
-
-
- controller_path = control_pbone.path_from_id()
-
- # add custom prop
- control_pbone["spread"] = 0.0
- prop = rna_idprop_ui_prop_get(control_pbone, "spread", create=True)
- prop["soft_min"] = -1.0
- prop["soft_max"] = 1.0
- prop["min"] = -1.0
- prop["max"] = 1.0
-
-
- # *****
- driver = driver_fcurves[0].driver
- driver.type = 'AVERAGE'
-
- var = driver.variables.new()
- var.name = "x"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = controller_path + ".rotation_euler[0]"
-
-
- # *****
- driver = driver_fcurves[1].driver
- driver.expression = "-x/4.0"
-
- var = driver.variables.new()
- var.name = "x"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = controller_path + ".rotation_euler[0]"
-
-
- # *****
- driver = driver_fcurves[2].driver
- driver.expression = "(1.0-cos(x))-s"
-
- for fcurve in driver_fcurves:
- fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier
-
- var = driver.variables.new()
- var.name = "x"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = controller_path + ".rotation_euler[0]"
-
- var = driver.variables.new()
- var.name = "s"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = controller_path + '["spread"]'
-
-
- for i, child_name in enumerate(children):
- child_pbone = obj.pose.bones[child_name]
- child_pbone.rotation_mode = 'YZX'
-
- if child_name != children[-1] and child_name != children[0]:
-
- # this is somewhat arbitrary but seems to look good
- inf = i / (len(children) + 1)
- inf = 1.0 - inf
- inf = ((inf * inf) + inf) / 2.0
-
- # used for X/Y constraint
- inf_minor = inf * inf
-
- con = child_pbone.constraints.new('COPY_ROTATION')
- con.name = "Copy Z Rot"
- con.target = obj
- con.subtarget = children[0] # also pinky_pbone
- con.owner_space = con.target_space = 'LOCAL'
- con.use_x, con.use_y, con.use_z = False, False, True
- con.influence = inf
-
- con = child_pbone.constraints.new('COPY_ROTATION')
- con.name = "Copy XY Rot"
- con.target = obj
- con.subtarget = children[0] # also pinky_pbone
- con.owner_space = con.target_space = 'LOCAL'
- con.use_x, con.use_y, con.use_z = True, True, False
- con.influence = inf_minor
-
-
- child_pbone = obj.pose.bones[children[-1]]
- child_pbone.rotation_mode = 'QUATERNION'
-
- # fix at the end since there is some trouble with tx info not being updated otherwise
- def x_direction():
- # 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 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))
-
- return degrees(rel_vec.angle(x_vec)) > 90.0
-
- if x_direction(): # flip
- driver.expression = "-(%s)" % driver.expression
-
-
- # last step setup layers
- arm.bones[control_name].layers = list(arm.bones[bone_definition[1]].layers)
-
-
- # no blending the result of this
- return None
diff --git a/release/scripts/modules/rigify/shape_key_control.py b/release/scripts/modules/rigify/shape_key_control.py
deleted file mode 100644
index a5f57313ab5..00000000000
--- a/release/scripts/modules/rigify/shape_key_control.py
+++ /dev/null
@@ -1,320 +0,0 @@
-# ##### 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 copy_bone_simple
-from rna_prop_ui import rna_idprop_ui_prop_get
-
-#METARIG_NAMES = ("cpy",)
-RIG_TYPE = "shape_key_control"
-
-
-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 is None:
- fcurve = obj.data.shape_keys.keys[name].driver_add("value")
- fcurve.driver.type = 'AVERAGE'
- new = True
-
- return fcurve, new
-
-
-# TODO:
-def metarig_template():
- # 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('Bone')
- #bone.head[:] = 0.0000, 0.0000, 0.0000
- #bone.tail[:] = 0.0000, 0.0000, 1.0000
- #bone.roll = 0.0000
- #bone.use_connect = False
- #
- #bpy.ops.object.mode_set(mode='OBJECT')
- #pbone = obj.pose.bones['Bone']
- #pbone['type'] = 'copy'
- pass
-
-
-def metarig_definition(obj, orig_bone_name):
- bone = obj.data.bones[orig_bone_name]
- return [bone.name]
-
-
-def main(obj, definitions, base_names, options):
- """ A rig that drives shape keys with the local transforms and/or custom
- properties of a single bone.
- A different shape can be driven by the negative value of a transform as
- well by giving a comma-separated list of two shapes.
-
- Required options:
- mesh: name of mesh object(s) to add/get shapekeys to/from
- (if multiple objects, make a comma-separated list)
- Optional options:
- loc_<x/y/z>: name of the shape key to tie to translation of the bone
- loc_<x/y/z>_fac: default multiplier of the bone influence on the shape key
- rot_<x/y/z>: name of the shape key to tie to rotation of the bone
- rot_<x/y/z>_fac: default multiplier of the bone influence on the shape key
- scale_<x/y/z>: name of the shape key to tie to scale of the bone
- scale_<x/y/z>_fac: default multiplier of the bone influence on the shape key
- shape_key_sliders: comma-separated list of custom properties to create sliders out of for driving shape keys
- <custom_prop>: for each property listed in shape_key_sliders, specify a shape key for it to drive
-
- """
-
- bpy.ops.object.mode_set(mode='EDIT')
- eb = obj.data.edit_bones
- pb = obj.pose.bones
-
- org_bone = definitions[0]
-
- # Options
- req_options = ["mesh"]
- for option in req_options:
- if option not in options:
- raise RigifyError("'%s' rig type requires a '%s' option (bone: %s)" % (RIG_TYPE, option, base_names[definitions[0]]))
-
- meshes = options["mesh"].replace(" ", "").split(",")
-
- bone = copy_bone_simple(obj.data, org_bone, base_names[org_bone], parent=True).name
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Set rotation mode and axis locks
- pb[bone].rotation_mode = pb[org_bone].rotation_mode
- pb[bone].lock_location = tuple(pb[org_bone].lock_location)
- pb[bone].lock_rotation = tuple(pb[org_bone].lock_rotation)
- pb[bone].lock_rotation_w = pb[org_bone].lock_rotation_w
- pb[bone].lock_rotations_4d = pb[org_bone].lock_rotations_4d
- pb[bone].lock_scale = tuple(pb[org_bone].lock_scale)
-
- # List of rig options for specifying shape keys
- # Append '_fac' to the end for the name of the corresponding 'factor
- # default' option for that shape
- shape_key_options = ["loc_x",
- "loc_y",
- "loc_z",
- "rot_x",
- "rot_y",
- "rot_z",
- "scale_x",
- "scale_y",
- "scale_z"]
-
- driver_paths = {"loc_x":".location[0]",
- "loc_y":".location[1]",
- "loc_z":".location[2]",
- "rot_x":".rotation_euler[0]",
- "rot_y":".rotation_euler[1]",
- "rot_z":".rotation_euler[2]",
- "qrot_x":".rotation_quaternion[1]",
- "qrot_y":".rotation_quaternion[2]",
- "qrot_z":".rotation_quaternion[3]",
- "scale_x":".scale[0]",
- "scale_y":".scale[1]",
- "scale_z":".scale[2]"}
-
- # Create the shape keys and drivers for transforms
- shape_info = []
- for option in shape_key_options:
- if option in options:
- shape_names = options[option].replace(" ", "").split(",")
-
- var_name = bone.replace(".","").replace("-","_") + "_" + option
- # Different RNA paths for euler vs quat
- if option in (shape_key_options[3:6]+shape_key_options[12:15]) \
- and pb[bone].rotation_mode == 'QUATERNION':
- var_path = driver_paths['q' + option]
- else:
- var_path = driver_paths[option]
-
- if (option+"_fac") in options:
- fac = options[option+"_fac"]
- else:
- fac = 1.0
-
- # Positive
- if shape_names[0] != "":
- # Different expressions for loc/rot/scale and positive/negative
- if option in shape_key_options[:3]:
- # Location
- expression = var_name + " * " + str(fac)
- elif option in shape_key_options[3:6]:
- # Rotation
- # Different expressions for euler vs quats
- if pb[bone].rotation_mode == 'QUATERNION':
- expression = "2 * asin(" + var_name + ") * " + str(fac)
- else:
- expression = var_name + " * " + str(fac)
- elif option in shape_key_options[6:9]:
- # Scale
- expression = "(1.0 - " + var_name + ") * " + str(fac) + " * -2"
- shape_name = shape_names[0]
- create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression)
-
- # Negative
- if shape_names[0] != "" and len(shape_names) > 1:
- # Different expressions for loc/rot/scale and positive/negative
- if option in shape_key_options[:3]:
- # Location
- expression = var_name + " * " + str(fac) + " * -1"
- elif option in shape_key_options[3:6]:
- # Rotation
- # Different expressions for euler vs quats
- if pb[bone].rotation_mode == 'QUATERNION':
- expression = "-2 * asin(" + var_name + ") * " + str(fac)
- else:
- expression = var_name + " * " + str(fac) + " * -1"
- elif option in shape_key_options[6:9]:
- # Scale
- expression = "(1.0 - " + var_name + ") * " + str(fac) + " * 2"
- shape_name = shape_names[1]
- create_shape_and_driver(obj, bone, meshes, shape_name, var_name, var_path, expression)
-
- # Create the shape keys and drivers for custom-property sliders
- if "shape_key_sliders" in options:
- # Get the slider names
- slider_names = options["shape_key_sliders"].replace(" ", "").split(",")
- if slider_names[0] != "":
- # Loop through the slider names and check if they have
- # shape keys specified for them, and if so, set them up.
- for slider_name in slider_names:
- if slider_name in options:
- shape_names = options[slider_name].replace(" ", "").split(",")
-
- # Set up the custom property on the bone
- prop = rna_idprop_ui_prop_get(pb[bone], slider_name, create=True)
- pb[bone][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, bone, 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, bone, meshes, shape_name, var_name, var_path, expression)
-
-
- # Org bone copy transforms of control bone
- con = pb[org_bone].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = bone
-
- return (None,)
-
-
-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
-
-
diff --git a/release/scripts/modules/rigify/shape_key_distance.py b/release/scripts/modules/rigify/shape_key_distance.py
deleted file mode 100644
index 3045fcdab0d..00000000000
--- a/release/scripts/modules/rigify/shape_key_distance.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# ##### 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
-
-#METARIG_NAMES = ("cpy",)
-RIG_TYPE = "shape_key_distance"
-
-
-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
- 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 is None:
- fcurve = obj.data.shape_keys.keys[name].driver_add("value")
- fcurve.driver.type = 'AVERAGE'
-
- return fcurve
-
-
-
-
-def metarig_template():
- # 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('Bone')
- bone.head[:] = 0.0000, 0.0000, 0.0000
- bone.tail[:] = 0.0000, 0.0000, 1.0000
- bone.roll = 0.0000
- bone.use_connect = False
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['Bone']
- pbone['type'] = 'copy'
-
-
-def metarig_definition(obj, orig_bone_name):
- bone = obj.data.bones[orig_bone_name]
- return [bone.name]
-
-
-def deform(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
- eb = obj.data.edit_bones
-
- bone_from = definitions[0]
-
-
- # Options
- req_options = ["to", "mesh", "shape_key"]
- for option in req_options:
- if option not in options:
- raise RigifyError("'%s' rig type requires a '%s' option (bone: %s)" % (RIG_TYPE, option, base_names[definitions[0]]))
-
- bone_to = "ORG-" + options["to"]
- meshes = options["mesh"].replace(" ", "").split(",")
- shape_key_name = options["shape_key"]
-
- if "dmul" in options:
- shape_blend_fac = options["dmul"]
- else:
- shape_blend_fac = 1.0
-
-
- # Calculate the distance between the bones
- distance = (eb[bone_from].head - eb[bone_to].head).length
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # For every listed mesh object
- for mesh_name in meshes:
- mesh_obj = bpy.data.objects[mesh_name]
-
- # Add/get the shape key
- shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
-
- # Add/get the shape key driver
- fcurve = addget_shape_key_driver(mesh_obj, name=shape_key_name)
- driver = fcurve.driver
-
- # Get the variable, or create it if it doesn't already exist
- var_name = base_names[bone_from]
- 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 = "LOC_DIFF"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].bone_target = bone_from
- var.targets[1].id_type = 'OBJECT'
- var.targets[1].id = obj
- var.targets[1].bone_target = bone_to
-
- # Set fcurve offset, so zero is at the rest distance
-
- mod = fcurve.modifiers[0]
- if distance > 0.00001:
- mod.coefficients[0] = -shape_blend_fac
- mod.coefficients[1] = shape_blend_fac / distance
-
- return (None,)
-
-
-
-
-def control(obj, definitions, base_names, options):
- """ options:
- mesh: name of mesh object with the shape key
- shape_key: name of shape key
- to: name of bone to measure distance from
- """
- pass
-
-
-
-
-def main(obj, bone_definition, base_names, options):
- # Create control rig
- #control(obj, bone_definition, base_names, options)
- # Create deform rig
- deform(obj, bone_definition, base_names, options)
-
- return (None,)
-
diff --git a/release/scripts/modules/rigify/shape_key_rotdiff.py b/release/scripts/modules/rigify/shape_key_rotdiff.py
deleted file mode 100644
index a6ba5adfe6b..00000000000
--- a/release/scripts/modules/rigify/shape_key_rotdiff.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# ##### 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
-
-#METARIG_NAMES = ("cpy",)
-RIG_TYPE = "shape_key_rotdiff"
-
-
-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
- 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 is None:
- fcurve = obj.data.shape_keys.keys[name].driver_add("value")
- fcurve.driver.type = 'AVERAGE'
-
- return fcurve
-
-
-
-
-def metarig_template():
- # 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('Bone')
- bone.head[:] = 0.0000, 0.0000, 0.0000
- bone.tail[:] = 0.0000, 0.0000, 1.0000
- bone.roll = 0.0000
- bone.use_connect = False
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['Bone']
- pbone['type'] = 'copy'
-
-
-def metarig_definition(obj, orig_bone_name):
- bone = obj.data.bones[orig_bone_name]
- return [bone.name]
-
-
-def deform(obj, definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
- eb = obj.data.edit_bones
-
- bone_from = definitions[0]
-
-
- # Options
- req_options = ["to", "mesh", "shape_key"]
- for option in req_options:
- if option not in options:
- raise RigifyError("'%s' rig type requires a '%s' option (bone: %s)" % (RIG_TYPE, option, base_names[definitions[0]]))
-
- bone_to = "ORG-" + options["to"]
- meshes = options["mesh"].replace(" ", "").split(",")
- shape_key_name = options["shape_key"]
-
- if "dmul" in options:
- shape_blend_fac = options["dmul"]
- else:
- shape_blend_fac = 1.0
-
-
- # Calculate the rotation difference between the bones
- rotdiff = (eb[bone_from].matrix.to_quat() * eb[bone_to].matrix.to_quat()) * 2
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # For every listed mesh object
- for mesh_name in meshes:
- mesh_obj = bpy.data.objects[mesh_name]
-
- # Add/get the shape key
- shape_key = addget_shape_key(mesh_obj, name=shape_key_name)
-
- # Add/get the shape key driver
- fcurve = addget_shape_key_driver(mesh_obj, name=shape_key_name)
- driver = fcurve.driver
-
- # Get the variable, or create it if it doesn't already exist
- var_name = base_names[bone_from]
- 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 = "ROTATION_DIFF"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].bone_target = bone_from
- var.targets[1].id_type = 'OBJECT'
- var.targets[1].id = obj
- var.targets[1].bone_target = bone_to
-
- # Set fcurve offset, so zero is at the rest distance
-
- mod = fcurve.modifiers[0]
- if rotdiff > 0.00001:
- mod.coefficients[0] = -shape_blend_fac
- mod.coefficients[1] = shape_blend_fac / rotdiff
-
- return (None,)
-
-
-
-
-def control(obj, definitions, base_names, options):
- """ options:
- mesh: name of mesh object with the shape key
- shape_key: name of shape key
- to: name of bone to measure distance from
- """
- pass
-
-
-
-
-def main(obj, bone_definition, base_names, options):
- # Create control rig
- #control(obj, bone_definition, base_names, options)
- # Create deform rig
- deform(obj, bone_definition, base_names, options)
-
- return (None,)
-
diff --git a/release/scripts/modules/rigify/spine_pivot_flex.py b/release/scripts/modules/rigify/spine_pivot_flex.py
deleted file mode 100644
index 7782380eedb..00000000000
--- a/release/scripts/modules/rigify/spine_pivot_flex.py
+++ /dev/null
@@ -1,481 +0,0 @@
-# ##### 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 = ("pelvis", "ribcage")
-
-
-def metarig_template():
- # 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('pelvis')
- bone.head[:] = 0.0000, -0.0306, 0.1039
- bone.tail[:] = 0.0000, -0.0306, -0.0159
- bone.roll = 0.0000
- bone.use_connect = False
- bone = arm.edit_bones.new('rib_cage')
- bone.head[:] = 0.0000, -0.0306, 0.1039
- bone.tail[:] = 0.0000, -0.0306, 0.2236
- bone.roll = -0.0000
- bone.use_connect = False
- bone.parent = arm.edit_bones['pelvis']
- bone = arm.edit_bones.new('spine.01')
- bone.head[:] = 0.0000, 0.0000, -0.0000
- bone.tail[:] = 0.0000, -0.0306, 0.1039
- bone.roll = -0.0000
- bone.use_connect = False
- bone.parent = arm.edit_bones['rib_cage']
- bone = arm.edit_bones.new('spine.02')
- bone.head[:] = 0.0000, -0.0306, 0.1039
- bone.tail[:] = -0.0000, -0.0398, 0.2045
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['spine.01']
- bone = arm.edit_bones.new('spine.03')
- bone.head[:] = -0.0000, -0.0398, 0.2045
- bone.tail[:] = -0.0000, -0.0094, 0.2893
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['spine.02']
- bone = arm.edit_bones.new('spine.04')
- bone.head[:] = -0.0000, -0.0094, 0.2893
- bone.tail[:] = -0.0000, 0.0335, 0.3595
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['spine.03']
- bone = arm.edit_bones.new('spine.05')
- bone.head[:] = -0.0000, 0.0335, 0.3595
- bone.tail[:] = -0.0000, 0.0555, 0.4327
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['spine.04']
- bone = arm.edit_bones.new('spine.06')
- bone.head[:] = -0.0000, 0.0555, 0.4327
- bone.tail[:] = -0.0000, 0.0440, 0.5207
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['spine.05']
- bone = arm.edit_bones.new('spine.07')
- bone.head[:] = -0.0000, 0.0440, 0.5207
- bone.tail[:] = -0.0000, 0.0021, 0.5992
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['spine.06']
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['rib_cage']
- pbone['type'] = 'spine_pivot_flex'
-
-
-def metarig_definition(obj, orig_bone_name):
- '''
- The bone given is the second in a chain.
- Expects at least 1 parent and a chain of children withe the same basename
- eg.
- pelvis -> rib_cage -> spine.01 -> spine.02 -> spine.03
-
- note: same as neck.
- '''
- arm = obj.data
- ribcage = arm.bones[orig_bone_name]
- pelvis = ribcage.parent
-
- if pelvis is None:
- raise RigifyError("expected the ribcage bone:'%s' to have a parent (ribcage)." % ribcage.name)
-
- children = ribcage.children
- if len(children) != 1:
- raise RigifyError("expected the ribcage to have only 1 child.")
-
- child = children[0]
-
- bone_definition = [pelvis.name, ribcage.name, child.name]
- bone_definition.extend([child.name for child in child.children_recursive_basename])
- return bone_definition
-
-
-def fk(*args):
- main(*args)
-
-
-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
-
-
-def main(obj, bone_definition, base_names, options):
- from mathutils import Vector, Matrix
- from math import radians, pi
-
- arm = obj.data
-
- # Initialize container classes for convenience
- mt = bone_class_instance(obj, ["pelvis", "ribcage"]) # meta
- mt.pelvis = bone_definition[0]
- mt.ribcage = bone_definition[1]
- mt.update()
-
- spine_chain_orig = tuple(bone_definition[2:])
- spine_chain = [arm.edit_bones[child_name] for child_name in spine_chain_orig]
- spine_chain_basename = base_names[spine_chain[0].name].rsplit(".", 1)[0] # probably 'ORG-spine.01' -> 'spine'
- spine_chain_len = len(spine_chain_orig)
-
- child = spine_chain[0]
- spine_chain_segment_length = child.length
- #child.parent = mt.pelvis_e # was mt.ribcage
-
- # The first bone in the chain happens to be the basis of others, create them now
- ex = bone_class_instance(obj, ["pelvis_copy", "ribcage_hinge", "ribcage_copy", "spine_rotate"])
-
- ex.pelvis_copy_e = copy_bone_simple(arm, mt.pelvis, base_names[mt.pelvis]) # no parent
- ex.pelvis_copy = ex.pelvis_copy_e.name
- ex.pelvis_copy_e.use_local_location = False
-
- # 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.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.use_connect = False
- ex.spine_rotate_e.parent = ex.pelvis_copy_e
-
-
- # Copy the last bone now
- child = spine_chain[-1]
-
- ex.ribcage_copy_e = copy_bone_simple(arm, mt.ribcage, base_names[mt.ribcage])
- ex.ribcage_copy = ex.ribcage_copy_e.name
- ex.ribcage_copy_e.use_connect = False
- ex.ribcage_copy_e.parent = ex.ribcage_hinge_e
-
- spine_chain = [child.name for child in spine_chain]
-
- # We have 3 spine chains
- # - original (ORG_*)
- # - copy (*use original name*)
- # - reverse (MCH-rev_*)
- spine_chain_attrs = [("spine_%.2d" % (i + 1)) for i in range(spine_chain_len)]
-
- mt_chain = bone_class_instance(obj, spine_chain_attrs) # ORG_*
- rv_chain = bone_class_instance(obj, spine_chain_attrs) # *
- ex_chain = bone_class_instance(obj, spine_chain_attrs) # MCH-rev_*
- del spine_chain_attrs
-
- for i, child_name in enumerate(spine_chain):
- child_name_orig = base_names[spine_chain_orig[i]]
-
- attr = mt_chain.attr_names[i] # eg. spine_04
-
- setattr(mt_chain, attr, spine_chain_orig[i]) # the original bone
-
- ebone = copy_bone_simple(arm, child_name, child_name_orig) # use the original name
- setattr(ex_chain, attr, ebone.name)
-
- ebone = copy_bone_simple(arm, child_name, "MCH-rev_%s" % child_name_orig)
- setattr(rv_chain, attr, ebone.name)
- ebone.use_connect = False
-
- mt_chain.update()
- ex_chain.update()
- rv_chain.update()
-
- # Now we need to re-parent these chains
- for i, child_name in enumerate(spine_chain_orig):
- attr = ex_chain.attr_names[i] + "_e"
- ebone = getattr(ex_chain, attr)
- if i == 0:
- ebone.use_connect = False
- ebone.parent = ex.pelvis_copy_e
- else:
- attr_parent = ex_chain.attr_names[i - 1] + "_e"
- ebone.parent = getattr(ex_chain, attr_parent)
-
- # intentional! get the parent from the other parallel chain member
- getattr(rv_chain, attr).parent = ebone
-
-
- # ex_chain needs to interlace bones!
- # Note, skip the first bone
- for i in range(1, spine_chain_len): # similar to neck
- child_name_orig = base_names[spine_chain_orig[i]]
- spine_e = getattr(mt_chain, mt_chain.attr_names[i] + "_e")
-
- # dont store parent names, re-reference as each chain bones parent.
- spine_e_parent = arm.edit_bones.new("MCH-rot_%s" % child_name_orig)
- spine_e_parent.head = spine_e.head
- spine_e_parent.tail = spine_e.head + (mt.ribcage_e.vector.normalize() * spine_chain_segment_length / 2.0)
- spine_e_parent.roll = mt.ribcage_e.roll
-
-
- spine_e = getattr(ex_chain, ex_chain.attr_names[i] + "_e")
- orig_parent = spine_e.parent
- spine_e.use_connect = False
- spine_e.parent = spine_e_parent
- spine_e_parent.use_connect = False
-
- spine_e_parent.parent = orig_parent
-
-
- # Rotate the rev chain 180 about the by the first bones center point
- pivot = (rv_chain.spine_01_e.head + rv_chain.spine_01_e.tail) * 0.5
- matrix = Matrix.Rotation(radians(180), 3, 'X')
- for i, attr in enumerate(rv_chain.attr_names): # similar to neck
- spine_e = getattr(rv_chain, attr + "_e")
- # use the first bone as the pivot
-
- spine_e.head = ((spine_e.head - pivot) * matrix) + pivot
- spine_e.tail = ((spine_e.tail - pivot) * matrix) + pivot
- spine_e.roll += pi # 180d roll
- del spine_e
-
- deform(obj, bone_definition, base_names, options)
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # refresh pose bones
- mt.update()
- ex.update()
- mt_chain.update()
- ex_chain.update()
- rv_chain.update()
-
- # Axis locks
- ex.ribcage_copy_p.lock_location = True, True, True
-
- con = ex.ribcage_hinge_p.constraints.new('COPY_ROTATION')
- con.name = "hinge"
- con.target = obj
- con.subtarget = ex.pelvis_copy
-
- # add driver
- 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_from_id() + '["hinge"]'
-
- mod = fcurve.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = 1.0
- mod.coefficients[1] = -1.0
-
- con = ex.spine_rotate_p.constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = ex.ribcage_copy
-
- # ex.pelvis_copy_p / rib_cage
- con = ex.ribcage_copy_p.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = ex.pelvis_copy
- con.head_tail = 0.0
-
- # This stores all important ID props
- prop = rna_idprop_ui_prop_get(ex.ribcage_copy_p, "hinge", create=True)
- ex.ribcage_copy_p["hinge"] = 1.0
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- prop = rna_idprop_ui_prop_get(ex.ribcage_copy_p, "pivot_slide", create=True)
- ex.ribcage_copy_p["pivot_slide"] = 1.0 / spine_chain_len
- prop["soft_min"] = 1.0 / spine_chain_len
- prop["soft_max"] = 1.0
-
-
- # Create a fake connected parent/child relationship with bone location constraints
- # positioned at the tip.
-
- # reverse bones / MCH-rev_spine.##
- for i in range(1, spine_chain_len):
- spine_p = getattr(rv_chain, rv_chain.attr_names[i] + "_p")
- spine_fake_parent_name = getattr(rv_chain, rv_chain.attr_names[i - 1])
-
- con = spine_p.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = spine_fake_parent_name
- con.head_tail = 1.0
- del spine_p, spine_fake_parent_name, con
-
-
- # 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_from_id()
-
- ex.ribcage_copy_p["bend_tot"] = 0.0
- fcurve = ex.ribcage_copy_p.driver_add('["bend_tot"]')
- driver = fcurve.driver
- driver.type = 'SUM'
- fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier
-
- for i in range(spine_chain_len - 1):
- 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 = rib_driver_path + ('["bend_%.2d"]' % (i + 1))
-
- for i in range(1, spine_chain_len):
-
- # Add bend prop
- prop_name = "bend_%.2d" % i
- prop = rna_idprop_ui_prop_get(ex.ribcage_copy_p, prop_name, create=True)
- if ("bend_%.2d" % i) in options:
- ex.ribcage_copy_p[prop_name] = options["bend_%.2d" % i]
- else:
- ex.ribcage_copy_p[prop_name] = 1.0
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- spine_p = getattr(ex_chain, ex_chain.attr_names[i] + "_p")
- spine_p_parent = spine_p.parent # interlaced bone
-
- con = spine_p_parent.constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = ex.spine_rotate
- con.owner_space = 'LOCAL'
- con.target_space = 'LOCAL'
- del spine_p
-
- # add driver
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'SCRIPTED'
- driver.expression = "bend/bend_tot"
-
- fcurve.modifiers.remove(fcurve.modifiers[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 = rib_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 = rib_driver_path + ('["%s"]' % prop_name)
-
-
-
- # original bone drivers
- # note: the first bone has a lot more constraints, but also this simple one is first.
- for i, attr in enumerate(mt_chain.attr_names):
- spine_p = getattr(mt_chain, attr + "_p")
-
- con = spine_p.constraints.new('COPY_ROTATION')
- con.target = obj
- con.subtarget = getattr(ex_chain, attr) # lock to the copy's rotation
- del spine_p
-
- # pivot slide: - lots of copy location constraints.
-
- con = mt_chain.spine_01_p.constraints.new('COPY_LOCATION')
- con.name = "base"
- con.target = obj
- con.subtarget = rv_chain.spine_01 # lock to the reverse location
-
- for i in range(1, spine_chain_len + 1):
- con = mt_chain.spine_01_p.constraints.new('COPY_LOCATION')
- con.name = "slide_%d" % i
- con.target = obj
-
- if i == spine_chain_len:
- attr = mt_chain.attr_names[i - 1]
- else:
- attr = mt_chain.attr_names[i]
-
- con.subtarget = getattr(rv_chain, attr) # lock to the reverse location
-
- if i == spine_chain_len:
- con.head_tail = 1.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 = rib_driver_path + '["pivot_slide"]'
-
- mod = fcurve.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = - (i - 1)
- mod.coefficients[1] = spine_chain_len
-
-
- # Set pelvis and ribcage controls to use the first and last bone in the
- # spine respectively for their custom shape transform
- ex.ribcage_copy_p.custom_shape_transform = obj.pose.bones[bone_definition[len(bone_definition)-1]]
- ex.pelvis_copy_p.custom_shape_transform = obj.pose.bones[bone_definition[2]]
-
-
- # 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]].layers)
- for attr in ex.attr_names:
- getattr(ex, attr + "_b").layers = layer
- for attr in ex_chain.attr_names:
- getattr(ex_chain, attr + "_b").layers = layer
- for attr in rv_chain.attr_names:
- getattr(rv_chain, attr + "_b").layers = layer
-
- layer = list(arm.bones[bone_definition[1]].layers)
- arm.bones[ex.pelvis_copy].layers = layer
- arm.bones[ex.ribcage_copy].layers = layer
-
- # no support for blending chains
- return None
diff --git a/release/scripts/modules/rigify/stretch.py b/release/scripts/modules/rigify/stretch.py
deleted file mode 100644
index 6a498e5aa29..00000000000
--- a/release/scripts/modules/rigify/stretch.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# ##### 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 copy_bone_simple
-
-METARIG_NAMES = tuple()
-RIG_TYPE = "stretch"
-
-# TODO
-#def metarig_template():
-# # 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('Bone')
-# bone.head[:] = 0.0000, 0.0000, 0.0000
-# bone.tail[:] = 0.0000, 0.0000, 1.0000
-# bone.roll = 0.0000
-# bone.use_connect = False
-#
-# bpy.ops.object.mode_set(mode='OBJECT')
-# 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}
-
-
-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).
- """
- # Verify required parameter
- if "to" not in options:
- raise RigifyError("'%s' rig type requires a 'to' parameter (bone: %s)" % (RIG_TYPE, base_names[bone_definition[0]]))
- if type(options["to"]) is not str:
- raise RigifyError("'%s' rig type 'to' parameter must be a string (bone: %s)" % (RIG_TYPE, base_names[bone_definition[0]]))
- if ("ORG-" + options["to"]) not in obj.data.bones:
- raise RigifyError("'%s' rig type 'to' parameter must name a bone in the metarig (bone: %s)" % (RIG_TYPE, base_names[bone_definition[0]]))
-
- preserve_volume = None
- # Check optional parameter
- if "preserve_volume" in options:
- try:
- preserve_volume = bool_map[options["preserve_volume"]]
- except KeyError:
- preserve_volume = False
-
- eb = obj.data.edit_bones
- bb = obj.data.bones
- pb = obj.pose.bones
-
- bpy.ops.object.mode_set(mode='EDIT')
- arm = obj.data
-
- mbone1 = bone_definition[0]
- mbone2 = "ORG-" + options["to"]
-
- bone_e = copy_bone_simple(obj.data, mbone1, "DEF-%s" % base_names[bone_definition[0]])
- bone_e.use_connect = False
- bone_e.parent = eb[mbone1]
- bone_e.tail = eb[mbone2].head
- bone = bone_e.name
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Constraints
- con = pb[bone].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = mbone2
-
- con = pb[bone].constraints.new('STRETCH_TO')
- con.target = obj
- con.subtarget = mbone2
- con.rest_length = bb[bone].length
- if preserve_volume:
- con.volume = 'VOLUME_XZX'
- else:
- con.volume = 'NO_VOLUME'
-
- return tuple()
diff --git a/release/scripts/modules/rigify/stretch_twist.py b/release/scripts/modules/rigify/stretch_twist.py
deleted file mode 100644
index 07ce031967f..00000000000
--- a/release/scripts/modules/rigify/stretch_twist.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# ##### 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 copy_bone_simple
-
-METARIG_NAMES = tuple()
-RIG_TYPE = "stretch_twist"
-
-# TODO
-#def metarig_template():
-# # 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('Bone')
-# bone.head[:] = 0.0000, 0.0000, 0.0000
-# bone.tail[:] = 0.0000, 0.0000, 1.0000
-# bone.roll = 0.0000
-# bone.use_connect = False
-#
-# bpy.ops.object.mode_set(mode='OBJECT')
-# 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}
-
-def metarig_definition(obj, orig_bone_name):
- return (orig_bone_name,)
-
-
-
-
-def main(obj, bone_definition, base_names, options):
- """ A dual-bone stretchy bone setup. Each half follows the twist of the
- bone on its side.
- Deformation only (no controls).
- """
- # Verify required parameter
- if "to" not in options:
- raise RigifyError("'%s' rig type requires a 'to' parameter (bone: %s)" % (RIG_TYPE, base_names[0]))
- if type(options["to"]) is not str:
- raise RigifyError("'%s' rig type 'to' parameter must be a string (bone: %s)" % (RIG_TYPE, base_names[0]))
- if ("ORG-" + options["to"]) not in obj.data.bones:
- raise RigifyError("'%s' rig type 'to' parameter must name a bone in the metarig (bone: %s)" % (RIG_TYPE, base_names[0]))
-
- preserve_volume = None
- # Check optional parameter
- if "preserve_volume" in options:
- try:
- preserve_volume = bool_map[options["preserve_volume"]]
- except KeyError:
- preserve_volume = False
-
- eb = obj.data.edit_bones
- bb = obj.data.bones
- pb = obj.pose.bones
-
- bpy.ops.object.mode_set(mode='EDIT')
- arm = obj.data
-
- mbone1 = bone_definition[0]
- mbone2 = "ORG-" + options["to"]
-
- bone_e = copy_bone_simple(obj.data, mbone1, "MCH-%s" % base_names[bone_definition[0]])
- bone_e.use_connect = False
- bone_e.parent = None
- bone_e.head = (eb[mbone1].head + eb[mbone2].head) / 2
- bone_e.tail = (bone_e.head[0], bone_e.head[1], bone_e.head[2]+0.1)
- mid_bone = bone_e.name
-
- bone_e = copy_bone_simple(obj.data, mbone1, "DEF-%s.01" % base_names[bone_definition[0]])
- bone_e.use_connect = False
- bone_e.parent = eb[mbone1]
- bone_e.tail = eb[mid_bone].head
- bone1 = bone_e.name
-
- bone_e = copy_bone_simple(obj.data, mbone2, "DEF-%s.02" % base_names[bone_definition[0]])
- bone_e.use_connect = False
- bone_e.parent = eb[mbone2]
- bone_e.tail = eb[mid_bone].head
- bone2 = bone_e.name
-
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Constraints
-
- # Mid bone
- con = pb[mid_bone].constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = mbone1
-
- con = pb[mid_bone].constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = mbone2
- con.influence = 0.5
-
- # Bone 1
- con = pb[bone1].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = mid_bone
-
- con = pb[bone1].constraints.new('STRETCH_TO')
- con.target = obj
- con.subtarget = mid_bone
- con.rest_length = bb[bone1].length
- if preserve_volume:
- con.volume = 'VOLUME_XZX'
- else:
- con.volume = 'NO_VOLUME'
-
- # Bone 2
- con = pb[bone2].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = mid_bone
-
- con = pb[bone2].constraints.new('STRETCH_TO')
- con.target = obj
- con.subtarget = mid_bone
- con.rest_length = bb[bone2].length
- if preserve_volume:
- con.volume = 'VOLUME_XZX'
- else:
- con.volume = 'NO_VOLUME'
-
- return tuple()
-
diff --git a/release/scripts/modules/rigify/tail_control.py b/release/scripts/modules/rigify/tail_control.py
deleted file mode 100644
index 32d414344cf..00000000000
--- a/release/scripts/modules/rigify/tail_control.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# ##### 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
-from mathutils import Vector, Matrix
-from math import radians, pi
-
-# not used, defined for completeness
-METARIG_NAMES = ("pelvis", "ribcage")
-
-
-def metarig_template():
- # TODO
- pass
- # 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('tail.01')
- #bone.head[:] = 0.0000, -0.0306, 0.1039
- #bone.tail[:] = 0.0000, -0.0306, -0.0159
- #bone.roll = 0.0000
- #bone.use_connect = False
-
- #bpy.ops.object.mode_set(mode='OBJECT')
- #pbone = obj.pose.bones['tail.01']
- #pbone['type'] = 'tail_spline_ik'
-
-
-def metarig_definition(obj, orig_bone_name):
- """ Collects and returns the relevent bones for the rig.
- The bone given is the first in the chain of tail bones.
- It includes bones in the chain up until it hits a bone that doesn't
- have the same name base.
-
- tail.01 -> tail.02 -> tail.03 -> ... -> tail.n
- """
- arm = obj.data
- tail_base = arm.bones[orig_bone_name]
-
- if tail_base.parent is None:
- raise RigifyError("'tail_control' rig type on bone '%s' requires a parent." % orig_bone_name)
-
- bone_definitions = [tail_base.name]
- bone_definitions.extend([child.name for child in tail_base.children_recursive_basename])
- return bone_definitions
-
-
-def main(obj, bone_definitions, base_names, options):
- bpy.ops.object.mode_set(mode='EDIT')
- arm = obj.data
- bb = obj.data.bones
- eb = obj.data.edit_bones
- pb = obj.pose.bones
-
- # Create bones for hinge/free
- # hinge 1 sticks with the parent
- # hinge 2 is the parent of the tail controls
- hinge1 = copy_bone_simple(arm, bone_definitions[0], "MCH-%s.hinge1" % base_names[bone_definitions[0]], parent=True).name
- hinge2 = copy_bone_simple(arm, bone_definitions[0], "MCH-%s.hinge2" % base_names[bone_definitions[0]], parent=False).name
-
- # Create tail control bones
- bones = []
- i = 0
- for bone_def in bone_definitions:
- bone = copy_bone_simple(arm, bone_def, base_names[bone_def], parent=True).name
- if i == 1: # Don't change parent of first tail bone
- eb[bone].use_connect = False
- eb[bone].parent = eb[hinge2]
- eb[bone].use_local_location = False
- i = 1
- bones += [bone]
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Rotation mode and axis locks
- for bone, org_bone in zip(bones, bone_definitions):
- pb[bone].rotation_mode = pb[org_bone].rotation_mode
- pb[bone].lock_location = tuple(pb[org_bone].lock_location)
- pb[bone].lock_rotations_4d = pb[org_bone].lock_rotations_4d
- pb[bone].lock_rotation = tuple(pb[org_bone].lock_rotation)
- pb[bone].lock_rotation_w = pb[org_bone].lock_rotation_w
- pb[bone].lock_scale = tuple(pb[org_bone].lock_scale)
-
- # Add custom properties
- pb[bones[0]]["hinge"] = 0.0
- prop = rna_idprop_ui_prop_get(pb[bones[0]], "hinge", create=True)
- prop["min"] = 0.0
- prop["max"] = 1.0
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- pb[bones[0]]["free"] = 0.0
- prop = rna_idprop_ui_prop_get(pb[bones[0]], "free", create=True)
- prop["min"] = 0.0
- prop["max"] = 1.0
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- # Add constraints
- for bone, org_bone in zip(bones, bone_definitions):
- con = pb[org_bone].constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = bone
-
- con_f = pb[hinge2].constraints.new('COPY_LOCATION')
- con_f.target = obj
- con_f.subtarget = hinge1
-
- con_h = pb[hinge2].constraints.new('COPY_TRANSFORMS')
- con_h.target = obj
- con_h.subtarget = hinge1
-
- # Add drivers
- bone_path = pb[bones[0]].path_from_id()
-
- driver_fcurve = con_f.driver_add("influence")
- driver = driver_fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.name = "free"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = bone_path + '["free"]'
- mod = driver_fcurve.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = 1.0
- mod.coefficients[1] = -1.0
-
- driver_fcurve = con_h.driver_add("influence")
- driver = driver_fcurve.driver
- driver.type = 'AVERAGE'
- var = driver.variables.new()
- var.name = "hinge"
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = bone_path + '["hinge"]'
- mod = driver_fcurve.modifiers[0]
- mod.poly_order = 1
- mod.coefficients[0] = 1.0
- mod.coefficients[1] = -1.0
-
-
- return None
diff --git a/release/scripts/modules/rigify/tongue.py b/release/scripts/modules/rigify/tongue.py
deleted file mode 100644
index 36c4316adc5..00000000000
--- a/release/scripts/modules/rigify/tongue.py
+++ /dev/null
@@ -1,361 +0,0 @@
-# ##### 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = 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.use_connect = False
- neck_e.parent = neck_e_parent
- neck_e_parent.use_connect = 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(fcurve.modifiers[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(fcurve.modifiers[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]].layers)
- for attr in ex_chain.attr_names:
- getattr(ex_chain, attr + "_b").layers = layer
- for attr in ex.attr_names:
- getattr(ex, attr + "_b").layers = layer
-
- layer = list(arm.bones[bone_definition[1]].layers)
- ex.head_ctrl_b.layers = 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
deleted file mode 100644
index f9c48a3bfcb..00000000000
--- a/release/scripts/modules/rigify/track_dual.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# ##### 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 copy_bone_simple
-
-METARIG_NAMES = tuple()
-RIG_TYPE = "track_dual"
-
-# TODO
-#def metarig_template():
-# # 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('Bone')
-# bone.head[:] = 0.0000, 0.0000, 0.0000
-# bone.tail[:] = 0.0000, 0.0000, 1.0000
-# bone.roll = 0.0000
-# bone.use_connect = False
-#
-# bpy.ops.object.mode_set(mode='OBJECT')
-# 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}
-
-
-def metarig_definition(obj, orig_bone_name):
- return (orig_bone_name,)
-
-
-def main(obj, bone_definition, base_names, options):
- """ A dual-bone track setup.
- Deformation only (no controls).
- """
- # Verify required parameter
- if "to" not in options:
- raise RigifyError("'%s' rig type requires a 'to' parameter (bone: %s)" % (RIG_TYPE, base_names[0]))
- if type(options["to"]) is not str:
- raise RigifyError("'%s' rig type 'to' parameter must be a string (bone: %s)" % (RIG_TYPE, base_names[0]))
- if ("ORG-" + options["to"]) not in obj.data.bones:
- raise RigifyError("'%s' rig type 'to' parameter must name a bone in the metarig (bone: %s)" % (RIG_TYPE, base_names[0]))
-
- eb = obj.data.edit_bones
- bb = obj.data.bones
- pb = obj.pose.bones
-
- bpy.ops.object.mode_set(mode='EDIT')
- arm = obj.data
-
- mbone1 = bone_definition[0]
- mbone2 = "ORG-" + options["to"]
-
- bone_e = copy_bone_simple(obj.data, mbone1, "DEF-%s.01" % base_names[bone_definition[0]])
- bone_e.use_connect = False
- bone_e.parent = eb[mbone1]
- bone_e.tail = (eb[mbone1].head + eb[mbone2].head) / 2
- bone1 = bone_e.name
-
- bone_e = copy_bone_simple(obj.data, mbone2, "DEF-%s.02" % base_names[bone_definition[0]])
- bone_e.use_connect = False
- bone_e.parent = eb[mbone1]
- bone_e.tail = (eb[mbone1].head + eb[mbone2].head) / 2
- bone2 = bone_e.name
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Constraints
- # Bone 1
- con = pb[bone1].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = mbone2
-
-
- # Bone 2
- con = pb[bone2].constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = mbone2
-
- con = pb[bone2].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = mbone1
-
-
- return tuple()
diff --git a/release/scripts/modules/rigify/track_reverse.py b/release/scripts/modules/rigify/track_reverse.py
deleted file mode 100644
index a65ac0e9416..00000000000
--- a/release/scripts/modules/rigify/track_reverse.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# ##### 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 copy_bone_simple
-
-METARIG_NAMES = tuple()
-RIG_TYPE = "track_reverse"
-
-# TODO
-#def metarig_template():
-# # 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('Bone')
-# bone.head[:] = 0.0000, 0.0000, 0.0000
-# bone.tail[:] = 0.0000, 0.0000, 1.0000
-# bone.roll = 0.0000
-# bone.use_connect = False
-#
-# bpy.ops.object.mode_set(mode='OBJECT')
-# 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}
-
-def metarig_definition(obj, orig_bone_name):
- return (orig_bone_name,)
-
-
-
-
-def main(obj, bone_definition, base_names, options):
- """ A bone that tracks bakwards towards its parent, while copying the
- location of it's target.
- Deformation only (no controls).
- """
- # Verify required parameter
- if "to" not in options:
- raise RigifyError("'%s' rig type requires a 'to' parameter (bone: %s)" % (RIG_TYPE, base_names[0]))
- if type(options["to"]) is not str:
- raise RigifyError("'%s' rig type 'to' parameter must be a string (bone: %s)" % (RIG_TYPE, base_names[0]))
- if ("ORG-" + options["to"]) not in obj.data.bones:
- raise RigifyError("'%s' rig type 'to' parameter must name a bone in the metarig (bone: %s)" % (RIG_TYPE, base_names[0]))
-
- eb = obj.data.edit_bones
- bb = obj.data.bones
- pb = obj.pose.bones
-
- bpy.ops.object.mode_set(mode='EDIT')
- arm = obj.data
-
- mbone1 = bone_definition[0]
- mbone2 = "ORG-" + options["to"]
-
- bone_e = copy_bone_simple(obj.data, mbone2, "DEF-%s.02" % base_names[bone_definition[0]])
- bone_e.use_connect = False
- bone_e.parent = eb[mbone1]
- bone_e.tail = eb[mbone1].head
- bone = bone_e.name
-
-
-
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Constraints
- con = pb[bone].constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = mbone2
-
- con = pb[bone].constraints.new('DAMPED_TRACK')
- con.target = obj
- con.subtarget = mbone1
-
-
- return tuple()
diff --git a/release/scripts/modules/rigify_utils.py b/release/scripts/modules/rigify_utils.py
deleted file mode 100644
index 1ffe366e0d5..00000000000
--- a/release/scripts/modules/rigify_utils.py
+++ /dev/null
@@ -1,467 +0,0 @@
-# ##### 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>
-
-# rigify its self does not depend on this module, however some of the
-# rigify templates use these utility functions.
-#
-# So even though this can be for general purpose use, this module was created
-# for rigify so in some cases seemingly generic functions make assumptions
-# that a generic function would need to check for.
-
-import bpy
-from mathutils import Vector
-from rna_prop_ui import rna_idprop_ui_prop_get
-
-DELIMITER = '-._'
-EMPTY_LAYER = [False] * 32
-
-
-def add_stretch_to(obj, from_name, to_name, name):
- '''
- Adds a bone that stretches from one to another
- '''
-
- mode_orig = obj.mode
- bpy.ops.object.mode_set(mode='EDIT')
-
- arm = obj.data
- stretch_ebone = arm.edit_bones.new(name)
- stretch_name = stretch_ebone.name
- del name
-
- head = stretch_ebone.head = arm.edit_bones[from_name].head.copy()
- #tail = stretch_ebone.tail = arm.edit_bones[to_name].head.copy()
-
- # annoying exception for zero length bones, since its using stretch_to the rest pose doesnt really matter
- #if (head - tail).length < 0.1:
- if 1:
- tail = stretch_ebone.tail = arm.edit_bones[from_name].tail.copy()
-
-
- # Now for the constraint
- bpy.ops.object.mode_set(mode='OBJECT')
-
- stretch_pbone = obj.pose.bones[stretch_name]
-
- con = stretch_pbone.constraints.new('COPY_LOCATION')
- con.target = obj
- con.subtarget = from_name
-
- con = stretch_pbone.constraints.new('STRETCH_TO')
- con.target = obj
- con.subtarget = to_name
- con.rest_length = (head - tail).length
- con.keep_axis = 'PLANE_X'
- con.volume = 'NO_VOLUME'
-
- bpy.ops.object.mode_set(mode=mode_orig)
-
- return stretch_name
-
-
-def copy_bone_simple(arm, from_bone, name, parent=False):
- ebone = arm.edit_bones[from_bone]
- ebone_new = arm.edit_bones.new(name)
-
- if parent:
- ebone_new.use_connect = ebone.use_connect
- ebone_new.parent = ebone.parent
-
- ebone_new.head = ebone.head
- ebone_new.tail = ebone.tail
- ebone_new.roll = ebone.roll
- ebone_new.layers = list(ebone.layers)
- return ebone_new
-
-
-def copy_bone_simple_list(arm, from_bones, to_bones, parent=False):
-
- if len(from_bones) != len(to_bones):
- raise Exception("bone list sizes must match")
-
- copy_bones = [copy_bone_simple(arm, bone_name, to_bones[i], True) for i, bone_name in enumerate(from_bones)]
-
- # now we need to re-parent
- for ebone in copy_bones:
- parent = ebone.parent
- if parent:
- try:
- i = from_bones.index(parent.name)
- except:
- i = -1
-
- if i == -1:
- ebone.parent = None
- else:
- ebone.parent = copy_bones[i]
-
- return copy_bones
-
-
-def blend_bone_list(obj, apply_bones, from_bones, to_bones, target_bone=None, target_prop="blend", blend_default=0.5):
-
- if obj.mode == 'EDIT':
- raise Exception("blending cant be called in editmode")
-
- if len(apply_bones) != len(from_bones):
- raise Exception("lists differ in length (from -> apply): \n\t%s\n\t%s" % (from_bones, apply_bones))
- if len(apply_bones) != len(to_bones):
- raise Exception("lists differ in length (to -> apply): \n\t%s\n\t%s" % (to_bones, apply_bones))
-
- # setup the blend property
- if target_bone is None:
- target_bone = apply_bones[-1] # default to the last bone
-
- prop_pbone = obj.pose.bones[target_bone]
- if prop_pbone.get(target_bone) is None:
- prop = rna_idprop_ui_prop_get(prop_pbone, target_prop, create=True)
- prop_pbone[target_prop] = blend_default
- prop["soft_min"] = 0.0
- prop["soft_max"] = 1.0
-
- driver_path = prop_pbone.path_from_id() + ('["%s"]' % target_prop)
-
- def blend_target(driver):
- var = driver.variables.new()
- var.name = target_bone
- var.targets[0].id_type = 'OBJECT'
- var.targets[0].id = obj
- var.targets[0].data_path = driver_path
-
- def blend_transforms(new_pbone, from_bone_name, to_bone_name):
- con = new_pbone.constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = from_bone_name
-
- con = new_pbone.constraints.new('COPY_TRANSFORMS')
- con.target = obj
- con.subtarget = to_bone_name
-
- fcurve = con.driver_add("influence")
- driver = fcurve.driver
- driver.type = 'AVERAGE'
- fcurve.modifiers.remove(fcurve.modifiers[0]) # grr dont need a modifier
-
- blend_target(driver)
-
- for i, new_bone_name in enumerate(apply_bones):
- from_bone_name = from_bones[i]
- to_bone_name = to_bones[i]
-
- # allow skipping some bones by having None in the list
- if None in (new_bone_name, from_bone_name, to_bone_name):
- continue
-
- new_pbone = obj.pose.bones[new_bone_name]
-
- blend_transforms(new_pbone, from_bone_name, to_bone_name)
-
-
-def add_pole_target_bone(obj, base_bone_name, name, mode='CROSS'):
- '''
- Does not actually create a poll target, just the bone to use as a poll target
- '''
- mode_orig = obj.mode
- bpy.ops.object.mode_set(mode='EDIT')
-
- arm = obj.data
-
- poll_ebone = arm.edit_bones.new(name)
- base_ebone = arm.edit_bones[base_bone_name]
- poll_name = poll_ebone.name
- parent_ebone = base_ebone.parent
-
- base_head = base_ebone.head.copy()
- base_tail = base_ebone.tail.copy()
- base_dir = base_head - base_tail
-
- parent_head = parent_ebone.head.copy()
- parent_tail = parent_ebone.tail.copy()
- parent_dir = parent_head - parent_tail
-
- distance = (base_dir.length + parent_dir.length)
-
- if mode == 'CROSS':
- # direction from the angle of the joint
- offset = base_dir.copy().normalize() - parent_dir.copy().normalize()
- 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))
- offset = (z_axis_a + z_axis_b).normalize() * distance
- else:
- # preset axis
- offset = Vector((0.0, 0.0, 0.0))
- if mode[0] == "+":
- val = distance
- else:
- val = - distance
-
- setattr(offset, mode[1].lower(), val)
-
- poll_ebone.head = base_head + offset
- poll_ebone.tail = base_head + (offset * (1.0 - (1.0 / 4.0)))
-
- bpy.ops.object.mode_set(mode=mode_orig)
-
- return poll_name
-
-
-def get_side_name(name):
- '''
- Returns the last part of a string (typically a bone's name) indicating
- whether it is a a left or right (or center, or whatever) bone.
- Returns an empty string if nothing is found.
- '''
- if name[-2] in DELIMITER:
- return name[-2:]
- else:
- return ""
-
-
-def get_base_name(name):
- '''
- Returns the part of a string (typically a bone's name) corresponding to it's
- base name (no sidedness, no ORG prefix).
- '''
- if name[-2] in DELIMITER:
- return name[:-2]
- else:
- return name
-
-
-def write_meta_rig(obj, func_name="metarig_template"):
- '''
- Write a metarig as a python script, this rig is to have all info needed for
- generating the real rig with rigify.
- '''
- code = []
-
- code.append("def %s():" % func_name)
- code.append(" # generated by rigify.write_meta_rig")
- bpy.ops.object.mode_set(mode='EDIT')
- code.append(" bpy.ops.object.mode_set(mode='EDIT')")
-
- code.append(" obj = bpy.context.active_object")
- code.append(" arm = obj.data")
-
- arm = obj.data
- # write parents first
- bones = [(len(bone.parent_recursive), bone.name) for bone in arm.edit_bones]
- bones.sort(key=lambda item: item[0])
- bones = [item[1] for item in bones]
-
-
- for bone_name in bones:
- bone = arm.edit_bones[bone_name]
- code.append(" bone = arm.edit_bones.new('%s')" % bone.name)
- code.append(" bone.head[:] = %.4f, %.4f, %.4f" % bone.head.to_tuple(4))
- code.append(" bone.tail[:] = %.4f, %.4f, %.4f" % bone.tail.to_tuple(4))
- code.append(" bone.roll = %.4f" % bone.roll)
- code.append(" bone.use_connect = %s" % str(bone.use_connect))
- if bone.parent:
- code.append(" bone.parent = arm.edit_bones['%s']" % bone.parent.name)
-
- bpy.ops.object.mode_set(mode='OBJECT')
- code.append("")
- code.append(" bpy.ops.object.mode_set(mode='OBJECT')")
-
- for bone_name in bones:
- pbone = obj.pose.bones[bone_name]
- pbone_written = False
-
- # Only 1 level of props, simple types supported
- for key, value in pbone.items():
- if key.startswith("_"):
- continue
-
- if type(value) not in (float, str, int):
- print("Unsupported ID Prop:", str((key, value)))
- continue
-
- if type(value) == str:
- value = "'" + value + "'"
-
- if not pbone_written: # only write bones we need
- code.append(" pbone = obj.pose.bones['%s']" % bone_name)
-
- code.append(" pbone['%s'] = %s" % (key, value))
-
- return "\n".join(code)
-
-
-# *** bone class collection ***
-
-
-def bone_class_instance(obj, slots, name="BoneContainer"):
- '''
- bone collection utility class to help manage cases with
- edit/pose/bone bones where switching modes can invalidate some of the members.
-
- there are also utility functions for manipulating all members.
- '''
-
- attr_names = tuple(slots) # dont modify the original
-
- if len(slots) != len(set(slots)):
- raise Exception("duplicate entries found %s" % attr_names)
-
- slots = list(slots) # dont modify the original
- for i in range(len(slots)):
- member = slots[i]
- slots.append(member + "_b") # bone bone
- slots.append(member + "_p") # pose bone
- slots.append(member + "_e") # edit bone
-
- class_dict = { \
- "obj": obj, \
- "attr_names": attr_names, \
- "attr_initialize": _bone_class_instance_attr_initialize, \
- "update": _bone_class_instance_update, \
- "rename": _bone_class_instance_rename, \
- "names": _bone_class_instance_names, \
- "copy": _bone_class_instance_copy, \
- "blend": _bone_class_instance_blend, \
- }
-
- instance = auto_class_instance(slots, name, class_dict)
- return instance
-
-
-def auto_class(slots, name="ContainerClass", class_dict=None):
-
- if class_dict:
- class_dict = class_dict.copy()
- else:
- class_dict = {}
-
- class_dict["__slots__"] = tuple(slots)
-
- return type(name, (object,), class_dict)
-
-
-def auto_class_instance(slots, name="ContainerClass", class_dict=None):
- return auto_class(slots, name, class_dict)()
-
-
-def _bone_class_instance_attr_initialize(self, attr_names, bone_names):
- ''' Initializes attributes, both lists must be aligned
- '''
- for attr in self.attr_names:
- i = attr_names.index(attr)
- setattr(self, attr, bone_names[i])
-
- self.update()
-
-
-def _bone_class_instance_update(self):
- ''' Re-Assigns bones from the blender data
- '''
- arm = self.obj.data
- bbones = arm.bones
- pbones = self.obj.pose.bones
- ebones = arm.edit_bones
-
- for member in self.attr_names:
- name = getattr(self, member, None)
- if name is not None:
- setattr(self, member + "_b", bbones.get(name))
- setattr(self, member + "_p", pbones.get(name))
- setattr(self, member + "_e", ebones.get(name))
-
-
-def _bone_class_instance_rename(self, attr, new_name):
- ''' Rename bones, editmode only
- '''
-
- if self.obj.mode != 'EDIT':
- raise Exception("Only rename in editmode supported")
-
- ebone = getattr(self, attr + "_e")
- ebone.name = new_name
-
- # we may not get what is asked for so get the name from the editbone
- setattr(self, attr, ebone.name)
-
-
-def _bone_class_instance_copy(self, from_fmt="%s", to_fmt="%s", exclude_attrs=(), base_names=None):
- from_name_ls = []
- new_name_ls = []
- new_slot_ls = []
-
- for attr in self.attr_names:
-
- if attr in exclude_attrs:
- continue
-
- bone_name_orig = getattr(self, attr)
- ebone = getattr(self, attr + "_e")
- # orig_names[attr] = bone_name_orig
-
- # insert formatting
- if from_fmt != "%s":
- bone_name = from_fmt % bone_name_orig
- ebone.name = bone_name
- bone_name = ebone.name # cant be sure we get what we ask for
- else:
- bone_name = bone_name_orig
-
- setattr(self, attr, bone_name)
-
- new_slot_ls.append(attr)
- from_name_ls.append(bone_name)
- if base_names:
- bone_name_orig = base_names[bone_name_orig]
- new_name_ls.append(to_fmt % bone_name_orig)
-
- new_bones = copy_bone_simple_list(self.obj.data, from_name_ls, new_name_ls, True)
- new_bc = bone_class_instance(self.obj, new_slot_ls)
-
- for i, attr in enumerate(new_slot_ls):
- ebone = new_bones[i]
- setattr(new_bc, attr + "_e", ebone)
- setattr(new_bc, attr, ebone.name)
-
- return new_bc
-
-
-def _bone_class_instance_names(self):
- return [getattr(self, attr) for attr in self.attr_names]
-
-
-def _bone_class_instance_blend(self, from_bc, to_bc, target_bone=None, target_prop="blend"):
- '''
- Use for blending bone chains.
-
- blend_target = (bone_name, bone_property)
- default to the last bone, blend prop
-
- XXX - toggles editmode, need to re-validate all editbones :(
- '''
-
- if self.attr_names != from_bc.attr_names or self.attr_names != to_bc.attr_names:
- raise Exception("can only blend between matching chains")
-
- apply_bones = [getattr(self, attr) for attr in self.attr_names]
- from_bones = [getattr(from_bc, attr) for attr in from_bc.attr_names]
- to_bones = [getattr(to_bc, attr) for attr in to_bc.attr_names]
-
- blend_bone_list(self.obj, apply_bones, from_bones, to_bones, target_bone, target_prop)
diff --git a/release/scripts/modules/rna_info.py b/release/scripts/modules/rna_info.py
index 4282889c51a..e0298d30aa2 100644
--- a/release/scripts/modules/rna_info.py
+++ b/release/scripts/modules/rna_info.py
@@ -152,7 +152,7 @@ class InfoStructRNA:
functions.append((identifier, attr))
return functions
- def __repr__(self):
+ def __str__(self):
txt = ""
txt += self.identifier
@@ -285,7 +285,7 @@ class InfoPropertyRNA:
return type_str
- def __repr__(self):
+ def __str__(self):
txt = ''
txt += ' * ' + self.identifier + ': ' + self.description
@@ -319,7 +319,7 @@ class InfoFunctionRNA:
self.return_values = tuple(self.return_values)
- def __repr__(self):
+ def __str__(self):
txt = ''
txt += ' * ' + self.identifier + '('
diff --git a/release/scripts/modules/rna_prop_ui.py b/release/scripts/modules/rna_prop_ui.py
index cbe0b668e77..9311987e2e7 100644
--- a/release/scripts/modules/rna_prop_ui.py
+++ b/release/scripts/modules/rna_prop_ui.py
@@ -58,7 +58,24 @@ def rna_idprop_ui_prop_clear(item, prop):
pass
-def draw(layout, context, context_member, use_edit=True):
+def rna_idprop_context_value(context, context_member, property_type):
+ space = context.space_data
+
+ if space is None or isinstance(space, bpy.types.SpaceProperties):
+ pin_id = space.pin_id
+ else:
+ pin_id = None
+
+ if pin_id and isinstance(pin_id, property_type):
+ rna_item = pin_id
+ context_member = "space_data.pin_id"
+ else:
+ rna_item = eval("context." + context_member)
+
+ return rna_item, context_member
+
+
+def draw(layout, context, context_member, property_type, use_edit=True):
def assign_props(prop, val, key):
prop.data_path = context_member
@@ -69,12 +86,14 @@ def draw(layout, context, context_member, use_edit=True):
except:
pass
- rna_item = eval("context." + context_member)
+ rna_item, context_member = rna_idprop_context_value(context, context_member, property_type)
# poll should really get this...
if not rna_item:
return
+ assert(isinstance(rna_item, property_type))
+
items = rna_item.items()
items.sort()
@@ -139,7 +158,16 @@ class PropertyPanel():
@classmethod
def poll(cls, context):
- return bool(eval("context.%s" % cls._context_path))
+ rna_item, context_member = rna_idprop_context_value(context, cls._context_path, cls._property_type)
+ return bool(rna_item)
+
+ """
+ def draw_header(self, context):
+ rna_item, context_member = rna_idprop_context_value(context, self._context_path, self._property_type)
+ tot = len(rna_item.keys())
+ if tot:
+ self.layout().label("%d:" % tot)
+ """
def draw(self, context):
- draw(self.layout, context, self._context_path)
+ draw(self.layout, context, self._context_path, self._property_type)
diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py
new file mode 100644
index 00000000000..303277a5d75
--- /dev/null
+++ b/release/scripts/modules/sys_info.py
@@ -0,0 +1,111 @@
+# ##### 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>
+
+# classes for extracting info from blenders internal classes
+
+import bpy
+import bgl
+
+import sys
+
+
+def cutPoint(text, length):
+ "Returns position of the last space found before 'length' chars"
+ l = length
+ c = text[l]
+ while c != ' ':
+ l -= 1
+ if l == 0:
+ return length # no space found
+ c = text[l]
+ return l
+
+
+def textWrap(text, length=70):
+ lines = []
+ while len(text) > 70:
+ cpt = cutPoint(text, length)
+ line, text = text[:cpt], text[cpt + 1:]
+ lines.append(line)
+ lines.append(text)
+ return lines
+
+
+def write_sysinfo(op):
+ output_filename = "system-info.txt"
+ warnings = 0
+ notices = 0
+
+ if output_filename in bpy.data.texts.keys():
+ output = bpy.data.texts[output_filename]
+ output.clear()
+ else:
+ output = bpy.data.texts.new(name=output_filename)
+
+ header = '= Blender {} System Information =\n'.format(bpy.app.version_string)
+ lilies = '{}\n\n'.format(len(header) * '=')
+ firstlilies = '{}\n'.format(len(header) * '=')
+ output.write(firstlilies)
+ output.write(header)
+ output.write(lilies)
+
+ # build info
+ output.write('\nBlender:\n')
+ output.write(lilies)
+ output.write('version {}, revision {}. {}\n'.format(bpy.app.version_string, bpy.app.build_revision, bpy.app.build_type))
+ output.write('build date: {}, {}\n'.format(bpy.app.build_date, bpy.app.build_time))
+ output.write('platform: {}\n'.format(bpy.app.build_platform))
+ output.write('binary path: {}\n'.format(bpy.app.binary_path))
+ output.write('build cflags: {}\n'.format(bpy.app.build_cflags))
+ output.write('build cxxflags: {}\n'.format(bpy.app.build_cxxflags))
+ output.write('build linkflags: {}\n'.format(bpy.app.build_linkflags))
+ output.write('build system: {}\n'.format(bpy.app.build_system))
+
+ # python info
+ output.write('\nPython:\n')
+ output.write(lilies)
+ output.write('version: {}\n'.format(sys.version))
+ output.write('paths:\n')
+ for p in sys.path:
+ output.write('\t{}\n'.format(p))
+
+ output.write('\nDirectories:\n')
+ output.write(lilies)
+ output.write('scripts: {}\n'.format(bpy.utils.script_paths()))
+ output.write('user scripts: {}\n'.format(bpy.utils.user_script_path()))
+ output.write('datafiles: {}\n'.format(bpy.utils.user_resource('DATAFILES')))
+ output.write('config: {}\n'.format(bpy.utils.user_resource('CONFIG')))
+ output.write('scripts : {}\n'.format(bpy.utils.user_resource('SCRIPTS')))
+ output.write('autosave: {}\n'.format(bpy.utils.user_resource('AUTOSAVE')))
+ output.write('tempdir: {}\n'.format(bpy.app.tempdir))
+
+ output.write('\nOpenGL\n')
+ output.write(lilies)
+ output.write('renderer:\t{}\n'.format(bgl.glGetString(bgl.GL_RENDERER)))
+ output.write('vendor:\t\t{}\n'.format(bgl.glGetString(bgl.GL_VENDOR)))
+ output.write('version:\t{}\n'.format(bgl.glGetString(bgl.GL_VERSION)))
+ output.write('extensions:\n')
+
+ glext = bgl.glGetString(bgl.GL_EXTENSIONS)
+ glext = textWrap(glext, 70)
+ for l in glext:
+ output.write('\t\t{}\n'.format(l))
+
+ op.report({'INFO'}, "System information generated in 'system-info.txt'")
diff --git a/release/scripts/op/add_armature_human.py b/release/scripts/op/add_armature_human.py
deleted file mode 100644
index 95b414f8228..00000000000
--- a/release/scripts/op/add_armature_human.py
+++ /dev/null
@@ -1,616 +0,0 @@
-# ##### 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-80 compliant>
-import bpy
-import mathutils
-from math import cos, sin, pi
-
-# could this be stored elsewhere?
-
-
-def metarig_template():
- # 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('pelvis')
- bone.head[:] = -0.0000, -0.0145, 1.1263
- bone.tail[:] = -0.0000, -0.0145, 0.9563
- bone.roll = 3.1416
- bone.use_connect = False
- bone = arm.edit_bones.new('torso')
- bone.head[:] = -0.0000, -0.0145, 1.1263
- bone.tail[:] = -0.0000, -0.0145, 1.2863
- bone.roll = 3.1416
- bone.use_connect = False
- bone.parent = arm.edit_bones['pelvis']
- bone = arm.edit_bones.new('spine.01')
- bone.head[:] = 0.0000, 0.0394, 0.9688
- bone.tail[:] = -0.0000, -0.0145, 1.1263
- bone.roll = 0.0000
- bone.use_connect = False
- bone.parent = arm.edit_bones['torso']
- bone = arm.edit_bones.new('spine.02')
- bone.head[:] = -0.0000, -0.0145, 1.1263
- bone.tail[:] = -0.0000, -0.0213, 1.2884
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['spine.01']
- bone = arm.edit_bones.new('thigh.L')
- bone.head[:] = 0.0933, -0.0421, 1.0434
- bone.tail[:] = 0.0933, -0.0516, 0.5848
- bone.roll = 0.0000
- bone.use_connect = False
- bone.parent = arm.edit_bones['spine.01']
- bone = arm.edit_bones.new('thigh.R')
- bone.head[:] = -0.0933, -0.0421, 1.0434
- bone.tail[:] = -0.0933, -0.0516, 0.5848
- bone.roll = -0.0000
- bone.use_connect = False
- bone.parent = arm.edit_bones['spine.01']
- bone = arm.edit_bones.new('spine.03')
- bone.head[:] = -0.0000, -0.0213, 1.2884
- bone.tail[:] = -0.0000, 0.0160, 1.3705
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['spine.02']
- bone = arm.edit_bones.new('shin.L')
- bone.head[:] = 0.0933, -0.0516, 0.5848
- bone.tail[:] = 0.0915, 0.0100, 0.1374
- bone.roll = 0.0034
- bone.use_connect = True
- bone.parent = arm.edit_bones['thigh.L']
- bone = arm.edit_bones.new('shin.R')
- bone.head[:] = -0.0933, -0.0516, 0.5848
- bone.tail[:] = -0.0915, 0.0100, 0.1374
- bone.roll = -0.0034
- bone.use_connect = True
- bone.parent = arm.edit_bones['thigh.R']
- bone = arm.edit_bones.new('spine.04')
- bone.head[:] = -0.0000, 0.0160, 1.3705
- bone.tail[:] = -0.0000, 0.0590, 1.4497
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['spine.03']
- bone = arm.edit_bones.new('foot.L')
- bone.head[:] = 0.0915, 0.0100, 0.1374
- bone.tail[:] = 0.1033, -0.0968, 0.0510
- bone.roll = 2.8964
- bone.use_connect = True
- bone.parent = arm.edit_bones['shin.L']
- bone = arm.edit_bones.new('foot.R')
- bone.head[:] = -0.0915, 0.0100, 0.1374
- bone.tail[:] = -0.1033, -0.0968, 0.0510
- bone.roll = -2.8793
- bone.use_connect = True
- bone.parent = arm.edit_bones['shin.R']
- bone = arm.edit_bones.new('neck_base')
- bone.head[:] = -0.0000, 0.0590, 1.4497
- bone.tail[:] = -0.0000, 0.0401, 1.5389
- bone.roll = -0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['spine.04']
- bone = arm.edit_bones.new('toe.L')
- bone.head[:] = 0.1033, -0.0968, 0.0510
- bone.tail[:] = 0.1136, -0.1848, 0.0510
- bone.roll = 0.0001
- bone.use_connect = True
- bone.parent = arm.edit_bones['foot.L']
- bone = arm.edit_bones.new('heel.L')
- bone.head[:] = 0.0809, 0.0969, -0.0000
- bone.tail[:] = 0.1020, -0.0846, -0.0000
- bone.roll = -0.0001
- bone.use_connect = False
- bone.parent = arm.edit_bones['foot.L']
- bone = arm.edit_bones.new('toe.R')
- bone.head[:] = -0.1033, -0.0968, 0.0510
- bone.tail[:] = -0.1136, -0.1848, 0.0510
- bone.roll = -0.0002
- bone.use_connect = True
- bone.parent = arm.edit_bones['foot.R']
- bone = arm.edit_bones.new('heel.R')
- bone.head[:] = -0.0809, 0.0969, -0.0000
- bone.tail[:] = -0.1020, -0.0846, -0.0000
- bone.roll = -0.0000
- bone.use_connect = False
- bone.parent = arm.edit_bones['foot.R']
- bone = arm.edit_bones.new('head')
- bone.head[:] = -0.0000, 0.0401, 1.5389
- bone.tail[:] = -0.0000, 0.0401, 1.5979
- bone.roll = 3.1416
- bone.use_connect = True
- bone.parent = arm.edit_bones['neck_base']
- bone = arm.edit_bones.new('DLT-shoulder.L')
- bone.head[:] = 0.0141, -0.0346, 1.4991
- bone.tail[:] = 0.1226, 0.0054, 1.4991
- bone.roll = 0.0005
- bone.use_connect = False
- bone.parent = arm.edit_bones['neck_base']
- bone = arm.edit_bones.new('DLT-shoulder.R')
- bone.head[:] = -0.0141, -0.0346, 1.4991
- bone.tail[:] = -0.1226, 0.0054, 1.4991
- bone.roll = -0.0005
- bone.use_connect = False
- bone.parent = arm.edit_bones['neck_base']
- bone = arm.edit_bones.new('neck.01')
- bone.head[:] = -0.0000, 0.0401, 1.5389
- bone.tail[:] = -0.0000, 0.0176, 1.5916
- bone.roll = 0.0000
- bone.use_connect = False
- bone.parent = arm.edit_bones['head']
- bone = arm.edit_bones.new('shoulder.L')
- bone.head[:] = 0.0141, -0.0346, 1.4991
- bone.tail[:] = 0.1226, 0.0216, 1.5270
- bone.roll = -0.1225
- bone.use_connect = False
- bone.parent = arm.edit_bones['DLT-shoulder.L']
- bone = arm.edit_bones.new('shoulder.R')
- bone.head[:] = -0.0141, -0.0346, 1.4991
- bone.tail[:] = -0.1226, 0.0216, 1.5270
- bone.roll = 0.0849
- bone.use_connect = False
- bone.parent = arm.edit_bones['DLT-shoulder.R']
- bone = arm.edit_bones.new('neck.02')
- bone.head[:] = -0.0000, 0.0176, 1.5916
- bone.tail[:] = -0.0000, 0.0001, 1.6499
- bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['neck.01']
- bone = arm.edit_bones.new('DLT-upper_arm.L')
- bone.head[:] = 0.1482, 0.0483, 1.4943
- bone.tail[:] = 0.2586, 0.1057, 1.5124
- bone.roll = 1.4969
- bone.use_connect = False
- bone.parent = arm.edit_bones['shoulder.L']
- bone = arm.edit_bones.new('DLT-upper_arm.R')
- bone.head[:] = -0.1482, 0.0483, 1.4943
- bone.tail[:] = -0.2586, 0.1057, 1.5124
- bone.roll = -1.4482
- bone.use_connect = False
- bone.parent = arm.edit_bones['shoulder.R']
- bone = arm.edit_bones.new('neck.03')
- bone.head[:] = -0.0000, 0.0001, 1.6499
- bone.tail[:] = -0.0000, 0.0001, 1.8522
- bone.roll = 0.0000
- bone.use_connect = True
- bone.parent = arm.edit_bones['neck.02']
- bone = arm.edit_bones.new('upper_arm.L')
- bone.head[:] = 0.1482, 0.0483, 1.4943
- bone.tail[:] = 0.3929, 0.0522, 1.4801
- bone.roll = 1.6281
- bone.use_connect = False
- bone.parent = arm.edit_bones['DLT-upper_arm.L']
- bone = arm.edit_bones.new('upper_arm.R')
- bone.head[:] = -0.1482, 0.0483, 1.4943
- bone.tail[:] = -0.3929, 0.0522, 1.4801
- bone.roll = -1.6281
- bone.use_connect = False
- bone.parent = arm.edit_bones['DLT-upper_arm.R']
- bone = arm.edit_bones.new('forearm.L')
- bone.head[:] = 0.3929, 0.0522, 1.4801
- bone.tail[:] = 0.6198, 0.0364, 1.4906
- bone.roll = 1.5240
- bone.use_connect = True
- bone.parent = arm.edit_bones['upper_arm.L']
- bone = arm.edit_bones.new('forearm.R')
- bone.head[:] = -0.3929, 0.0522, 1.4801
- bone.tail[:] = -0.6198, 0.0364, 1.4906
- bone.roll = -1.5219
- bone.use_connect = True
- bone.parent = arm.edit_bones['upper_arm.R']
- bone = arm.edit_bones.new('hand.L')
- bone.head[:] = 0.6198, 0.0364, 1.4906
- bone.tail[:] = 0.6592, 0.0364, 1.4853
- bone.roll = -3.0065
- bone.use_connect = True
- bone.parent = arm.edit_bones['forearm.L']
- bone = arm.edit_bones.new('hand.R')
- bone.head[:] = -0.6198, 0.0364, 1.4906
- bone.tail[:] = -0.6592, 0.0364, 1.4853
- bone.roll = 3.0065
- bone.use_connect = True
- bone.parent = arm.edit_bones['forearm.R']
- bone = arm.edit_bones.new('palm.04.L')
- bone.head[:] = 0.6514, 0.0658, 1.4906
- bone.tail[:] = 0.7287, 0.0810, 1.4747
- bone.roll = -3.0715
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand.L']
- bone = arm.edit_bones.new('palm.03.L')
- bone.head[:] = 0.6533, 0.0481, 1.4943
- bone.tail[:] = 0.7386, 0.0553, 1.4781
- bone.roll = -3.0290
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand.L']
- bone = arm.edit_bones.new('palm.02.L')
- bone.head[:] = 0.6539, 0.0305, 1.4967
- bone.tail[:] = 0.7420, 0.0250, 1.4835
- bone.roll = -3.0669
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand.L']
- bone = arm.edit_bones.new('palm.01.L')
- bone.head[:] = 0.6514, 0.0116, 1.4961
- bone.tail[:] = 0.7361, -0.0074, 1.4823
- bone.roll = -2.9422
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand.L']
- bone = arm.edit_bones.new('thumb.01.L')
- bone.head[:] = 0.6380, -0.0005, 1.4848
- bone.tail[:] = 0.6757, -0.0408, 1.4538
- bone.roll = -0.7041
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand.L']
- bone = arm.edit_bones.new('palm.04.R')
- bone.head[:] = -0.6514, 0.0658, 1.4906
- bone.tail[:] = -0.7287, 0.0810, 1.4747
- bone.roll = 3.0715
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand.R']
- bone = arm.edit_bones.new('palm.03.R')
- bone.head[:] = -0.6533, 0.0481, 1.4943
- bone.tail[:] = -0.7386, 0.0553, 1.4781
- bone.roll = 3.0290
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand.R']
- bone = arm.edit_bones.new('palm.02.R')
- bone.head[:] = -0.6539, 0.0305, 1.4967
- bone.tail[:] = -0.7420, 0.0250, 1.4835
- bone.roll = 3.0669
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand.R']
- bone = arm.edit_bones.new('thumb.01.R')
- bone.head[:] = -0.6380, -0.0005, 1.4848
- bone.tail[:] = -0.6757, -0.0408, 1.4538
- bone.roll = 0.7041
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand.R']
- bone = arm.edit_bones.new('palm.01.R')
- bone.head[:] = -0.6514, 0.0116, 1.4961
- bone.tail[:] = -0.7361, -0.0074, 1.4823
- bone.roll = 2.9332
- bone.use_connect = False
- bone.parent = arm.edit_bones['hand.R']
- bone = arm.edit_bones.new('finger_pinky.01.L')
- bone.head[:] = 0.7287, 0.0810, 1.4747
- bone.tail[:] = 0.7698, 0.0947, 1.4635
- bone.roll = -3.0949
- bone.use_connect = True
- bone.parent = arm.edit_bones['palm.04.L']
- bone = arm.edit_bones.new('finger_ring.01.L')
- bone.head[:] = 0.7386, 0.0553, 1.4781
- bone.tail[:] = 0.7890, 0.0615, 1.4667
- bone.roll = -3.0081
- bone.use_connect = True
- bone.parent = arm.edit_bones['palm.03.L']
- bone = arm.edit_bones.new('finger_middle.01.L')
- bone.head[:] = 0.7420, 0.0250, 1.4835
- bone.tail[:] = 0.7975, 0.0221, 1.4712
- bone.roll = -2.9982
- bone.use_connect = True
- bone.parent = arm.edit_bones['palm.02.L']
- bone = arm.edit_bones.new('finger_index.01.L')
- bone.head[:] = 0.7361, -0.0074, 1.4823
- bone.tail[:] = 0.7843, -0.0204, 1.4718
- bone.roll = -3.0021
- bone.use_connect = True
- bone.parent = arm.edit_bones['palm.01.L']
- bone = arm.edit_bones.new('thumb.02.L')
- bone.head[:] = 0.6757, -0.0408, 1.4538
- bone.tail[:] = 0.6958, -0.0568, 1.4376
- bone.roll = -0.6963
- bone.use_connect = True
- bone.parent = arm.edit_bones['thumb.01.L']
- bone = arm.edit_bones.new('finger_pinky.01.R')
- bone.head[:] = -0.7287, 0.0810, 1.4747
- bone.tail[:] = -0.7698, 0.0947, 1.4635
- bone.roll = 3.0949
- bone.use_connect = True
- bone.parent = arm.edit_bones['palm.04.R']
- bone = arm.edit_bones.new('finger_ring.01.R')
- bone.head[:] = -0.7386, 0.0553, 1.4781
- bone.tail[:] = -0.7890, 0.0615, 1.4667
- bone.roll = 2.9892
- bone.use_connect = True
- bone.parent = arm.edit_bones['palm.03.R']
- bone = arm.edit_bones.new('finger_middle.01.R')
- bone.head[:] = -0.7420, 0.0250, 1.4835
- bone.tail[:] = -0.7975, 0.0221, 1.4712
- bone.roll = 2.9816
- bone.use_connect = True
- bone.parent = arm.edit_bones['palm.02.R']
- bone = arm.edit_bones.new('thumb.02.R')
- bone.head[:] = -0.6757, -0.0408, 1.4538
- bone.tail[:] = -0.6958, -0.0568, 1.4376
- bone.roll = 0.6963
- bone.use_connect = True
- bone.parent = arm.edit_bones['thumb.01.R']
- bone = arm.edit_bones.new('finger_index.01.R')
- bone.head[:] = -0.7361, -0.0074, 1.4823
- bone.tail[:] = -0.7843, -0.0204, 1.4718
- bone.roll = 2.9498
- bone.use_connect = True
- bone.parent = arm.edit_bones['palm.01.R']
- bone = arm.edit_bones.new('finger_pinky.02.L')
- bone.head[:] = 0.7698, 0.0947, 1.4635
- bone.tail[:] = 0.7910, 0.1018, 1.4577
- bone.roll = -3.0949
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_pinky.01.L']
- bone = arm.edit_bones.new('finger_ring.02.L')
- bone.head[:] = 0.7890, 0.0615, 1.4667
- bone.tail[:] = 0.8177, 0.0650, 1.4600
- bone.roll = -3.0006
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_ring.01.L']
- bone = arm.edit_bones.new('finger_middle.02.L')
- bone.head[:] = 0.7975, 0.0221, 1.4712
- bone.tail[:] = 0.8289, 0.0206, 1.4643
- bone.roll = -2.9995
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_middle.01.L']
- bone = arm.edit_bones.new('finger_index.02.L')
- bone.head[:] = 0.7843, -0.0204, 1.4718
- bone.tail[:] = 0.8117, -0.0275, 1.4660
- bone.roll = -3.0064
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_index.01.L']
- bone = arm.edit_bones.new('thumb.03.L')
- bone.head[:] = 0.6958, -0.0568, 1.4376
- bone.tail[:] = 0.7196, -0.0671, 1.4210
- bone.roll = -0.8072
- bone.use_connect = True
- bone.parent = arm.edit_bones['thumb.02.L']
- bone = arm.edit_bones.new('finger_pinky.02.R')
- bone.head[:] = -0.7698, 0.0947, 1.4635
- bone.tail[:] = -0.7910, 0.1018, 1.4577
- bone.roll = 3.0949
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_pinky.01.R']
- bone = arm.edit_bones.new('finger_ring.02.R')
- bone.head[:] = -0.7890, 0.0615, 1.4667
- bone.tail[:] = -0.8177, 0.0650, 1.4600
- bone.roll = 3.0341
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_ring.01.R']
- bone = arm.edit_bones.new('finger_middle.02.R')
- bone.head[:] = -0.7975, 0.0221, 1.4712
- bone.tail[:] = -0.8289, 0.0206, 1.4643
- bone.roll = 3.0291
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_middle.01.R']
- bone = arm.edit_bones.new('thumb.03.R')
- bone.head[:] = -0.6958, -0.0568, 1.4376
- bone.tail[:] = -0.7196, -0.0671, 1.4210
- bone.roll = 0.8072
- bone.use_connect = True
- bone.parent = arm.edit_bones['thumb.02.R']
- bone = arm.edit_bones.new('finger_index.02.R')
- bone.head[:] = -0.7843, -0.0204, 1.4718
- bone.tail[:] = -0.8117, -0.0275, 1.4660
- bone.roll = 3.0705
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_index.01.R']
- bone = arm.edit_bones.new('finger_pinky.03.L')
- bone.head[:] = 0.7910, 0.1018, 1.4577
- bone.tail[:] = 0.8109, 0.1085, 1.4523
- bone.roll = -3.0949
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_pinky.02.L']
- bone = arm.edit_bones.new('finger_ring.03.L')
- bone.head[:] = 0.8177, 0.0650, 1.4600
- bone.tail[:] = 0.8396, 0.0677, 1.4544
- bone.roll = -2.9819
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_ring.02.L']
- bone = arm.edit_bones.new('finger_middle.03.L')
- bone.head[:] = 0.8289, 0.0206, 1.4643
- bone.tail[:] = 0.8534, 0.0193, 1.4589
- bone.roll = -3.0004
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_middle.02.L']
- bone = arm.edit_bones.new('finger_index.03.L')
- bone.head[:] = 0.8117, -0.0275, 1.4660
- bone.tail[:] = 0.8331, -0.0333, 1.4615
- bone.roll = -3.0103
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_index.02.L']
- bone = arm.edit_bones.new('finger_pinky.03.R')
- bone.head[:] = -0.7910, 0.1018, 1.4577
- bone.tail[:] = -0.8109, 0.1085, 1.4523
- bone.roll = 3.0949
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_pinky.02.R']
- bone = arm.edit_bones.new('finger_ring.03.R')
- bone.head[:] = -0.8177, 0.0650, 1.4600
- bone.tail[:] = -0.8396, 0.0677, 1.4544
- bone.roll = 2.9819
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_ring.02.R']
- bone = arm.edit_bones.new('finger_middle.03.R')
- bone.head[:] = -0.8289, 0.0206, 1.4643
- bone.tail[:] = -0.8534, 0.0193, 1.4589
- bone.roll = 3.0004
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_middle.02.R']
- bone = arm.edit_bones.new('finger_index.03.R')
- bone.head[:] = -0.8117, -0.0275, 1.4660
- bone.tail[:] = -0.8331, -0.0333, 1.4615
- bone.roll = 2.9917
- bone.use_connect = True
- bone.parent = arm.edit_bones['finger_index.02.R']
-
- bpy.ops.object.mode_set(mode='OBJECT')
- pbone = obj.pose.bones['torso']
- pbone['type'] = 'spine_pivot_flex'
- pbone = obj.pose.bones['torso']
- pbone['spine_pivot_flex.later_main'] = 1
- pbone = obj.pose.bones['torso']
- pbone['spine_pivot_flex.layer_extra'] = 2
- pbone = obj.pose.bones['thigh.L']
- pbone['type'] = 'leg_biped'
- pbone = obj.pose.bones['thigh.L']
- pbone['leg_biped_generic.layer_ik'] = 12
- pbone = obj.pose.bones['thigh.L']
- pbone['leg_biped_generic.layer_fk'] = 11
- pbone = obj.pose.bones['thigh.R']
- pbone['type'] = 'leg_biped'
- pbone = obj.pose.bones['thigh.R']
- pbone['leg_biped_generic.layer_ik'] = 14
- pbone = obj.pose.bones['thigh.R']
- pbone['leg_biped_generic.layer_fk'] = 13
- pbone = obj.pose.bones['head']
- pbone['type'] = 'neck_flex'
- pbone = obj.pose.bones['head']
- pbone['neck_flex.layer_extra'] = 4
- pbone = obj.pose.bones['head']
- pbone['neck_flex.layer_main'] = 3
- pbone = obj.pose.bones['DLT-shoulder.L']
- pbone['type'] = 'delta'
- pbone = obj.pose.bones['DLT-shoulder.R']
- pbone['type'] = 'delta'
- pbone = obj.pose.bones['shoulder.L']
- pbone['type'] = 'copy'
- pbone = obj.pose.bones['shoulder.L']
- pbone['copy.layers'] = 1
- pbone = obj.pose.bones['shoulder.R']
- pbone['type'] = 'copy'
- pbone = obj.pose.bones['shoulder.R']
- pbone['copy.layers'] = 1
- pbone = obj.pose.bones['DLT-upper_arm.L']
- pbone['type'] = 'delta'
- pbone = obj.pose.bones['DLT-upper_arm.R']
- pbone['type'] = 'delta'
- pbone = obj.pose.bones['upper_arm.L']
- pbone['type'] = 'arm_biped'
- pbone = obj.pose.bones['upper_arm.L']
- pbone['arm_biped_generic.elbow_parent'] = 'spine.04'
- pbone = obj.pose.bones['upper_arm.L']
- pbone['arm_biped_generic.layer_fk'] = 7
- pbone = obj.pose.bones['upper_arm.L']
- pbone['arm_biped_generic.layer_ik'] = 8
- pbone = obj.pose.bones['upper_arm.R']
- pbone['type'] = 'arm_biped'
- pbone = obj.pose.bones['upper_arm.R']
- pbone['arm_biped_generic.layer_fk'] = 9
- pbone = obj.pose.bones['upper_arm.R']
- pbone['arm_biped_generic.layer_ik'] = 10
- pbone = obj.pose.bones['upper_arm.R']
- pbone['arm_biped_generic.elbow_parent'] = 'spine.04'
- pbone = obj.pose.bones['palm.01.L']
- pbone['type'] = 'palm_curl'
- pbone = obj.pose.bones['palm.01.L']
- pbone['palm_curl.layers'] = 5
- pbone = obj.pose.bones['thumb.01.L']
- pbone['type'] = 'finger_curl'
- pbone = obj.pose.bones['thumb.01.L']
- pbone['finger_curl.layer_main'] = 5
- pbone = obj.pose.bones['thumb.01.L']
- pbone['finger_curl.layer_extra'] = 6
- pbone = obj.pose.bones['thumb.01.R']
- pbone['type'] = 'finger_curl'
- pbone = obj.pose.bones['thumb.01.R']
- pbone['finger_curl.layer_main'] = 5
- pbone = obj.pose.bones['thumb.01.R']
- pbone['finger_curl.layer_extra'] = 6
- pbone = obj.pose.bones['palm.01.R']
- pbone['type'] = 'palm_curl'
- pbone = obj.pose.bones['palm.01.R']
- pbone['palm_curl.layers'] = 5
- pbone = obj.pose.bones['finger_pinky.01.L']
- pbone['type'] = 'finger_curl'
- pbone = obj.pose.bones['finger_pinky.01.L']
- pbone['finger_curl.layer_main'] = 5
- pbone = obj.pose.bones['finger_pinky.01.L']
- pbone['finger_curl.layer_extra'] = 6
- pbone = obj.pose.bones['finger_ring.01.L']
- pbone['type'] = 'finger_curl'
- pbone = obj.pose.bones['finger_ring.01.L']
- pbone['finger_curl.layer_main'] = 5
- pbone = obj.pose.bones['finger_ring.01.L']
- pbone['finger_curl.layer_extra'] = 6
- pbone = obj.pose.bones['finger_middle.01.L']
- pbone['type'] = 'finger_curl'
- pbone = obj.pose.bones['finger_middle.01.L']
- pbone['finger_curl.layer_main'] = 5
- pbone = obj.pose.bones['finger_middle.01.L']
- pbone['finger_curl.layer_extra'] = 6
- pbone = obj.pose.bones['finger_index.01.L']
- pbone['type'] = 'finger_curl'
- pbone = obj.pose.bones['finger_index.01.L']
- pbone['finger_curl.layer_main'] = 5
- pbone = obj.pose.bones['finger_index.01.L']
- pbone['finger_curl.layer_extra'] = 6
- pbone = obj.pose.bones['finger_pinky.01.R']
- pbone['type'] = 'finger_curl'
- pbone = obj.pose.bones['finger_pinky.01.R']
- pbone['finger_curl.layer_main'] = 5
- pbone = obj.pose.bones['finger_pinky.01.R']
- pbone['finger_curl.layer_extra'] = 6
- pbone = obj.pose.bones['finger_ring.01.R']
- pbone['type'] = 'finger_curl'
- pbone = obj.pose.bones['finger_ring.01.R']
- pbone['finger_curl.layer_main'] = 5
- pbone = obj.pose.bones['finger_ring.01.R']
- pbone['finger_curl.layer_extra'] = 6
- pbone = obj.pose.bones['finger_middle.01.R']
- pbone['type'] = 'finger_curl'
- pbone = obj.pose.bones['finger_middle.01.R']
- pbone['finger_curl.layer_main'] = 5
- pbone = obj.pose.bones['finger_middle.01.R']
- pbone['finger_curl.layer_extra'] = 6
- pbone = obj.pose.bones['finger_index.01.R']
- pbone['type'] = 'finger_curl'
- pbone = obj.pose.bones['finger_index.01.R']
- pbone['finger_curl.layer_main'] = 5
- pbone = obj.pose.bones['finger_index.01.R']
- pbone['finger_curl.layer_extra'] = 6
-
-
-class AddHuman(bpy.types.Operator):
- '''Add an advanced human metarig base'''
- bl_idname = "object.armature_human_advanced_add"
- bl_label = "Add Humanoid (advanced metarig)"
- bl_options = {'REGISTER', 'UNDO'}
-
- def execute(self, context):
- bpy.ops.object.armature_add()
- obj = context.active_object
- mode_orig = obj.mode
- bpy.ops.object.mode_set(mode='EDIT') # grr, remove bone
- bones = context.active_object.data.edit_bones
- bones.remove(bones[0])
- metarig_template()
- bpy.ops.object.mode_set(mode=mode_orig)
- return {'FINISHED'}
-
-
-# Add to a menu
-menu_func = (lambda self, context: self.layout.operator(AddHuman.bl_idname,
- icon='OUTLINER_OB_ARMATURE', text="Human (Meta-Rig)"))
-
-
-def register():
- bpy.types.INFO_MT_armature_add.append(menu_func)
-
-
-def unregister():
- 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 36baca45719..db4f90f05d1 100644
--- a/release/scripts/op/add_mesh_torus.py
+++ b/release/scripts/op/add_mesh_torus.py
@@ -26,8 +26,8 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg):
Vector = mathutils.Vector
Quaternion = mathutils.Quaternion
- PI_2 = pi * 2
- z_axis = (0, 0, 1)
+ PI_2 = pi * 2.0
+ z_axis = 0.0, 0.0, 1.0
verts = []
faces = []
@@ -103,8 +103,12 @@ class AddTorus(bpy.types.Operator):
default=0.5, min=0.01, max=100.0)
# generic transform props
- location = FloatVectorProperty(name="Location")
- rotation = FloatVectorProperty(name="Rotation")
+ view_align = BoolProperty(name="Align to View",
+ default=False)
+ location = FloatVectorProperty(name="Location",
+ subtype='TRANSLATION')
+ rotation = FloatVectorProperty(name="Rotation",
+ subtype='EULER')
def execute(self, context):
@@ -128,7 +132,7 @@ class AddTorus(bpy.types.Operator):
mesh.update()
import add_object_utils
- add_object_utils.add_object_data(context, mesh, operator=self)
+ add_object_utils.object_data_add(context, mesh, operator=self)
return {'FINISHED'}
@@ -138,10 +142,12 @@ def menu_func(self, context):
def register():
+ bpy.utils.register_class(AddTorus)
bpy.types.INFO_MT_mesh_add.append(menu_func)
def unregister():
+ bpy.utils.unregister_class(AddTorus)
bpy.types.INFO_MT_mesh_add.remove(menu_func)
if __name__ == "__main__":
diff --git a/release/scripts/op/animsys_update.py b/release/scripts/op/animsys_update.py
index 698021fca7f..9262ff40a37 100644
--- a/release/scripts/op/animsys_update.py
+++ b/release/scripts/op/animsys_update.py
@@ -367,6 +367,7 @@ data_path_update = [
("PoseBone", "ik_limit_z", "use_ik_limit_z"),
("PoseBone", "ik_lin_control", "use_ik_linear_control"),
("PoseBone", "ik_rot_control", "use_ik_rotation_control"),
+ ("Bone", "use_hinge", "use_inherit_rotation"),
("SPHFluidSettings", "spring_k", "spring_force"),
("SPHFluidSettings", "stiffness_k", "stiffness"),
("SPHFluidSettings", "stiffness_knear", "stiffness_near"),
@@ -674,6 +675,10 @@ data_path_update = [
("SequenceCrop", "top", "max_y"),
("SequenceCrop", "bottom", "min_x"),
("SequenceCrop", "left", "min_y"),
+ ("Sequence", "speed_fader", "speed_factor"),
+ ("SpeedControlSequence", "global_speed", "multiply_speed"),
+ ("SpeedControlSequence", "use_curve_velocity", "use_as_speed"),
+ ("SpeedControlSequence", "use_curve_compress_y", "scale_to_length"),
]
@@ -687,7 +692,6 @@ class UpdateAnimData(bpy.types.Operator):
def execute(self, context):
import animsys_refactor
- reload(animsys_refactor)
animsys_refactor.update_data_paths(data_path_update)
return {'FINISHED'}
@@ -695,5 +699,10 @@ class UpdateAnimData(bpy.types.Operator):
if __name__ == "__main__":
bpy.ops.anim.update_data_paths()
+
def register():
- pass
+ bpy.utils.register_module(__name__)
+
+
+def unregister():
+ bpy.utils.unregister_module(__name__)
diff --git a/release/scripts/op/console_python.py b/release/scripts/op/console_python.py
index 601fab23617..98d3f3f74a3 100644
--- a/release/scripts/op/console_python.py
+++ b/release/scripts/op/console_python.py
@@ -83,6 +83,9 @@ def get_console(console_id):
namespace["bpy"] = bpy
namespace["C"] = bpy.context
+ namespace.update(__import__("mathutils").__dict__) # from mathutils import *
+ namespace.update(__import__("math").__dict__) # from math import *
+
console = InteractiveConsole(locals=namespace, filename="<blender_console>")
if _BPY_MAIN_OWN:
@@ -110,9 +113,6 @@ def execute(context):
except:
return {'CANCELLED'}
- if sc.console_type != 'PYTHON':
- return {'CANCELLED'}
-
console, stdout, stderr = get_console(hash(context.region))
# redirect output
@@ -161,6 +161,10 @@ def execute(context):
stdout.truncate(0)
stderr.truncate(0)
+ # special exception. its possible the command loaded a new user interface
+ if hash(sc) != hash(context.space_data):
+ return
+
bpy.ops.console.scrollback_append(text=sc.prompt + line, type='INPUT')
if is_multiline:
@@ -183,8 +187,14 @@ def execute(context):
# restore the stdin
sys.stdin = stdin_backup
+ # execute any hooks
+ for func, args in execute.hooks:
+ func(*args)
+
return {'FINISHED'}
+execute.hooks = []
+
def autocomplete(context):
from console import intellisense
@@ -196,9 +206,6 @@ def autocomplete(context):
if not console:
return {'CANCELLED'}
- if sc.console_type != 'PYTHON':
- return {'CANCELLED'}
-
# dont allow the stdin to be used, can lock blender.
# note: unlikely stdin would be used for autocomp. but its possible.
stdin_backup = sys.stdin
@@ -257,14 +264,16 @@ def banner(context):
sc = context.space_data
version_string = sys.version.strip().replace('\n', ' ')
- add_scrollback(" * Python Interactive Console %s *" % version_string, 'OUTPUT')
- add_scrollback("Command History: Up/Down Arrow", 'OUTPUT')
- add_scrollback("Cursor: Left/Right Home/End", 'OUTPUT')
- add_scrollback("Remove: Backspace/Delete", 'OUTPUT')
- add_scrollback("Execute: Enter", 'OUTPUT')
- add_scrollback("Autocomplete: Ctrl+Space", 'OUTPUT')
- add_scrollback("Ctrl +/- Wheel: Zoom", 'OUTPUT')
- add_scrollback("Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bgl, blf, mathutils, geometry", 'OUTPUT')
+ add_scrollback("PYTHON INTERACTIVE CONSOLE %s" % version_string, 'OUTPUT')
+ add_scrollback("", 'OUTPUT')
+ add_scrollback("Command History: Up/Down Arrow", 'OUTPUT')
+ add_scrollback("Cursor: Left/Right Home/End", 'OUTPUT')
+ add_scrollback("Remove: Backspace/Delete", 'OUTPUT')
+ add_scrollback("Execute: Enter", 'OUTPUT')
+ add_scrollback("Autocomplete: Ctrl+Space", 'OUTPUT')
+ add_scrollback("Ctrl +/- Wheel: Zoom", 'OUTPUT')
+ add_scrollback("Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bgl, blf, mathutils", 'OUTPUT')
+ add_scrollback("Convenience Imports: from mathutils import *; from math import *", 'OUTPUT')
add_scrollback("", 'OUTPUT')
add_scrollback(" WARNING!!! Blender 2.5 API is subject to change, see API reference for more info.", 'ERROR')
add_scrollback("", 'OUTPUT')
diff --git a/release/scripts/op/fcurve_euler_filter.py b/release/scripts/op/fcurve_euler_filter.py
index b396fa0562f..6332bbe309c 100644
--- a/release/scripts/op/fcurve_euler_filter.py
+++ b/release/scripts/op/fcurve_euler_filter.py
@@ -1,7 +1,28 @@
+# ##### 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>
+
from math import *
import bpy
from mathutils import *
+
def main(context):
def cleanupEulCurve(fcv):
keys = []
@@ -12,37 +33,38 @@ def main(context):
for i in range(len(keys)):
cur = keys[i]
- prev = keys[i-1] if i > 0 else None
- next = keys[i+1] if i < len(keys)-1 else None
+ prev = keys[i - 1] if i > 0 else None
+ next = keys[i + 1] if i < len(keys) - 1 else None
if prev is None:
continue
th = pi
- if abs(prev[1][1] - cur[1][1]) >= th: # more than 180 degree jump
- fac = pi*2
+ if abs(prev[1][1] - cur[1][1]) >= th: # more than 180 degree jump
+ fac = pi * 2.0
if prev[1][1] > cur[1][1]:
- while abs(cur[1][1]-prev[1][1]) >= th: # < prev[1][1]:
+ while abs(cur[1][1] - prev[1][1]) >= th: # < prev[1][1]:
cur[0][1] += fac
cur[1][1] += fac
cur[2][1] += fac
elif prev[1][1] < cur[1][1]:
- while abs(cur[1][1]-prev[1][1]) >= th:
+ while abs(cur[1][1] - prev[1][1]) >= th:
cur[0][1] -= fac
cur[1][1] -= fac
cur[2][1] -= fac
for i in range(len(keys)):
for x in range(2):
- fcv.keyframe_points[i].handle_left[x] = keys[i][0][x]
- fcv.keyframe_points[i].co[x] = keys[i][1][x]
- fcv.keyframe_points[i].handle_right[x] = keys[i][2][x]
+ fcv.keyframe_points[i].handle_left[x] = keys[i][0][x]
+ fcv.keyframe_points[i].co[x] = keys[i][1][x]
+ fcv.keyframe_points[i].handle_right[x] = keys[i][2][x]
flist = bpy.context.active_object.animation_data.action.fcurves
for f in flist:
if f.select and f.data_path.endswith("rotation_euler"):
cleanupEulCurve(f)
+
class DiscontFilterOp(bpy.types.Operator):
"""Fixes the most common causes of gimbal lock in the fcurves of the active bone"""
bl_idname = "graph.euler_filter"
@@ -57,10 +79,11 @@ class DiscontFilterOp(bpy.types.Operator):
return {'FINISHED'}
def register():
- pass
+ bpy.utils.register_module(__name__)
+
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/image.py b/release/scripts/op/image.py
index ca7a017febd..e1d471f8254 100644
--- a/release/scripts/op/image.py
+++ b/release/scripts/op/image.py
@@ -32,13 +32,17 @@ class EditExternally(bpy.types.Operator):
def _editor_guess(self, context):
import platform
- system = platform.system()
+ try:
+ system = platform.system()
+ except UnicodeDecodeError:
+ import sys
+ system = sys.platform
image_editor = context.user_preferences.filepaths.image_editor
# use image editor in the preferences when available.
if not image_editor:
- if system == 'Windows':
+ if system in ('Windows', 'win32'):
image_editor = ["start"] # not tested!
elif system == 'Darwin':
image_editor = ["open"]
@@ -84,7 +88,7 @@ class EditExternally(bpy.types.Operator):
class SaveDirty(bpy.types.Operator):
- '''Select object matching a naming pattern'''
+ """Save all modified textures"""
bl_idname = "image.save_dirty"
bl_label = "Save Dirty"
bl_options = {'REGISTER', 'UNDO'}
@@ -105,7 +109,7 @@ class SaveDirty(bpy.types.Operator):
class ProjectEdit(bpy.types.Operator):
- '''Select object matching a naming pattern'''
+ """Edit a snapshot if the viewport in an external image editor"""
bl_idname = "image.project_edit"
bl_label = "Project Edit"
bl_options = {'REGISTER'}
@@ -139,7 +143,7 @@ class ProjectEdit(bpy.types.Operator):
# filepath = bpy.path.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
+ # TODO, have a way to check if the file is saved, assume startup.blend
tmpdir = context.user_preferences.filepaths.temporary_directory
filepath = os.path.join(tmpdir, "project_edit")
else:
@@ -170,7 +174,7 @@ class ProjectEdit(bpy.types.Operator):
class ProjectApply(bpy.types.Operator):
- '''Select object matching a naming pattern'''
+ """Project edited image back onto the object"""
bl_idname = "image.project_apply"
bl_label = "Project Apply"
bl_options = {'REGISTER'}
@@ -191,11 +195,11 @@ class ProjectApply(bpy.types.Operator):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/io_anim_bvh/__init__.py b/release/scripts/op/io_anim_bvh/__init__.py
deleted file mode 100644
index e7b922e1ceb..00000000000
--- a/release/scripts/op/io_anim_bvh/__init__.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# ##### 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>
-
-# To support reload properly, try to access a package var, if it's there, reload everything
-if "bpy" in locals():
- # only reload if we alredy loaded, highly annoying
- import sys
- reload(sys.modules.get("io_anim_bvh.import_bvh", sys))
-
-
-import bpy
-from bpy.props import *
-from io_utils import ImportHelper
-
-
-class BvhImporter(bpy.types.Operator, ImportHelper):
- '''Load a OBJ Motion Capture File'''
- bl_idname = "import_anim.bvh"
- bl_label = "Import BVH"
-
- filename_ext = ".bvh"
- filter_glob = StringProperty(default="*.bvh", options={'HIDDEN'})
-
- 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)
- frame_start = IntProperty(name="Start Frame", description="Starting frame for the animation", default=1)
- use_cyclic = 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"),
- ('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"),
- ),
- name="Rotation",
- description="Rotation conversion.",
- default='NATIVE')
-
- def execute(self, context):
- import io_anim_bvh.import_bvh
- return io_anim_bvh.import_bvh.load(self, context,
- filepath=self.filepath,
- rotate_mode=self.rotate_mode,
- scale=self.scale,
- use_cyclic=self.use_cyclic,
- frame_start=self.frame_start,
- )
-
-
-def menu_func(self, context):
- self.layout.operator(BvhImporter.bl_idname, text="Motion Capture (.bvh)")
-
-
-def register():
- bpy.types.INFO_MT_file_import.append(menu_func)
-
-
-def unregister():
- bpy.types.INFO_MT_file_import.remove(menu_func)
-
-if __name__ == "__main__":
- register()
diff --git a/release/scripts/op/io_anim_bvh/import_bvh.py b/release/scripts/op/io_anim_bvh/import_bvh.py
deleted file mode 100644
index ef0fb92aee5..00000000000
--- a/release/scripts/op/io_anim_bvh/import_bvh.py
+++ /dev/null
@@ -1,568 +0,0 @@
-# ##### 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>
-
-# Script copyright (C) Campbell Barton
-
-import math
-from math import radians
-
-import bpy
-import mathutils
-from mathutils import Vector, Euler, Matrix
-
-
-class bvh_node_class(object):
- __slots__ = (
- 'name',# bvh joint name
- 'parent',# bvh_node_class type or None for no parent
- 'children',# a list of children of this type.
- 'rest_head_world',# worldspace rest location for the head of this node
- 'rest_head_local',# localspace rest location for the head of this node
- 'rest_tail_world',# # worldspace rest location for the tail of this node
- 'rest_tail_local',# # worldspace rest location for the tail of this node
- 'channels',# list of 6 ints, -1 for an unused channel, otherwise an index for the BVH motion data lines, lock triple then rot triple
- 'rot_order',# a triple of indicies as to the order rotation is applied. [0,1,2] is x/y/z - [None, None, None] if no rotation.
- 'anim_data',# a list one tuple's one for each frame. (locx, locy, locz, rotx, roty, rotz)
- 'has_loc',# Conveinience function, bool, same as (channels[0]!=-1 or channels[1]!=-1 channels[2]!=-1)
- 'has_rot',# Conveinience function, bool, same as (channels[3]!=-1 or channels[4]!=-1 channels[5]!=-1)
- 'temp')# use this for whatever you want
-
- def __init__(self, name, rest_head_world, rest_head_local, parent, channels, rot_order):
- self.name = name
- self.rest_head_world = rest_head_world
- self.rest_head_local = rest_head_local
- self.rest_tail_world = None
- self.rest_tail_local = None
- self.parent = parent
- self.channels = channels
- self.rot_order = rot_order
-
- # convenience functions
- self.has_loc = channels[0] != -1 or channels[1] != -1 or channels[2] != -1
- self.has_rot = channels[3] != -1 or channels[4] != -1 or channels[5] != -1
-
-
- self.children = []
-
- # list of 6 length tuples: (lx,ly,lz, rx,ry,rz)
- # even if the channels arnt used they will just be zero
- #
- self.anim_data = [(0, 0, 0, 0, 0, 0)]
-
- def __repr__(self):
- return 'BVH name:"%s", rest_loc:(%.3f,%.3f,%.3f), rest_tail:(%.3f,%.3f,%.3f)' %\
- (self.name,\
- self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z,\
- self.rest_head_world.x, self.rest_head_world.y, self.rest_head_world.z)
-
-
-# Change the order rotation is applied.
-MATRIX_IDENTITY_3x3 = Matrix([1, 0, 0], [0, 1, 0], [0, 0, 1])
-MATRIX_IDENTITY_4x4 = Matrix([1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1])
-
-
-def eulerRotate(x, y, z, rot_order):
- # Clamp all values between 0 and 360, values outside this raise an error.
- mats = [Matrix.Rotation(x, 3, 'X'), Matrix.Rotation(y, 3, 'Y'), Matrix.Rotation(z, 3, 'Z')]
- return (MATRIX_IDENTITY_3x3 * mats[rot_order[0]] * (mats[rot_order[1]] * (mats[rot_order[2]]))).to_euler()
-
- # Should work but doesnt!
- '''
- 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())
- '''
-
-
-def read_bvh(context, file_path, ROT_MODE='XYZ', GLOBAL_SCALE=1.0):
- # File loading stuff
- # Open the file for importing
- file = open(file_path, 'rU')
-
- # Seperate into a list of lists, each line a list of words.
- file_lines = file.readlines()
- # Non standard carrage returns?
- if len(file_lines) == 1:
- file_lines = file_lines[0].split('\r')
-
- # Split by whitespace.
- file_lines = [ll for ll in [l.split() for l in file_lines] if ll]
-
-
- # Create Hirachy as empties
-
- if file_lines[0][0].lower() == 'hierarchy':
- #print 'Importing the BVH Hierarchy for:', file_path
- pass
- else:
- raise 'ERROR: This is not a BVH file'
-
- bvh_nodes = {None: None}
- bvh_nodes_serial = [None]
-
- channelIndex = -1
-
-
- lineIdx = 0 # An index for the file.
- while lineIdx < len(file_lines) -1:
- #...
- if file_lines[lineIdx][0].lower() == 'root' or file_lines[lineIdx][0].lower() == 'joint':
-
- # Join spaces into 1 word with underscores joining it.
- if len(file_lines[lineIdx]) > 2:
- file_lines[lineIdx][1] = '_'.join(file_lines[lineIdx][1:])
- file_lines[lineIdx] = file_lines[lineIdx][:2]
-
- # MAY NEED TO SUPPORT MULTIPLE ROOT's HERE!!!, Still unsure weather multiple roots are possible.??
-
- # Make sure the names are unique- Object names will match joint names exactly and both will be unique.
- name = file_lines[lineIdx][1]
-
- #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
- lineIdx += 1 # Incriment to the next line (Channels)
-
- # newChannel[Xposition, Yposition, Zposition, Xrotation, Yrotation, Zrotation]
- # newChannel references indecies to the motiondata,
- # if not assigned then -1 refers to the last value that will be added on loading at a value of zero, this is appended
- # We'll add a zero value onto the end of the MotionDATA so this is always refers to a value.
- my_channel = [-1, -1, -1, -1, -1, -1]
- my_rot_order = [None, None, None]
- rot_count = 0
- for channel in file_lines[lineIdx][2:]:
- channel = channel.lower()
- channelIndex += 1 # So the index points to the right channel
- if channel == 'xposition':
- my_channel[0] = channelIndex
- elif channel == 'yposition':
- my_channel[1] = channelIndex
- elif channel == 'zposition':
- my_channel[2] = channelIndex
-
- elif channel == 'xrotation':
- my_channel[3] = channelIndex
- my_rot_order[rot_count] = 0
- rot_count += 1
- elif channel == 'yrotation':
- my_channel[4] = channelIndex
- my_rot_order[rot_count] = 1
- rot_count += 1
- elif channel == 'zrotation':
- my_channel[5] = channelIndex
- my_rot_order[rot_count] = 2
- rot_count += 1
-
- channels = file_lines[lineIdx][2:]
-
- my_parent = bvh_nodes_serial[-1] # account for none
-
-
- # Apply the parents offset accumletivly
- if my_parent is None:
- rest_head_world = Vector(rest_head_local)
- else:
- rest_head_world = my_parent.rest_head_world + rest_head_local
-
- bvh_node = bvh_nodes[name] = bvh_node_class(name, rest_head_world, rest_head_local, my_parent, my_channel, my_rot_order)
-
- # If we have another child then we can call ourselves a parent, else
- bvh_nodes_serial.append(bvh_node)
-
- # 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
-
- 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
-
-
- # Just so we can remove the Parents in a uniform way- End end never has kids
- # so this is a placeholder
- bvh_nodes_serial.append(None)
-
- if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0] == '}': # == ['}']
- bvh_nodes_serial.pop() # Remove the last item
-
- if len(file_lines[lineIdx]) == 1 and file_lines[lineIdx][0].lower() == 'motion':
- #print '\nImporting motion data'
- lineIdx += 3 # Set the cursor to the first frame
- break
-
- lineIdx += 1
-
-
- # Remove the None value used for easy parent reference
- del bvh_nodes[None]
- # Dont use anymore
- del bvh_nodes_serial
-
- bvh_nodes_list = bvh_nodes.values()
-
- while lineIdx < len(file_lines):
- line = file_lines[lineIdx]
- for bvh_node in bvh_nodes_list:
- #for bvh_node in bvh_nodes_serial:
- lx = ly = lz = rx = ry = rz = 0.0
- channels = bvh_node.channels
- anim_data = bvh_node.anim_data
- if channels[0] != -1:
- lx = GLOBAL_SCALE * float(line[channels[0]])
-
- if channels[1] != -1:
- ly = GLOBAL_SCALE * float(line[channels[1]])
-
- if channels[2] != -1:
- lz = GLOBAL_SCALE * float(line[channels[2]])
-
- if channels[3] != -1 or channels[4] != -1 or channels[5] != -1:
- rx, ry, rz = float(line[channels[3]]), float(line[channels[4]]), float(line[channels[5]])
-
- if ROT_MODE != 'NATIVE':
- rx, ry, rz = eulerRotate(radians(rx), radians(ry), radians(rz), bvh_node.rot_order)
- else:
- rx, ry, rz = radians(rx), radians(ry), radians(rz)
-
- # Done importing motion data #
- anim_data.append((lx, ly, lz, rx, ry, rz))
- lineIdx += 1
-
- # Assign children
- for bvh_node in bvh_nodes.values():
- bvh_node_parent = bvh_node.parent
- if bvh_node_parent:
- bvh_node_parent.children.append(bvh_node)
-
- # Now set the tip of each bvh_node
- for bvh_node in bvh_nodes.values():
-
- if not bvh_node.rest_tail_world:
- if len(bvh_node.children) == 0:
- # could just fail here, but rare BVH files have childless nodes
- bvh_node.rest_tail_world = Vector(bvh_node.rest_head_world)
- bvh_node.rest_tail_local = Vector(bvh_node.rest_head_local)
- elif len(bvh_node.children) == 1:
- bvh_node.rest_tail_world = Vector(bvh_node.children[0].rest_head_world)
- bvh_node.rest_tail_local = bvh_node.rest_head_local + bvh_node.children[0].rest_head_local
- else:
- # allow this, see above
- #if not bvh_node.children:
- # 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))
- 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
-
- bvh_node.rest_tail_world = rest_tail_world * (1.0 / len(bvh_node.children))
- bvh_node.rest_tail_local = rest_tail_local * (1.0 / len(bvh_node.children))
-
- # Make sure tail isnt the same location as the head.
- if (bvh_node.rest_tail_local - bvh_node.rest_head_local).length <= 0.001 * GLOBAL_SCALE:
- bvh_node.rest_tail_local.y = bvh_node.rest_tail_local.y + GLOBAL_SCALE / 10
- bvh_node.rest_tail_world.y = bvh_node.rest_tail_world.y + GLOBAL_SCALE / 10
-
- return bvh_nodes
-
-
-def bvh_node_dict2objects(context, bvh_nodes, IMPORT_START_FRAME=1, IMPORT_LOOP=False):
-
- if IMPORT_START_FRAME < 1:
- IMPORT_START_FRAME = 1
-
- scn = context.scene
- scn.objects.selected = []
-
- objects = []
-
- def add_ob(name):
- ob = scn.objects.new('Empty', None)
- objects.append(ob)
- return ob
-
- # Add objects
- for name, bvh_node in bvh_nodes.items():
- bvh_node.temp = add_ob(name)
-
- # Parent the objects
- for bvh_node in bvh_nodes.values():
- bvh_node.temp.makeParent([bvh_node_child.temp for bvh_node_child in bvh_node.children], 1, 0) # ojbs, noninverse, 1 = not fast.
-
- # Offset
- for bvh_node in bvh_nodes.values():
- # Make relative to parents offset
- bvh_node.temp.loc = bvh_node.rest_head_local
-
- # Add tail objects
- for name, bvh_node in bvh_nodes.items():
- if not bvh_node.children:
- ob_end = add_ob(name + '_end')
- bvh_node.temp.makeParent([ob_end], 1, 0) # ojbs, noninverse, 1 = not fast.
- ob_end.loc = bvh_node.rest_tail_local
-
-
- # Animate the data, the last used bvh_node will do since they all have the same number of frames
- 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[frame_current]
-
- rest_head_local = bvh_node.rest_head_local
- bvh_node.temp.loc = rest_head_local + Vector((lx, ly, lz))
-
- bvh_node.temp.rot = rx, ry, rz
-
- bvh_node.temp.insertIpoKey(Blender.Object.IpoKeyTypes.LOCROT) # XXX invalid
-
- scn.update(1)
- return objects
-
-
-def bvh_node_dict2armature(context, bvh_nodes, ROT_MODE='XYZ', IMPORT_START_FRAME=1, IMPORT_LOOP=False):
-
- if IMPORT_START_FRAME < 1:
- IMPORT_START_FRAME = 1
-
- # Add the new armature,
- scn = context.scene
-#XXX scn.objects.selected = []
- for ob in scn.objects:
- ob.select = False
-
- scn.frame_set(IMPORT_START_FRAME)
-
- arm_data = bpy.data.armatures.new("MyBVH")
- arm_ob = bpy.data.objects.new("MyBVH", arm_data)
-
- scn.objects.link(arm_ob)
-
- arm_ob.select = True
- scn.objects.active = arm_ob
-
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
- bpy.ops.object.mode_set(mode='EDIT', toggle=False)
-
- # Get the average bone length for zero length bones, we may not use this.
- average_bone_length = 0.0
- nonzero_count = 0
- for bvh_node in bvh_nodes.values():
- l = (bvh_node.rest_head_local - bvh_node.rest_tail_local).length
- if l:
- average_bone_length += l
- nonzero_count += 1
-
- # Very rare cases all bones couldbe zero length???
- if not average_bone_length:
- average_bone_length = 0.1
- else:
- # Normal operation
- average_bone_length = average_bone_length / nonzero_count
-
- # XXX, annoying, remove bone.
- while arm_data.edit_bones:
- arm_ob.edit_bones.remove(arm_data.edit_bones[-1])
-
- ZERO_AREA_BONES = []
- for name, bvh_node in bvh_nodes.items():
- # New editbone
- bone = bvh_node.temp = arm_data.edit_bones.new(name)
-
- bone.head = bvh_node.rest_head_world
- bone.tail = bvh_node.rest_tail_world
-
- # ZERO AREA BONES.
- if (bone.head - bone.tail).length < 0.001:
- if bvh_node.parent:
- ofs = bvh_node.parent.rest_head_local - bvh_node.parent.rest_tail_local
- if ofs.length: # is our parent zero length also?? unlikely
- bone.tail = bone.tail + ofs
- else:
- bone.tail.y = bone.tail.y + average_bone_length
- else:
- bone.tail.y = bone.tail.y + average_bone_length
-
- ZERO_AREA_BONES.append(bone.name)
-
-
- for bvh_node in bvh_nodes.values():
- if bvh_node.parent:
- # bvh_node.temp is the Editbone
-
- # Set the bone parent
- bvh_node.temp.parent = bvh_node.parent.temp
-
- # Set the connection state
- if not bvh_node.has_loc and\
- bvh_node.parent and\
- bvh_node.parent.temp.name not in ZERO_AREA_BONES and\
- bvh_node.parent.rest_tail_local == bvh_node.rest_head_local:
- bvh_node.temp.use_connect = True
-
- # Replace the editbone with the editbone name,
- # to avoid memory errors accessing the editbone outside editmode
- for bvh_node in bvh_nodes.values():
- bvh_node.temp = bvh_node.temp.name
-
-#XXX arm_data.update()
-
- # Now Apply the animation to the armature
-
- # Get armature animation data
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
- bpy.ops.object.mode_set(mode='POSE', toggle=False)
-
- pose = arm_ob.pose
- pose_bones = pose.bones
-
- if ROT_MODE == 'NATIVE':
- eul_order_lookup = {\
- (0, 1, 2): 'XYZ',
- (0, 2, 1): 'XZY',
- (1, 0, 2): 'YXZ',
- (1, 2, 0): 'YZX',
- (2, 0, 1): 'ZXY',
- (2, 1, 0): 'ZYX'}
-
- for bvh_node in bvh_nodes.values():
- bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened.
- pose_bone = pose_bones[bone_name]
- pose_bone.rotation_mode = eul_order_lookup[tuple(bvh_node.rot_order)]
-
- elif ROT_MODE != 'QUATERNION':
- for pose_bone in pose_bones:
- pose_bone.rotation_mode = ROT_MODE
- else:
- # Quats default
- pass
-
- context.scene.update()
-
- bpy.ops.pose.select_all() # set
- bpy.ops.anim.keyframe_insert_menu(type=-4) # XXX - -4 ???
-
-
-#XXX action = Blender.Armature.NLA.NewAction("Action")
-#XXX action.setActive(arm_ob)
-
- #bpy.ops.action.new()
- #action = bpy.data.actions[-1]
-
- # arm_ob.animation_data.action = action
- action = arm_ob.animation_data.action
-
- # Replace the bvh_node.temp (currently an editbone)
- # With a tuple (pose_bone, armature_bone, bone_rest_matrix, bone_rest_matrix_inv)
- for bvh_node in bvh_nodes.values():
- bone_name = bvh_node.temp # may not be the same name as the bvh_node, could have been shortened.
- pose_bone = pose_bones[bone_name]
- rest_bone = arm_data.bones[bone_name]
- bone_rest_matrix = rest_bone.matrix_local.rotation_part()
-
-
- bone_rest_matrix_inv = Matrix(bone_rest_matrix)
- bone_rest_matrix_inv.invert()
-
- bone_rest_matrix_inv.resize4x4()
- bone_rest_matrix.resize4x4()
- bvh_node.temp = (pose_bone, bone, bone_rest_matrix, bone_rest_matrix_inv)
-
-
- # Make a dict for fast access without rebuilding a list all the time.
-
- # KEYFRAME METHOD, SLOW, USE IPOS DIRECT
- # TODO: use f-point samples instead (Aligorith)
-
- if ROT_MODE != 'QUATERNION':
- 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 frame_current in range(len(bvh_node.anim_data)-1): # skip the first frame (rest frame)
- # print frame_current
-
- # 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[frame_current + 1]
-
- if bvh_node.has_rot:
- 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(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 * Matrix.Translation(Vector((lx, ly, lz)) - bvh_node.rest_head_local)).translation_part()
-
- if bvh_node.has_loc:
- pose_bone.keyframe_insert("location")
- if bvh_node.has_rot:
- if ROT_MODE == 'QUATERNION':
- pose_bone.keyframe_insert("rotation_quaternion")
- else:
- pose_bone.keyframe_insert("rotation_euler")
-
-
- # bpy.ops.anim.keyframe_insert_menu(type=-4) # XXX - -4 ???
- bpy.ops.screen.frame_offset(delta=1)
-
- for cu in action.fcurves:
- if IMPORT_LOOP:
- pass # 2.5 doenst have cyclic now?
-
- for bez in cu.keyframe_points:
- bez.interpolation = 'LINEAR'
-
- return arm_ob
-
-
-def load(operator, context, filepath="", rotate_mode='NATIVE', scale=1.0, use_cyclic=False, frame_start=1):
- import time
- t1 = time.time()
- print('\tparsing bvh %r...' % filepath, end="")
-
- bvh_nodes = read_bvh(context, filepath,
- ROT_MODE=rotate_mode,
- GLOBAL_SCALE=scale)
-
- print('%.4f' % (time.time() - t1))
- t1 = time.time()
- print('\timporting to blender...', end="")
-
- bvh_node_dict2armature(context, bvh_nodes,
- ROT_MODE=rotate_mode,
- IMPORT_START_FRAME=frame_start,
- IMPORT_LOOP=use_cyclic)
-
- print('Done in %.4f\n' % (time.time() - t1))
-
- return {'FINISHED'}
diff --git a/release/scripts/op/io_mesh_ply/__init__.py b/release/scripts/op/io_mesh_ply/__init__.py
deleted file mode 100644
index a67afe0cc87..00000000000
--- a/release/scripts/op/io_mesh_ply/__init__.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# ##### 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 #####
-
-# To support reload properly, try to access a package var, if it's there, reload everything
-if "bpy" in locals():
- import sys
- reload(sys.modules.get("io_mesh_ply.export_ply", sys))
-
-
-import bpy
-from bpy.props import *
-from io_utils import ExportHelper
-
-
-class ExportPLY(bpy.types.Operator, ExportHelper):
- '''Export a single object as a stanford PLY with normals, colours and texture coordinates.'''
- bl_idname = "export.ply"
- bl_label = "Export PLY"
-
- filename_ext = ".ply"
-
- 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)
- use_uv_coords = BoolProperty(name="UVs", description="Exort the active UV layer", default=True)
- use_colors = BoolProperty(name="Vertex Colors", description="Exort the active vertex color layer", default=True)
-
- @classmethod
- def poll(cls, context):
- return context.active_object != None
-
- def execute(self, context):
- filepath = self.filepath
- filepath = bpy.path.ensure_ext(filepath, self.filename_ext)
- import io_mesh_ply.export_ply
- return io_mesh_ply.export_ply.save(self, context, **self.properties)
-
- def draw(self, context):
- layout = self.layout
-
- row = layout.row()
- row.prop(self, "use_modifiers")
- row.prop(self, "use_normals")
- row = layout.row()
- row.prop(self, "use_uv_coords")
- row.prop(self, "use_colors")
-
-
-def menu_func(self, context):
- self.layout.operator(ExportPLY.bl_idname, text="Stanford (.ply)")
-
-
-def register():
- bpy.types.INFO_MT_file_export.append(menu_func)
-
-
-def unregister():
- bpy.types.INFO_MT_file_export.remove(menu_func)
-
-if __name__ == "__main__":
- register()
diff --git a/release/scripts/op/io_mesh_ply/export_ply.py b/release/scripts/op/io_mesh_ply/export_ply.py
deleted file mode 100644
index 08369a46c84..00000000000
--- a/release/scripts/op/io_mesh_ply/export_ply.py
+++ /dev/null
@@ -1,206 +0,0 @@
-# ##### 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>
-
-# Copyright (C) 2004, 2005: Bruce Merry, bmerry@cs.uct.ac.za
-# Contributors: Bruce Merry, Campbell Barton
-
-"""
-This script exports Stanford PLY files from Blender. It supports normals,
-colours, and texture coordinates per face or per vertex.
-Only one mesh can be exported at a time.
-"""
-
-import bpy
-import os
-
-
-def save(operator, context, filepath="", use_modifiers=True, use_normals=True, use_uv_coords=True, use_colors=True):
-
- def rvec3d(v):
- return round(v[0], 6), round(v[1], 6), round(v[2], 6)
-
-
- def rvec2d(v):
- return round(v[0], 6), round(v[1], 6)
-
- scene = context.scene
- obj = context.object
-
- if not obj:
- raise Exception("Error, Select 1 active object")
-
- file = open(filepath, 'w')
-
- if scene.objects.active:
- bpy.ops.object.mode_set(mode='OBJECT')
-
- if use_modifiers:
- mesh = obj.create_mesh(scene, True, 'PREVIEW')
- else:
- mesh = obj.data
-
- if not mesh:
- raise Exception("Error, could not get mesh data from active object")
-
- # mesh.transform(obj.matrix_world) # XXX
-
- faceUV = (len(mesh.uv_textures) > 0)
- vertexUV = (len(mesh.sticky) > 0)
- vertexColors = len(mesh.vertex_colors) > 0
-
- if (not faceUV) and (not vertexUV):
- use_uv_coords = False
- if not vertexColors:
- use_colors = False
-
- if not use_uv_coords:
- faceUV = vertexUV = False
- if not use_colors:
- vertexColors = False
-
- if faceUV:
- active_uv_layer = mesh.uv_textures.active
- if not active_uv_layer:
- use_uv_coords = False
- faceUV = None
- else:
- active_uv_layer = active_uv_layer.data
-
- if vertexColors:
- active_col_layer = mesh.vertex_colors.active
- if not active_col_layer:
- use_colors = False
- vertexColors = None
- else:
- active_col_layer = active_col_layer.data
-
- # incase
- color = uvcoord = uvcoord_key = normal = normal_key = None
-
- mesh_verts = mesh.vertices # save a lookup
- ply_verts = [] # list of dictionaries
- # vdict = {} # (index, normal, uv) -> new index
- vdict = [{} for i in range(len(mesh_verts))]
- ply_faces = [[] for f in range(len(mesh.faces))]
- vert_count = 0
- for i, f in enumerate(mesh.faces):
-
-
- smooth = f.use_smooth
- if not smooth:
- normal = tuple(f.normal)
- normal_key = rvec3d(normal)
-
- if faceUV:
- uv = active_uv_layer[i]
- uv = uv.uv1, uv.uv2, uv.uv3, uv.uv4 # XXX - crufty :/
- if vertexColors:
- col = active_col_layer[i]
- col = col.color1, col.color2, col.color3, col.color4
-
- f_verts = f.vertices
-
- pf = ply_faces[i]
- for j, vidx in enumerate(f_verts):
- v = mesh_verts[vidx]
-
- if smooth:
- normal = tuple(v.normal)
- normal_key = rvec3d(normal)
-
- if faceUV:
- uvcoord = uv[j][0], 1.0 - uv[j][1]
- uvcoord_key = rvec2d(uvcoord)
- elif vertexUV:
- uvcoord = v.uvco[0], 1.0 - v.uvco[1]
- uvcoord_key = rvec2d(uvcoord)
-
- if vertexColors:
- color = col[j]
- color = int(color[0] * 255.0), int(color[1] * 255.0), int(color[2] * 255.0)
-
-
- key = normal_key, uvcoord_key, color
-
- vdict_local = vdict[vidx]
- pf_vidx = vdict_local.get(key) # Will be None initially
-
- if pf_vidx is None: # same as vdict_local.has_key(key)
- pf_vidx = vdict_local[key] = vert_count
- ply_verts.append((vidx, normal, uvcoord, color))
- vert_count += 1
-
- pf.append(pf_vidx)
-
- file.write('ply\n')
- file.write('format ascii 1.0\n')
- file.write('comment Created by Blender %s - www.blender.org, source file: %r\n' % (bpy.app.version_string, os.path.basename(bpy.data.filepath)))
-
- file.write('element vertex %d\n' % len(ply_verts))
-
- file.write('property float x\n')
- file.write('property float y\n')
- file.write('property float z\n')
-
- if use_normals:
- file.write('property float nx\n')
- file.write('property float ny\n')
- file.write('property float nz\n')
- if use_uv_coords:
- file.write('property float s\n')
- file.write('property float t\n')
- if use_colors:
- file.write('property uchar red\n')
- file.write('property uchar green\n')
- file.write('property uchar blue\n')
-
- file.write('element face %d\n' % len(mesh.faces))
- file.write('property list uchar uint vertex_indices\n')
- file.write('end_header\n')
-
- for i, v in enumerate(ply_verts):
- file.write('%.6f %.6f %.6f ' % tuple(mesh_verts[v[0]].co)) # co
- if use_normals:
- file.write('%.6f %.6f %.6f ' % v[1]) # no
- if use_uv_coords:
- file.write('%.6f %.6f ' % v[2]) # uv
- if use_colors:
- file.write('%u %u %u' % v[3]) # col
- file.write('\n')
-
- for pf in ply_faces:
- if len(pf) == 3:
- file.write('3 %d %d %d\n' % tuple(pf))
- else:
- file.write('4 %d %d %d %d\n' % tuple(pf))
-
- file.close()
- print("writing %r done" % filepath)
-
- if use_modifiers:
- bpy.data.meshes.remove(mesh)
-
- # XXX
- """
- if is_editmode:
- Blender.Window.EditMode(1, '', 0)
- """
-
- return {'FINISHED'}
diff --git a/release/scripts/op/io_scene_3ds/__init__.py b/release/scripts/op/io_scene_3ds/__init__.py
deleted file mode 100644
index 139a88209d2..00000000000
--- a/release/scripts/op/io_scene_3ds/__init__.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# ##### 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>
-
-# To support reload properly, try to access a package var, if it's there, reload everything
-if "bpy" in locals():
- import sys
- reload(sys.modules.get("io_scene_3ds.import_3ds", sys))
- reload(sys.modules.get("io_scene_3ds.export_3ds", sys))
-
-
-import bpy
-from bpy.props import *
-from io_utils import ImportHelper, ExportHelper
-
-
-class Import3DS(bpy.types.Operator, ImportHelper):
- '''Import from 3DS file format (.3ds)'''
- bl_idname = "import_scene.autodesk_3ds"
- bl_label = 'Import 3DS'
-
- filename_ext = ".3ds"
- filter_glob = StringProperty(default="*.3ds", options={'HIDDEN'})
-
- constrain_size = 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)
- use_image_search = BoolProperty(name="Image Search", description="Search subdirectories for any assosiated images (Warning, may be slow)", default=True)
- use_apply_transform = BoolProperty(name="Apply Transform", description="Workaround for object transformations importing incorrectly", default=False)
-
- def execute(self, context):
- import io_scene_3ds.import_3ds
- return io_scene_3ds.import_3ds.load(self, context, **self.properties)
-
-
-class Export3DS(bpy.types.Operator, ExportHelper):
- '''Export to 3DS file format (.3ds)'''
- bl_idname = "export_scene.autodesk_3ds"
- bl_label = 'Export 3DS'
-
- filename_ext = ".3ds"
-
- def execute(self, context):
- import io_scene_3ds.export_3ds
- return io_scene_3ds.export_3ds.save(self, context, **self.properties)
-
-
-# Add to a menu
-def menu_func_export(self, context):
- self.layout.operator(Export3DS.bl_idname, text="3D Studio (.3ds)")
-
-def menu_func_import(self, context):
- self.layout.operator(Import3DS.bl_idname, text="3D Studio (.3ds)")
-
-def register():
- bpy.types.INFO_MT_file_import.append(menu_func_import)
- bpy.types.INFO_MT_file_export.append(menu_func_export)
-
-
-def unregister():
- bpy.types.INFO_MT_file_import.remove(menu_func_import)
- bpy.types.INFO_MT_file_export.remove(menu_func_export)
-
-# NOTES:
-# why add 1 extra vertex? and remove it when done? - "Answer - eekadoodle - would need to re-order UV's without this since face order isnt always what we give blender, BMesh will solve :D"
-# disabled scaling to size, this requires exposing bb (easy) and understanding how it works (needs some time)
-
-if __name__ == "__main__":
- register()
-
diff --git a/release/scripts/op/io_scene_3ds/export_3ds.py b/release/scripts/op/io_scene_3ds/export_3ds.py
deleted file mode 100644
index 0cbb4347dda..00000000000
--- a/release/scripts/op/io_scene_3ds/export_3ds.py
+++ /dev/null
@@ -1,1044 +0,0 @@
-# ##### 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>
-
-# Script copyright (C) Bob Holcomb
-# Contributors: Campbell Barton, Bob Holcomb, Richard Lärkäng, Damien McGinnes, Mark Stijnman
-
-"""
-Exporting is based on 3ds loader from www.gametutorials.com(Thanks DigiBen) and using information
-from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode.
-"""
-
-######################################################
-# Data Structures
-######################################################
-
-#Some of the chunks that we will export
-#----- Primary Chunk, at the beginning of each file
-PRIMARY= 0x4D4D
-
-#------ Main Chunks
-OBJECTINFO = 0x3D3D #This gives the version of the mesh and is found right before the material and object information
-VERSION = 0x0002 #This gives the version of the .3ds file
-KFDATA = 0xB000 #This is the header for all of the key frame info
-
-#------ sub defines of OBJECTINFO
-MATERIAL=45055 #0xAFFF // This stored the texture info
-OBJECT=16384 #0x4000 // This stores the faces, vertices, etc...
-
-#>------ sub defines of MATERIAL
-MATNAME = 0xA000 # This holds the material name
-MATAMBIENT = 0xA010 # Ambient color of the object/material
-MATDIFFUSE = 0xA020 # This holds the color of the object/material
-MATSPECULAR = 0xA030 # SPecular color of the object/material
-MATSHINESS = 0xA040 # ??
-MATMAP = 0xA200 # This is a header for a new material
-MATMAPFILE = 0xA300 # This holds the file name of the texture
-
-RGB1= 0x0011
-RGB2= 0x0012
-
-#>------ sub defines of OBJECT
-OBJECT_MESH = 0x4100 # This lets us know that we are reading a new object
-OBJECT_LIGHT = 0x4600 # This lets un know we are reading a light object
-OBJECT_CAMERA= 0x4700 # This lets un know we are reading a camera object
-
-#>------ sub defines of CAMERA
-OBJECT_CAM_RANGES= 0x4720 # The camera range values
-
-#>------ sub defines of OBJECT_MESH
-OBJECT_VERTICES = 0x4110 # The objects vertices
-OBJECT_FACES = 0x4120 # The objects faces
-OBJECT_MATERIAL = 0x4130 # This is found if the object has a material, either texture map or color
-OBJECT_UV = 0x4140 # The UV texture coordinates
-OBJECT_TRANS_MATRIX = 0x4160 # The Object Matrix
-
-#>------ sub defines of KFDATA
-KFDATA_KFHDR = 0xB00A
-KFDATA_KFSEG = 0xB008
-KFDATA_KFCURTIME = 0xB009
-KFDATA_OBJECT_NODE_TAG = 0xB002
-
-#>------ sub defines of OBJECT_NODE_TAG
-OBJECT_NODE_ID = 0xB030
-OBJECT_NODE_HDR = 0xB010
-OBJECT_PIVOT = 0xB013
-OBJECT_INSTANCE_NAME = 0xB011
-POS_TRACK_TAG = 0xB020
-ROT_TRACK_TAG = 0xB021
-SCL_TRACK_TAG = 0xB022
-
-import struct
-
-# So 3ds max can open files, limit names to 12 in length
-# this is verry annoying for filenames!
-name_unique = []
-name_mapping = {}
-def sane_name(name):
- name_fixed = name_mapping.get(name)
- if name_fixed is not None:
- return name_fixed
-
- new_name = name[:12]
-
- i = 0
-
- while new_name in name_unique:
- new_name = new_name[:-4] + '.%.3d' % i
- i+=1
-
- name_unique.append(new_name)
- name_mapping[name] = new_name
- return new_name
-
-def uv_key(uv):
- return round(uv[0], 6), round(uv[1], 6)
-# return round(uv.x, 6), round(uv.y, 6)
-
-# size defines:
-SZ_SHORT = 2
-SZ_INT = 4
-SZ_FLOAT = 4
-
-class _3ds_short(object):
- '''Class representing a short (2-byte integer) for a 3ds file.
- *** This looks like an unsigned short H is unsigned from the struct docs - Cam***'''
- __slots__ = 'value'
- def __init__(self, val=0):
- self.value=val
-
- def get_size(self):
- return SZ_SHORT
-
- def write(self,file):
- file.write(struct.pack("<H", self.value))
-
- def __str__(self):
- return str(self.value)
-
-class _3ds_int(object):
- '''Class representing an int (4-byte integer) for a 3ds file.'''
- __slots__ = 'value'
- def __init__(self, val=0):
- self.value=val
-
- def get_size(self):
- return SZ_INT
-
- def write(self,file):
- file.write(struct.pack("<I", self.value))
-
- def __str__(self):
- return str(self.value)
-
-class _3ds_float(object):
- '''Class representing a 4-byte IEEE floating point number for a 3ds file.'''
- __slots__ = 'value'
- def __init__(self, val=0.0):
- self.value=val
-
- def get_size(self):
- return SZ_FLOAT
-
- def write(self,file):
- file.write(struct.pack("<f", self.value))
-
- def __str__(self):
- return str(self.value)
-
-
-class _3ds_string(object):
- '''Class representing a zero-terminated string for a 3ds file.'''
- __slots__ = 'value'
- def __init__(self, val=""):
- self.value=val
-
- def get_size(self):
- return (len(self.value)+1)
-
- def write(self,file):
- binary_format = "<%ds" % (len(self.value)+1)
- file.write(struct.pack(binary_format, self.value))
-
- def __str__(self):
- return self.value
-
-class _3ds_point_3d(object):
- '''Class representing a three-dimensional point for a 3ds file.'''
- __slots__ = 'x','y','z'
- def __init__(self, point=(0.0,0.0,0.0)):
- self.x, self.y, self.z = point
-
- def get_size(self):
- return 3*SZ_FLOAT
-
- def write(self,file):
- file.write(struct.pack('<3f', self.x, self.y, self.z))
-
- def __str__(self):
- return '(%f, %f, %f)' % (self.x, self.y, self.z)
-
-# Used for writing a track
-"""
-class _3ds_point_4d(object):
- '''Class representing a four-dimensional point for a 3ds file, for instance a quaternion.'''
- __slots__ = 'x','y','z','w'
- def __init__(self, point=(0.0,0.0,0.0,0.0)):
- self.x, self.y, self.z, self.w = point
-
- def get_size(self):
- return 4*SZ_FLOAT
-
- def write(self,file):
- data=struct.pack('<4f', self.x, self.y, self.z, self.w)
- file.write(data)
-
- def __str__(self):
- return '(%f, %f, %f, %f)' % (self.x, self.y, self.z, self.w)
-"""
-
-class _3ds_point_uv(object):
- '''Class representing a UV-coordinate for a 3ds file.'''
- __slots__ = 'uv'
- def __init__(self, point=(0.0,0.0)):
- self.uv = point
-
- def __cmp__(self, other):
- return cmp(self.uv,other.uv)
-
- def get_size(self):
- return 2*SZ_FLOAT
-
- def write(self,file):
- data=struct.pack('<2f', self.uv[0], self.uv[1])
- file.write(data)
-
- def __str__(self):
- return '(%g, %g)' % self.uv
-
-class _3ds_rgb_color(object):
- '''Class representing a (24-bit) rgb color for a 3ds file.'''
- __slots__ = 'r','g','b'
- def __init__(self, col=(0,0,0)):
- self.r, self.g, self.b = col
-
- def get_size(self):
- return 3
-
- def write(self,file):
- file.write( struct.pack('<3B', int(255*self.r), int(255*self.g), int(255*self.b) ) )
-# file.write( struct.pack('<3c', chr(int(255*self.r)), chr(int(255*self.g)), chr(int(255*self.b)) ) )
-
- def __str__(self):
- return '{%f, %f, %f}' % (self.r, self.g, self.b)
-
-class _3ds_face(object):
- '''Class representing a face for a 3ds file.'''
- __slots__ = 'vindex'
- def __init__(self, vindex):
- self.vindex = vindex
-
- def get_size(self):
- return 4*SZ_SHORT
-
- def write(self,file):
- # The last zero is only used by 3d studio
- file.write(struct.pack("<4H", self.vindex[0],self.vindex[1], self.vindex[2], 0))
-
- def __str__(self):
- return '[%d %d %d]' % (self.vindex[0],self.vindex[1], self.vindex[2])
-
-class _3ds_array(object):
- '''Class representing an array of variables for a 3ds file.
-
- Consists of a _3ds_short to indicate the number of items, followed by the items themselves.
- '''
- __slots__ = 'values', 'size'
- def __init__(self):
- self.values=[]
- self.size=SZ_SHORT
-
- # add an item:
- def add(self,item):
- self.values.append(item)
- self.size+=item.get_size()
-
- def get_size(self):
- return self.size
-
- def write(self,file):
- _3ds_short(len(self.values)).write(file)
- #_3ds_int(len(self.values)).write(file)
- for value in self.values:
- value.write(file)
-
- # To not overwhelm the output in a dump, a _3ds_array only
- # outputs the number of items, not all of the actual items.
- def __str__(self):
- return '(%d items)' % len(self.values)
-
-class _3ds_named_variable(object):
- '''Convenience class for named variables.'''
-
- __slots__ = 'value', 'name'
- def __init__(self, name, val=None):
- self.name=name
- self.value=val
-
- def get_size(self):
- if self.value is None:
- return 0
- else:
- return self.value.get_size()
-
- def write(self, file):
- if self.value is not None:
- self.value.write(file)
-
- def dump(self,indent):
- if self.value is not None:
- spaces=""
- for i in range(indent):
- spaces += " "
- if (self.name!=""):
- print(spaces, self.name, " = ", self.value)
- else:
- print(spaces, "[unnamed]", " = ", self.value)
-
-
-#the chunk class
-class _3ds_chunk(object):
- '''Class representing a chunk in a 3ds file.
-
- Chunks contain zero or more variables, followed by zero or more subchunks.
- '''
- __slots__ = 'ID', 'size', 'variables', 'subchunks'
- def __init__(self, id=0):
- self.ID=_3ds_short(id)
- self.size=_3ds_int(0)
- self.variables=[]
- self.subchunks=[]
-
- def set_ID(id):
- self.ID=_3ds_short(id)
-
- def add_variable(self, name, var):
- '''Add a named variable.
-
- The name is mostly for debugging purposes.'''
- self.variables.append(_3ds_named_variable(name,var))
-
- def add_subchunk(self, chunk):
- '''Add a subchunk.'''
- self.subchunks.append(chunk)
-
- def get_size(self):
- '''Calculate the size of the chunk and return it.
-
- The sizes of the variables and subchunks are used to determine this chunk\'s size.'''
- tmpsize=self.ID.get_size()+self.size.get_size()
- for variable in self.variables:
- tmpsize+=variable.get_size()
- for subchunk in self.subchunks:
- tmpsize+=subchunk.get_size()
- self.size.value=tmpsize
- return self.size.value
-
- def write(self, file):
- '''Write the chunk to a file.
-
- Uses the write function of the variables and the subchunks to do the actual work.'''
- #write header
- self.ID.write(file)
- self.size.write(file)
- for variable in self.variables:
- variable.write(file)
- for subchunk in self.subchunks:
- subchunk.write(file)
-
-
- def dump(self, indent=0):
- '''Write the chunk to a file.
-
- Dump is used for debugging purposes, to dump the contents of a chunk to the standard output.
- Uses the dump function of the named variables and the subchunks to do the actual work.'''
- spaces=""
- for i in range(indent):
- spaces += " "
- print(spaces, "ID=", hex(self.ID.value), "size=", self.get_size())
- for variable in self.variables:
- variable.dump(indent+1)
- for subchunk in self.subchunks:
- subchunk.dump(indent+1)
-
-
-
-######################################################
-# EXPORT
-######################################################
-
-def get_material_images(material):
- # blender utility func.
- if material:
- return [s.texture.image for s in material.texture_slots if s and s.texture.type == 'IMAGE' and s.texture.image]
-
- return []
-# images = []
-# if material:
-# for mtex in material.getTextures():
-# if mtex and mtex.tex.type == Blender.Texture.Types.IMAGE:
-# image = mtex.tex.image
-# if image:
-# images.append(image) # maye want to include info like diffuse, spec here.
-# return images
-
-
-def make_material_subchunk(id, color):
- '''Make a material subchunk.
-
- Used for color subchunks, such as diffuse color or ambient color subchunks.'''
- mat_sub = _3ds_chunk(id)
- col1 = _3ds_chunk(RGB1)
- col1.add_variable("color1", _3ds_rgb_color(color))
- mat_sub.add_subchunk(col1)
-# optional:
-# col2 = _3ds_chunk(RGB1)
-# col2.add_variable("color2", _3ds_rgb_color(color))
-# mat_sub.add_subchunk(col2)
- return mat_sub
-
-
-def make_material_texture_chunk(id, images):
- """Make Material Map texture chunk
- """
- mat_sub = _3ds_chunk(id)
-
- def add_image(img):
- 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)
-
- for image in images:
- add_image(image)
-
- return mat_sub
-
-def make_material_chunk(material, image):
- '''Make a material chunk out of a blender material.'''
- material_chunk = _3ds_chunk(MATERIAL)
- name = _3ds_chunk(MATNAME)
-
- if material: name_str = material.name
- else: name_str = 'None'
- if image: name_str += image.name
-
- name.add_variable("name", _3ds_string(sane_name(name_str)))
- material_chunk.add_subchunk(name)
-
- if not material:
- material_chunk.add_subchunk(make_material_subchunk(MATAMBIENT, (0,0,0) ))
- material_chunk.add_subchunk(make_material_subchunk(MATDIFFUSE, (.8, .8, .8) ))
- material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, (1,1,1) ))
-
- else:
- material_chunk.add_subchunk(make_material_subchunk(MATAMBIENT, [a*material.ambient for a in material.diffuse_color] ))
-# material_chunk.add_subchunk(make_material_subchunk(MATAMBIENT, [a*material.amb for a in material.rgbCol] ))
- material_chunk.add_subchunk(make_material_subchunk(MATDIFFUSE, material.diffuse_color))
-# material_chunk.add_subchunk(make_material_subchunk(MATDIFFUSE, material.rgbCol))
- material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, material.specular_color))
-# material_chunk.add_subchunk(make_material_subchunk(MATSPECULAR, material.specCol))
-
- images = get_material_images(material) # can be None
- if image: images.append(image)
-
- if images:
- material_chunk.add_subchunk(make_material_texture_chunk(MATMAP, images))
-
- return material_chunk
-
-class tri_wrapper(object):
- '''Class representing a triangle.
-
- Used when converting faces to triangles'''
-
- __slots__ = 'vertex_index', 'mat', 'image', 'faceuvs', 'offset'
- def __init__(self, vindex=(0,0,0), mat=None, image=None, faceuvs=None):
- self.vertex_index= vindex
- self.mat= mat
- self.image= image
- self.faceuvs= faceuvs
- self.offset= [0, 0, 0] # offset indicies
-
-
-def extract_triangles(mesh):
- '''Extract triangles from a mesh.
-
- If the mesh contains quads, they will be split into triangles.'''
- tri_list = []
- do_uv = len(mesh.uv_textures)
-# do_uv = mesh.faceUV
-
-# if not do_uv:
-# face_uv = None
-
- img = None
- for i, face in enumerate(mesh.faces):
- f_v = face.vertices
-# f_v = face.v
-
- uf = mesh.uv_textures.active.data[i] if do_uv else None
-
- if do_uv:
- f_uv = uf.uv
- # f_uv = (uf.uv1, uf.uv2, uf.uv3, uf.uv4) if face.vertices[3] else (uf.uv1, uf.uv2, uf.uv3)
-# f_uv = face.uv
- img = uf.image if uf else None
-# img = face.image
- if img: img = img.name
-
- # if f_v[3] == 0:
- if len(f_v)==3:
- new_tri = tri_wrapper((f_v[0], f_v[1], f_v[2]), face.material_index, img)
-# new_tri = tri_wrapper((f_v[0].index, f_v[1].index, f_v[2].index), face.mat, img)
- if (do_uv): new_tri.faceuvs= uv_key(f_uv[0]), uv_key(f_uv[1]), uv_key(f_uv[2])
- tri_list.append(new_tri)
-
- else: #it's a quad
- new_tri = tri_wrapper((f_v[0], f_v[1], f_v[2]), face.material_index, img)
-# new_tri = tri_wrapper((f_v[0].index, f_v[1].index, f_v[2].index), face.mat, img)
- new_tri_2 = tri_wrapper((f_v[0], f_v[2], f_v[3]), face.material_index, img)
-# new_tri_2 = tri_wrapper((f_v[0].index, f_v[2].index, f_v[3].index), face.mat, img)
-
- if (do_uv):
- new_tri.faceuvs= uv_key(f_uv[0]), uv_key(f_uv[1]), uv_key(f_uv[2])
- new_tri_2.faceuvs= uv_key(f_uv[0]), uv_key(f_uv[2]), uv_key(f_uv[3])
-
- tri_list.append( new_tri )
- tri_list.append( new_tri_2 )
-
- return tri_list
-
-
-def remove_face_uv(verts, tri_list):
- '''Remove face UV coordinates from a list of triangles.
-
- Since 3ds files only support one pair of uv coordinates for each vertex, face uv coordinates
- need to be converted to vertex uv coordinates. That means that vertices need to be duplicated when
- there are multiple uv coordinates per vertex.'''
-
- # initialize a list of UniqueLists, one per vertex:
- #uv_list = [UniqueList() for i in xrange(len(verts))]
- unique_uvs= [{} for i in range(len(verts))]
-
- # for each face uv coordinate, add it to the UniqueList of the vertex
- for tri in tri_list:
- for i in range(3):
- # store the index into the UniqueList for future reference:
- # offset.append(uv_list[tri.vertex_index[i]].add(_3ds_point_uv(tri.faceuvs[i])))
-
- context_uv_vert= unique_uvs[tri.vertex_index[i]]
- uvkey= tri.faceuvs[i]
-
- offset_index__uv_3ds = context_uv_vert.get(uvkey)
-
- if not offset_index__uv_3ds:
- offset_index__uv_3ds = context_uv_vert[uvkey] = len(context_uv_vert), _3ds_point_uv(uvkey)
-
- tri.offset[i] = offset_index__uv_3ds[0]
-
-
-
- # At this point, each vertex has a UniqueList containing every uv coordinate that is associated with it
- # only once.
-
- # Now we need to duplicate every vertex as many times as it has uv coordinates and make sure the
- # faces refer to the new face indices:
- vert_index = 0
- vert_array = _3ds_array()
- uv_array = _3ds_array()
- index_list = []
- for i,vert in enumerate(verts):
- index_list.append(vert_index)
-
- pt = _3ds_point_3d(vert.co) # reuse, should be ok
- uvmap = [None] * len(unique_uvs[i])
- for ii, uv_3ds in unique_uvs[i].values():
- # add a vertex duplicate to the vertex_array for every uv associated with this vertex:
- vert_array.add(pt)
- # add the uv coordinate to the uv array:
- # This for loop does not give uv's ordered by ii, so we create a new map
- # and add the uv's later
- # uv_array.add(uv_3ds)
- uvmap[ii] = uv_3ds
-
- # Add the uv's in the correct order
- for uv_3ds in uvmap:
- # add the uv coordinate to the uv array:
- uv_array.add(uv_3ds)
-
- vert_index += len(unique_uvs[i])
-
- # Make sure the triangle vertex indices now refer to the new vertex list:
- for tri in tri_list:
- for i in range(3):
- tri.offset[i]+=index_list[tri.vertex_index[i]]
- tri.vertex_index= tri.offset
-
- return vert_array, uv_array, tri_list
-
-def make_faces_chunk(tri_list, mesh, materialDict):
- '''Make a chunk for the faces.
-
- Also adds subchunks assigning materials to all faces.'''
-
- materials = mesh.materials
- if not materials:
- mat = None
-
- face_chunk = _3ds_chunk(OBJECT_FACES)
- face_list = _3ds_array()
-
-
- if len(mesh.uv_textures):
-# if mesh.faceUV:
- # Gather materials used in this mesh - mat/image pairs
- unique_mats = {}
- for i,tri in enumerate(tri_list):
-
- face_list.add(_3ds_face(tri.vertex_index))
-
- if materials:
- mat = materials[tri.mat]
- if mat: mat = mat.name
-
- img = tri.image
-
- try:
- context_mat_face_array = unique_mats[mat, img][1]
- except:
-
- if mat: name_str = mat
- else: name_str = 'None'
- if img: name_str += img
-
- context_mat_face_array = _3ds_array()
- unique_mats[mat, img] = _3ds_string(sane_name(name_str)), context_mat_face_array
-
-
- context_mat_face_array.add(_3ds_short(i))
- # obj_material_faces[tri.mat].add(_3ds_short(i))
-
- face_chunk.add_variable("faces", face_list)
- for mat_name, mat_faces in unique_mats.values():
- obj_material_chunk=_3ds_chunk(OBJECT_MATERIAL)
- obj_material_chunk.add_variable("name", mat_name)
- obj_material_chunk.add_variable("face_list", mat_faces)
- face_chunk.add_subchunk(obj_material_chunk)
-
- else:
-
- obj_material_faces=[]
- obj_material_names=[]
- for m in materials:
- if m:
- obj_material_names.append(_3ds_string(sane_name(m.name)))
- obj_material_faces.append(_3ds_array())
- n_materials = len(obj_material_names)
-
- for i,tri in enumerate(tri_list):
- face_list.add(_3ds_face(tri.vertex_index))
- if (tri.mat < n_materials):
- obj_material_faces[tri.mat].add(_3ds_short(i))
-
- face_chunk.add_variable("faces", face_list)
- for i in range(n_materials):
- obj_material_chunk=_3ds_chunk(OBJECT_MATERIAL)
- obj_material_chunk.add_variable("name", obj_material_names[i])
- obj_material_chunk.add_variable("face_list", obj_material_faces[i])
- face_chunk.add_subchunk(obj_material_chunk)
-
- return face_chunk
-
-def make_vert_chunk(vert_array):
- '''Make a vertex chunk out of an array of vertices.'''
- vert_chunk = _3ds_chunk(OBJECT_VERTICES)
- vert_chunk.add_variable("vertices",vert_array)
- return vert_chunk
-
-def make_uv_chunk(uv_array):
- '''Make a UV chunk out of an array of UVs.'''
- uv_chunk = _3ds_chunk(OBJECT_UV)
- uv_chunk.add_variable("uv coords", uv_array)
- return uv_chunk
-
-def make_mesh_chunk(mesh, materialDict):
- '''Make a chunk out of a Blender mesh.'''
-
- # Extract the triangles from the mesh:
- tri_list = extract_triangles(mesh)
-
- if len(mesh.uv_textures):
-# if mesh.faceUV:
- # Remove the face UVs and convert it to vertex UV:
- vert_array, uv_array, tri_list = remove_face_uv(mesh.vertices, tri_list)
- else:
- # Add the vertices to the vertex array:
- vert_array = _3ds_array()
- for vert in mesh.vertices:
- vert_array.add(_3ds_point_3d(vert.co))
- # If the mesh has vertex UVs, create an array of UVs:
- if len(mesh.sticky):
-# if mesh.vertexUV:
- uv_array = _3ds_array()
- for uv in mesh.sticky:
-# for vert in mesh.vertices:
- uv_array.add(_3ds_point_uv(uv.co))
-# uv_array.add(_3ds_point_uv(vert.uvco))
- else:
- # no UV at all:
- uv_array = None
-
- # create the chunk:
- mesh_chunk = _3ds_chunk(OBJECT_MESH)
-
- # add vertex chunk:
- mesh_chunk.add_subchunk(make_vert_chunk(vert_array))
- # add faces chunk:
-
- mesh_chunk.add_subchunk(make_faces_chunk(tri_list, mesh, materialDict))
-
- # if available, add uv chunk:
- if uv_array:
- mesh_chunk.add_subchunk(make_uv_chunk(uv_array))
-
- return mesh_chunk
-
-""" # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
-def make_kfdata(start=0, stop=0, curtime=0):
- '''Make the basic keyframe data chunk'''
- kfdata = _3ds_chunk(KFDATA)
-
- kfhdr = _3ds_chunk(KFDATA_KFHDR)
- kfhdr.add_variable("revision", _3ds_short(0))
- # Not really sure what filename is used for, but it seems it is usually used
- # to identify the program that generated the .3ds:
- kfhdr.add_variable("filename", _3ds_string("Blender"))
- kfhdr.add_variable("animlen", _3ds_int(stop-start))
-
- kfseg = _3ds_chunk(KFDATA_KFSEG)
- kfseg.add_variable("start", _3ds_int(start))
- kfseg.add_variable("stop", _3ds_int(stop))
-
- kfcurtime = _3ds_chunk(KFDATA_KFCURTIME)
- kfcurtime.add_variable("curtime", _3ds_int(curtime))
-
- kfdata.add_subchunk(kfhdr)
- kfdata.add_subchunk(kfseg)
- kfdata.add_subchunk(kfcurtime)
- return kfdata
-"""
-
-"""
-def make_track_chunk(ID, obj):
- '''Make a chunk for track data.
-
- Depending on the ID, this will construct a position, rotation or scale track.'''
- track_chunk = _3ds_chunk(ID)
- track_chunk.add_variable("track_flags", _3ds_short())
- track_chunk.add_variable("unknown", _3ds_int())
- track_chunk.add_variable("unknown", _3ds_int())
- track_chunk.add_variable("nkeys", _3ds_int(1))
- # Next section should be repeated for every keyframe, but for now, animation is not actually supported.
- track_chunk.add_variable("tcb_frame", _3ds_int(0))
- track_chunk.add_variable("tcb_flags", _3ds_short())
- if obj.type=='Empty':
- if ID==POS_TRACK_TAG:
- # position vector:
- track_chunk.add_variable("position", _3ds_point_3d(obj.getLocation()))
- elif ID==ROT_TRACK_TAG:
- # rotation (quaternion, angle first, followed by axis):
- q = obj.getEuler().to_quat()
- track_chunk.add_variable("rotation", _3ds_point_4d((q.angle, q.axis[0], q.axis[1], q.axis[2])))
- elif ID==SCL_TRACK_TAG:
- # scale vector:
- track_chunk.add_variable("scale", _3ds_point_3d(obj.getSize()))
- else:
- # meshes have their transformations applied before
- # exporting, so write identity transforms here:
- if ID==POS_TRACK_TAG:
- # position vector:
- track_chunk.add_variable("position", _3ds_point_3d((0.0,0.0,0.0)))
- elif ID==ROT_TRACK_TAG:
- # rotation (quaternion, angle first, followed by axis):
- track_chunk.add_variable("rotation", _3ds_point_4d((0.0, 1.0, 0.0, 0.0)))
- elif ID==SCL_TRACK_TAG:
- # scale vector:
- track_chunk.add_variable("scale", _3ds_point_3d((1.0, 1.0, 1.0)))
-
- return track_chunk
-"""
-
-"""
-def make_kf_obj_node(obj, name_to_id):
- '''Make a node chunk for a Blender object.
-
- Takes the Blender object as a parameter. Object id's are taken from the dictionary name_to_id.
- Blender Empty objects are converted to dummy nodes.'''
-
- name = obj.name
- # main object node chunk:
- kf_obj_node = _3ds_chunk(KFDATA_OBJECT_NODE_TAG)
- # chunk for the object id:
- obj_id_chunk = _3ds_chunk(OBJECT_NODE_ID)
- # object id is from the name_to_id dictionary:
- obj_id_chunk.add_variable("node_id", _3ds_short(name_to_id[name]))
-
- # object node header:
- obj_node_header_chunk = _3ds_chunk(OBJECT_NODE_HDR)
- # object name:
- if obj.type == 'Empty':
- # Empties are called "$$$DUMMY" and use the OBJECT_INSTANCE_NAME chunk
- # for their name (see below):
- obj_node_header_chunk.add_variable("name", _3ds_string("$$$DUMMY"))
- else:
- # Add the name:
- obj_node_header_chunk.add_variable("name", _3ds_string(sane_name(name)))
- # Add Flag variables (not sure what they do):
- obj_node_header_chunk.add_variable("flags1", _3ds_short(0))
- obj_node_header_chunk.add_variable("flags2", _3ds_short(0))
-
- # Check parent-child relationships:
- parent = obj.parent
- if (parent is None) or (parent.name not in name_to_id):
- # If no parent, or the parents name is not in the name_to_id dictionary,
- # parent id becomes -1:
- obj_node_header_chunk.add_variable("parent", _3ds_short(-1))
- else:
- # Get the parent's id from the name_to_id dictionary:
- obj_node_header_chunk.add_variable("parent", _3ds_short(name_to_id[parent.name]))
-
- # Add pivot chunk:
- obj_pivot_chunk = _3ds_chunk(OBJECT_PIVOT)
- obj_pivot_chunk.add_variable("pivot", _3ds_point_3d(obj.getLocation()))
- kf_obj_node.add_subchunk(obj_pivot_chunk)
-
- # add subchunks for object id and node header:
- kf_obj_node.add_subchunk(obj_id_chunk)
- kf_obj_node.add_subchunk(obj_node_header_chunk)
-
- # Empty objects need to have an extra chunk for the instance name:
- if obj.type == 'Empty':
- obj_instance_name_chunk = _3ds_chunk(OBJECT_INSTANCE_NAME)
- obj_instance_name_chunk.add_variable("name", _3ds_string(sane_name(name)))
- kf_obj_node.add_subchunk(obj_instance_name_chunk)
-
- # Add track chunks for position, rotation and scale:
- kf_obj_node.add_subchunk(make_track_chunk(POS_TRACK_TAG, obj))
- kf_obj_node.add_subchunk(make_track_chunk(ROT_TRACK_TAG, obj))
- kf_obj_node.add_subchunk(make_track_chunk(SCL_TRACK_TAG, obj))
-
- return kf_obj_node
-"""
-
-
-def save(operator, context, filepath=""):
- import bpy
- import time
- from io_utils import create_derived_objects, free_derived_objects
-
- '''Save the Blender scene to a 3ds file.'''
-
- # Time the export
- time1 = time.clock()
-# Blender.Window.WaitCursor(1)
-
- sce = context.scene
-
- if bpy.ops.object.mode_set.poll():
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # Initialize the main chunk (primary):
- primary = _3ds_chunk(PRIMARY)
- # Add version chunk:
- version_chunk = _3ds_chunk(VERSION)
- version_chunk.add_variable("version", _3ds_int(3))
- primary.add_subchunk(version_chunk)
-
- # init main object info chunk:
- object_info = _3ds_chunk(OBJECTINFO)
-
- ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
- # init main key frame data chunk:
- kfdata = make_kfdata()
- '''
-
- # Get all the supported objects selected in this scene:
- # ob_sel= list(sce.objects.context)
- # mesh_objects = [ (ob, me) for ob in ob_sel for me in (BPyMesh.getMeshFromObject(ob, None, True, False, sce),) if me ]
- # empty_objects = [ ob for ob in ob_sel if ob.type == 'Empty' ]
-
- # Make a list of all materials used in the selected meshes (use a dictionary,
- # each material is added once):
- materialDict = {}
- mesh_objects = []
- 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(scene, ob)
-
- if derived is None:
- continue
-
- for ob_derived, mat in derived:
-# for ob_derived, mat in getDerivedObjects(ob, False):
-
- if ob.type not in ('MESH', 'CURVE', 'SURFACE', 'TEXT', 'META'):
- continue
-
- data = ob_derived.create_mesh(scene, True, 'PREVIEW')
-# data = getMeshFromObject(ob_derived, None, True, False, sce)
- if data:
- data.transform(mat)
-# data.transform(mat, recalc_normals=False)
- mesh_objects.append((ob_derived, data))
- mat_ls = data.materials
- mat_ls_len = len(mat_ls)
-
- # get material/image tuples.
- if len(data.uv_textures):
-# if data.faceUV:
- if not mat_ls:
- mat = mat_name = None
-
- for f, uf in zip(data.faces, data.uv_textures.active.data):
- if mat_ls:
- mat_index = f.material_index
-# mat_index = f.mat
- if mat_index >= mat_ls_len:
- mat_index = f.mat = 0
- mat = mat_ls[mat_index]
- if mat: mat_name = mat.name
- else: mat_name = None
- # else there already set to none
-
- img = uf.image
-# img = f.image
- if img: img_name = img.name
- else: img_name = None
-
- materialDict.setdefault((mat_name, img_name), (mat, img) )
-
-
- else:
- for mat in mat_ls:
- if mat: # material may be None so check its not.
- materialDict.setdefault((mat.name, None), (mat, None) )
-
- # Why 0 Why!
- for f in data.faces:
- if f.material_index >= mat_ls_len:
-# if f.mat >= mat_ls_len:
- f.material_index = 0
- # f.mat = 0
-
- if free:
- free_derived_objects(ob)
-
-
- # Make material chunks for all materials used in the meshes:
- for mat_and_image in materialDict.values():
- object_info.add_subchunk(make_material_chunk(mat_and_image[0], mat_and_image[1]))
-
- # Give all objects a unique ID and build a dictionary from object name to object id:
- """
- name_to_id = {}
- for ob, data in mesh_objects:
- name_to_id[ob.name]= len(name_to_id)
- #for ob in empty_objects:
- # name_to_id[ob.name]= len(name_to_id)
- """
-
- # Create object chunks for all meshes:
- i = 0
- for ob, blender_mesh in mesh_objects:
- # create a new object chunk
- object_chunk = _3ds_chunk(OBJECT)
-
- # set the object name
- object_chunk.add_variable("name", _3ds_string(sane_name(ob.name)))
-
- # make a mesh chunk out of the mesh:
- object_chunk.add_subchunk(make_mesh_chunk(blender_mesh, materialDict))
- object_info.add_subchunk(object_chunk)
-
- ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
- # make a kf object node for the object:
- kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id))
- '''
- if not blender_mesh.users:
- bpy.data.meshes.remove(blender_mesh)
-# blender_mesh.vertices = None
-
- i+=i
-
- # Create chunks for all empties:
- ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
- for ob in empty_objects:
- # Empties only require a kf object node:
- kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id))
- pass
- '''
-
- # Add main object info chunk to primary chunk:
- primary.add_subchunk(object_info)
-
- ''' # COMMENTED OUT FOR 2.42 RELEASE!! CRASHES 3DS MAX
- # Add main keyframe data chunk to primary chunk:
- primary.add_subchunk(kfdata)
- '''
-
- # At this point, the chunk hierarchy is completely built.
-
- # Check the size:
- primary.get_size()
- # Open the file for writing:
- file = open(filepath, 'wb')
-
- # Recursively write the chunks to file:
- primary.write(file)
-
- # Close the file:
- file.close()
-
- # Clear name mapping vars, could make locals too
- name_unique[:] = []
- name_mapping.clear()
-
- # Debugging only: report the exporting time:
-# Blender.Window.WaitCursor(0)
- print("3ds export time: %.2f" % (time.clock() - time1))
-
- # Debugging only: dump the chunk hierarchy:
- #primary.dump()
-
- return {'FINISHED'}
diff --git a/release/scripts/op/io_scene_3ds/import_3ds.py b/release/scripts/op/io_scene_3ds/import_3ds.py
deleted file mode 100644
index 0eed3562b7b..00000000000
--- a/release/scripts/op/io_scene_3ds/import_3ds.py
+++ /dev/null
@@ -1,794 +0,0 @@
-# ##### 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>
-
-# Script copyright (C) Bob Holcomb
-# Contributors: Bob Holcomb, Richard L?rk?ng, Damien McGinnes, Campbell Barton, Mario Lapin
-
-import os
-import time
-import struct
-
-from io_utils import load_image
-
-import bpy
-import mathutils
-
-BOUNDS_3DS = []
-
-
-######################################################
-# Data Structures
-######################################################
-
-#Some of the chunks that we will see
-#----- Primary Chunk, at the beginning of each file
-PRIMARY = int('0x4D4D',16)
-
-#------ Main Chunks
-OBJECTINFO = 0x3D3D #This gives the version of the mesh and is found right before the material and object information
-VERSION = 0x0002 #This gives the version of the .3ds file
-EDITKEYFRAME= 0xB000 #This is the header for all of the key frame info
-
-#------ sub defines of OBJECTINFO
-MATERIAL = 45055 #0xAFFF // This stored the texture info
-OBJECT = 16384 #0x4000 // This stores the faces, vertices, etc...
-
-#>------ sub defines of MATERIAL
-#------ sub defines of MATERIAL_BLOCK
-MAT_NAME = 0xA000 # This holds the material name
-MAT_AMBIENT = 0xA010 # Ambient color of the object/material
-MAT_DIFFUSE = 0xA020 # This holds the color of the object/material
-MAT_SPECULAR = 0xA030 # SPecular color of the object/material
-MAT_SHINESS = 0xA040 # ??
-MAT_TRANSPARENCY= 0xA050 # Transparency value of material
-MAT_SELF_ILLUM = 0xA080 # Self Illumination value of material
-MAT_WIRE = 0xA085 # Only render's wireframe
-
-MAT_TEXTURE_MAP = 0xA200 # This is a header for a new texture map
-MAT_SPECULAR_MAP= 0xA204 # This is a header for a new specular map
-MAT_OPACITY_MAP = 0xA210 # This is a header for a new opacity map
-MAT_REFLECTION_MAP= 0xA220 # This is a header for a new reflection map
-MAT_BUMP_MAP = 0xA230 # This is a header for a new bump map
-MAT_MAP_FILEPATH = 0xA300 # This holds the file name of the texture
-
-MAT_FLOAT_COLOR = 0x0010 #color defined as 3 floats
-MAT_24BIT_COLOR = 0x0011 #color defined as 3 bytes
-
-#>------ sub defines of OBJECT
-OBJECT_MESH = 0x4100 # This lets us know that we are reading a new object
-OBJECT_LAMP = 0x4600 # This lets un know we are reading a light object
-OBJECT_LAMP_SPOT = 0x4610 # The light is a spotloght.
-OBJECT_LAMP_OFF = 0x4620 # The light off.
-OBJECT_LAMP_ATTENUATE = 0x4625
-OBJECT_LAMP_RAYSHADE = 0x4627
-OBJECT_LAMP_SHADOWED = 0x4630
-OBJECT_LAMP_LOCAL_SHADOW = 0x4640
-OBJECT_LAMP_LOCAL_SHADOW2 = 0x4641
-OBJECT_LAMP_SEE_CONE = 0x4650
-OBJECT_LAMP_SPOT_RECTANGULAR = 0x4651
-OBJECT_LAMP_SPOT_OVERSHOOT = 0x4652
-OBJECT_LAMP_SPOT_PROJECTOR = 0x4653
-OBJECT_LAMP_EXCLUDE = 0x4654
-OBJECT_LAMP_RANGE = 0x4655
-OBJECT_LAMP_ROLL = 0x4656
-OBJECT_LAMP_SPOT_ASPECT = 0x4657
-OBJECT_LAMP_RAY_BIAS = 0x4658
-OBJECT_LAMP_INNER_RANGE = 0x4659
-OBJECT_LAMP_OUTER_RANGE = 0x465A
-OBJECT_LAMP_MULTIPLIER = 0x465B
-OBJECT_LAMP_AMBIENT_LIGHT = 0x4680
-
-
-
-OBJECT_CAMERA= 0x4700 # This lets un know we are reading a camera object
-
-#>------ sub defines of CAMERA
-OBJECT_CAM_RANGES= 0x4720 # The camera range values
-
-#>------ sub defines of OBJECT_MESH
-OBJECT_VERTICES = 0x4110 # The objects vertices
-OBJECT_FACES = 0x4120 # The objects faces
-OBJECT_MATERIAL = 0x4130 # This is found if the object has a material, either texture map or color
-OBJECT_UV = 0x4140 # The UV texture coordinates
-OBJECT_TRANS_MATRIX = 0x4160 # The Object Matrix
-
-global scn
-scn = None
-
-#the chunk class
-class chunk:
- ID = 0
- length = 0
- bytes_read = 0
-
- #we don't read in the bytes_read, we compute that
- binary_format='<HI'
-
- def __init__(self):
- self.ID = 0
- self.length = 0
- self.bytes_read = 0
-
- def dump(self):
- print('ID: ', self.ID)
- print('ID in hex: ', hex(self.ID))
- print('length: ', self.length)
- print('bytes_read: ', self.bytes_read)
-
-def read_chunk(file, chunk):
- temp_data = file.read(struct.calcsize(chunk.binary_format))
- data = struct.unpack(chunk.binary_format, temp_data)
- chunk.ID = data[0]
- chunk.length = data[1]
- #update the bytes read function
- chunk.bytes_read = 6
-
- #if debugging
- #chunk.dump()
-
-def read_string(file):
- #read in the characters till we get a null character
- s = b''
- while not s.endswith(b'\x00'):
- s += struct.unpack('<c', file.read(1))[0]
- #print 'string: ',s
-
- #remove the null character from the string
- s = str(s[:-1], 'ASCII')
-# print("read string", s)
- return s
-
-######################################################
-# IMPORT
-######################################################
-def process_next_object_chunk(file, previous_chunk):
- new_chunk = chunk()
- temp_chunk = chunk()
-
- while (previous_chunk.bytes_read < previous_chunk.length):
- #read the next chunk
- read_chunk(file, new_chunk)
-
-def skip_to_end(file, skip_chunk):
- buffer_size = skip_chunk.length - skip_chunk.bytes_read
- binary_format='%ic' % buffer_size
- temp_data = file.read(struct.calcsize(binary_format))
- skip_chunk.bytes_read += buffer_size
-
-
-def add_texture_to_material(image, texture, material, mapto):
- #print('assigning %s to %s' % (texture, material))
-
- if mapto not in ("COLOR", "SPECULARITY", "ALPHA", "NORMAL"):
- print('/tError: Cannot map to "%s"\n\tassuming diffuse color. modify material "%s" later.' % (mapto, material.name))
- mapto = "COLOR"
-
- if image:
- texture.image = image
-
- mtex = material.texture_slots.add()
- mtex.texture = texture
- mtex.texture_coords = 'UV'
- mtex.use_map_color_diffuse = False
-
- if mapto == 'COLOR':
- mtex.use_map_color_diffuse = True
- elif mapto == 'SPECULARITY':
- mtex.use_map_specular = True
- elif mapto == 'ALPHA':
- mtex.use_map_alpha = True
- elif mapto == 'NORMAL':
- mtex.use_map_normal = True
-
-
-def process_next_chunk(file, previous_chunk, importedObjects, IMAGE_SEARCH):
- #print previous_chunk.bytes_read, 'BYTES READ'
- 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()
- contextMesh_vertls = None # flat array: (verts * 3)
- contextMesh_facels = None
- contextMeshMaterials = {} # matname:[face_idxs]
- contextMeshUV = None # flat array (verts * 2)
-
- TEXTURE_DICT = {}
- MATDICT = {}
-# TEXMODE = Mesh.FaceModes['TEX']
-
- # Localspace variable names, faster.
- STRUCT_SIZE_1CHAR = struct.calcsize('c')
- STRUCT_SIZE_2FLOAT = struct.calcsize('2f')
- STRUCT_SIZE_3FLOAT = struct.calcsize('3f')
- STRUCT_SIZE_UNSIGNED_SHORT = struct.calcsize('H')
- STRUCT_SIZE_4UNSIGNED_SHORT = struct.calcsize('4H')
- STRUCT_SIZE_4x3MAT = struct.calcsize('ffffffffffff')
- _STRUCT_SIZE_4x3MAT = struct.calcsize('fffffffffffff')
- # STRUCT_SIZE_4x3MAT = calcsize('ffffffffffff')
- # print STRUCT_SIZE_4x3MAT, ' STRUCT_SIZE_4x3MAT'
-
- def putContextMesh(myContextMesh_vertls, myContextMesh_facels, myContextMeshMaterials):
-
- bmesh = bpy.data.meshes.new(contextObName)
- if myContextMesh_vertls:
-
- bmesh.vertices.add(len(myContextMesh_vertls)//3)
- bmesh.faces.add(len(myContextMesh_facels))
- bmesh.vertices.foreach_set("co", myContextMesh_vertls)
-
- eekadoodle_faces = []
- for v1, v2, v3 in myContextMesh_facels:
- eekadoodle_faces.extend([v3, v1, v2, 0] if v3 == 0 else [v1, v2, v3, 0])
- bmesh.faces.foreach_set("vertices_raw", eekadoodle_faces)
-
- if bmesh.faces and contextMeshUV:
- bmesh.uv_textures.new()
- uv_faces = bmesh.uv_textures.active.data[:]
- else:
- uv_faces = None
-
- for mat_idx, (matName, faces) in enumerate(myContextMeshMaterials.items()):
- if matName is None:
- bmat = None
- else:
- bmat = MATDICT[matName][1]
- img = TEXTURE_DICT.get(bmat.name)
-
- bmesh.materials.append(bmat) # can be None
-
- if uv_faces and img:
- for fidx in faces:
- bmesh.faces[fidx].material_index = mat_idx
- uf = uv_faces[fidx]
- uf.image = img
- uf.use_image = True
- else:
- for fidx in faces:
- bmesh.faces[fidx].material_index = mat_idx
-
- if uv_faces:
- for fidx, uf in enumerate(uv_faces):
- face = myContextMesh_facels[fidx]
- v1, v2, v3 = face
-
- # eekadoodle
- if v3 == 0:
- v1, v2, v3 = v3, v1, v2
-
- uf.uv1 = contextMeshUV[v1 * 2:(v1 * 2) + 2]
- uf.uv2 = contextMeshUV[v2 * 2:(v2 * 2) + 2]
- uf.uv3 = contextMeshUV[v3 * 2:(v3 * 2) + 2]
- # always a tri
-
- ob = bpy.data.objects.new(tempName, bmesh)
- SCN.objects.link(ob)
-
- '''
- if contextMatrix_tx:
- ob.setMatrix(contextMatrix_tx)
- '''
-
- if contextMatrix_rot:
- ob.matrix_world = contextMatrix_rot
-
- importedObjects.append(ob)
- bmesh.update()
-
- #a spare chunk
- new_chunk = chunk()
- temp_chunk = chunk()
-
- CreateBlenderObject = False
-
- def read_float_color(temp_chunk):
- temp_data = file.read(struct.calcsize('3f'))
- temp_chunk.bytes_read += 12
- return [float(col) for col in struct.unpack('<3f', temp_data)]
-
- def read_byte_color(temp_chunk):
- temp_data = file.read(struct.calcsize('3B'))
- temp_chunk.bytes_read += 3
- return [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
-
- def read_texture(new_chunk, temp_chunk, name, mapto):
- new_texture = bpy.data.textures.new(name, type='IMAGE')
-
- img = None
- while (new_chunk.bytes_read < new_chunk.length):
- #print 'MAT_TEXTURE_MAP..while', new_chunk.bytes_read, new_chunk.length
- read_chunk(file, temp_chunk)
-
- if (temp_chunk.ID == MAT_MAP_FILEPATH):
- texture_name = read_string(file)
- img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
- new_chunk.bytes_read += (len(texture_name)+1) #plus one for the null character that gets removed
-
- else:
- skip_to_end(file, temp_chunk)
-
- new_chunk.bytes_read += temp_chunk.bytes_read
-
- # add the map to the material in the right channel
- if img:
- add_texture_to_material(img, new_texture, contextMaterial, mapto)
-
- dirname = os.path.dirname(file.name)
-
- #loop through all the data for this chunk (previous chunk) and see what it is
- while (previous_chunk.bytes_read < previous_chunk.length):
- #print '\t', previous_chunk.bytes_read, 'keep going'
- #read the next chunk
- #print 'reading a chunk'
- read_chunk(file, new_chunk)
-
- #is it a Version chunk?
- if (new_chunk.ID == VERSION):
- #print 'if (new_chunk.ID == VERSION):'
- #print 'found a VERSION chunk'
- #read in the version of the file
- #it's an unsigned short (H)
- temp_data = file.read(struct.calcsize('I'))
- version = struct.unpack('<I', temp_data)[0]
- new_chunk.bytes_read += 4 #read the 4 bytes for the version number
- #this loader works with version 3 and below, but may not with 4 and above
- if (version > 3):
- print('\tNon-Fatal Error: Version greater than 3, may not load correctly: ', version)
-
- #is it an object info chunk?
- elif (new_chunk.ID == OBJECTINFO):
- #print 'elif (new_chunk.ID == OBJECTINFO):'
- # print 'found an OBJECTINFO chunk'
- process_next_chunk(file, new_chunk, importedObjects, IMAGE_SEARCH)
-
- #keep track of how much we read in the main chunk
- new_chunk.bytes_read += temp_chunk.bytes_read
-
- #is it an object chunk?
- elif (new_chunk.ID == OBJECT):
-
- if CreateBlenderObject:
- putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)
- contextMesh_vertls = []; contextMesh_facels = []
-
- ## preparando para receber o proximo objeto
- contextMeshMaterials = {} # matname:[face_idxs]
- contextMeshUV = None
- #contextMesh.vertexUV = 1 # Make sticky coords.
- # Reset matrix
- contextMatrix_rot = None
- #contextMatrix_tx = None
-
- CreateBlenderObject = True
- tempName = read_string(file)
- contextObName = tempName
- new_chunk.bytes_read += len(tempName)+1
-
- #is it a material chunk?
- elif (new_chunk.ID == MATERIAL):
-
-# print("read material")
-
- #print 'elif (new_chunk.ID == MATERIAL):'
- contextMaterial = bpy.data.materials.new('Material')
-
- elif (new_chunk.ID == MAT_NAME):
- #print 'elif (new_chunk.ID == MAT_NAME):'
- material_name = read_string(file)
-
-# print("material name", material_name)
-
- #plus one for the null character that ended the string
- new_chunk.bytes_read += len(material_name)+1
-
- contextMaterial.name = material_name.rstrip() # remove trailing whitespace
- MATDICT[material_name]= (contextMaterial.name, contextMaterial)
-
- elif (new_chunk.ID == MAT_AMBIENT):
- #print 'elif (new_chunk.ID == MAT_AMBIENT):'
- read_chunk(file, temp_chunk)
- if (temp_chunk.ID == MAT_FLOAT_COLOR):
- contextMaterial.mirror_color = read_float_color(temp_chunk)
-# temp_data = file.read(struct.calcsize('3f'))
-# temp_chunk.bytes_read += 12
-# contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)]
- elif (temp_chunk.ID == MAT_24BIT_COLOR):
- contextMaterial.mirror_color = read_byte_color(temp_chunk)
-# temp_data = file.read(struct.calcsize('3B'))
-# temp_chunk.bytes_read += 3
-# contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
- else:
- skip_to_end(file, temp_chunk)
- new_chunk.bytes_read += temp_chunk.bytes_read
-
- elif (new_chunk.ID == MAT_DIFFUSE):
- #print 'elif (new_chunk.ID == MAT_DIFFUSE):'
- read_chunk(file, temp_chunk)
- if (temp_chunk.ID == MAT_FLOAT_COLOR):
- contextMaterial.diffuse_color = read_float_color(temp_chunk)
-# temp_data = file.read(struct.calcsize('3f'))
-# temp_chunk.bytes_read += 12
-# contextMaterial.rgbCol = [float(col) for col in struct.unpack('<3f', temp_data)]
- elif (temp_chunk.ID == MAT_24BIT_COLOR):
- contextMaterial.diffuse_color = read_byte_color(temp_chunk)
-# temp_data = file.read(struct.calcsize('3B'))
-# temp_chunk.bytes_read += 3
-# contextMaterial.rgbCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
- else:
- skip_to_end(file, temp_chunk)
-
-# print("read material diffuse color", contextMaterial.diffuse_color)
-
- new_chunk.bytes_read += temp_chunk.bytes_read
-
- elif (new_chunk.ID == MAT_SPECULAR):
- #print 'elif (new_chunk.ID == MAT_SPECULAR):'
- read_chunk(file, temp_chunk)
- if (temp_chunk.ID == MAT_FLOAT_COLOR):
- contextMaterial.specular_color = read_float_color(temp_chunk)
-# temp_data = file.read(struct.calcsize('3f'))
-# temp_chunk.bytes_read += 12
-# contextMaterial.mirCol = [float(col) for col in struct.unpack('<3f', temp_data)]
- elif (temp_chunk.ID == MAT_24BIT_COLOR):
- contextMaterial.specular_color = read_byte_color(temp_chunk)
-# temp_data = file.read(struct.calcsize('3B'))
-# temp_chunk.bytes_read += 3
-# contextMaterial.mirCol = [float(col)/255 for col in struct.unpack('<3B', temp_data)] # data [0,1,2] == rgb
- else:
- skip_to_end(file, temp_chunk)
- new_chunk.bytes_read += temp_chunk.bytes_read
-
- elif (new_chunk.ID == MAT_TEXTURE_MAP):
- read_texture(new_chunk, temp_chunk, "Diffuse", "COLOR")
-
- elif (new_chunk.ID == MAT_SPECULAR_MAP):
- read_texture(new_chunk, temp_chunk, "Specular", "SPECULARITY")
-
- elif (new_chunk.ID == MAT_OPACITY_MAP):
- read_texture(new_chunk, temp_chunk, "Opacity", "ALPHA")
-
- elif (new_chunk.ID == MAT_BUMP_MAP):
- read_texture(new_chunk, temp_chunk, "Bump", "NORMAL")
-
- elif (new_chunk.ID == MAT_TRANSPARENCY):
- #print 'elif (new_chunk.ID == MAT_TRANSPARENCY):'
- read_chunk(file, temp_chunk)
- temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
-
- temp_chunk.bytes_read += 2
- contextMaterial.alpha = 1-(float(struct.unpack('<H', temp_data)[0])/100)
- new_chunk.bytes_read += temp_chunk.bytes_read
-
-
- elif (new_chunk.ID == OBJECT_LAMP): # Basic lamp support.
-
- temp_data = file.read(STRUCT_SIZE_3FLOAT)
-
- x,y,z = struct.unpack('<3f', temp_data)
- new_chunk.bytes_read += STRUCT_SIZE_3FLOAT
-
- ob = bpy.data.objects.new("Lamp", bpy.data.lamps.new("Lamp"))
- SCN.objects.link(ob)
-
- contextLamp[1]= ob.data
-# contextLamp[1]= bpy.data.lamps.new()
- contextLamp[0]= ob
-# contextLamp[0]= SCN_OBJECTS.new(contextLamp[1])
- importedObjects.append(contextLamp[0])
-
- #print 'number of faces: ', num_faces
- #print x,y,z
- contextLamp[0].location = (x, y, z)
-# contextLamp[0].setLocation(x,y,z)
-
- # Reset matrix
- contextMatrix_rot = None
- #contextMatrix_tx = None
- #print contextLamp.name,
-
- elif (new_chunk.ID == OBJECT_MESH):
- # print 'Found an OBJECT_MESH chunk'
- pass
- elif (new_chunk.ID == OBJECT_VERTICES):
- '''
- Worldspace vertex locations
- '''
- # print 'elif (new_chunk.ID == OBJECT_VERTICES):'
- temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- num_verts = struct.unpack('<H', temp_data)[0]
- new_chunk.bytes_read += 2
-
- # print 'number of verts: ', num_verts
- contextMesh_vertls = struct.unpack('<%df' % (num_verts * 3), file.read(STRUCT_SIZE_3FLOAT * num_verts))
- new_chunk.bytes_read += STRUCT_SIZE_3FLOAT * num_verts
- # dummyvert is not used atm!
-
- #print 'object verts: bytes read: ', new_chunk.bytes_read
-
- elif (new_chunk.ID == OBJECT_FACES):
- # print 'elif (new_chunk.ID == OBJECT_FACES):'
- temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- num_faces = struct.unpack('<H', temp_data)[0]
- new_chunk.bytes_read += 2
- #print 'number of faces: ', num_faces
-
- # print '\ngetting a face'
- temp_data = file.read(STRUCT_SIZE_4UNSIGNED_SHORT * num_faces)
- new_chunk.bytes_read += STRUCT_SIZE_4UNSIGNED_SHORT * num_faces #4 short ints x 2 bytes each
- contextMesh_facels = struct.unpack('<%dH' % (num_faces * 4), temp_data)
- contextMesh_facels = [contextMesh_facels[i - 3:i] for i in range(3, (num_faces * 4) + 3, 4)]
-
- elif (new_chunk.ID == OBJECT_MATERIAL):
- # print 'elif (new_chunk.ID == OBJECT_MATERIAL):'
- material_name = read_string(file)
- new_chunk.bytes_read += len(material_name)+1 # remove 1 null character.
-
- temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- num_faces_using_mat = struct.unpack('<H', temp_data)[0]
- new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT
-
-
- temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT * num_faces_using_mat)
- new_chunk.bytes_read += STRUCT_SIZE_UNSIGNED_SHORT * num_faces_using_mat
-
- contextMeshMaterials[material_name]= struct.unpack("<%dH" % (num_faces_using_mat), temp_data)
-
- #look up the material in all the materials
-
- elif (new_chunk.ID == OBJECT_UV):
- temp_data = file.read(STRUCT_SIZE_UNSIGNED_SHORT)
- num_uv = struct.unpack('<H', temp_data)[0]
- new_chunk.bytes_read += 2
-
- temp_data = file.read(STRUCT_SIZE_2FLOAT * num_uv)
- new_chunk.bytes_read += STRUCT_SIZE_2FLOAT * num_uv
- contextMeshUV = struct.unpack('<%df' % (num_uv * 2), temp_data)
-
- elif (new_chunk.ID == OBJECT_TRANS_MATRIX):
- # How do we know the matrix size? 54 == 4x4 48 == 4x3
- temp_data = file.read(STRUCT_SIZE_4x3MAT)
- data = list( struct.unpack('<ffffffffffff', temp_data) )
- new_chunk.bytes_read += STRUCT_SIZE_4x3MAT
-
- contextMatrix_rot = mathutils.Matrix(\
- data[:3] + [0],\
- data[3:6] + [0],\
- data[6:9] + [0],\
- data[9:] + [1])
-
-
- '''
- contextMatrix_rot = Blender.mathutils.Matrix(\
- data[:3] + [0],\
- data[3:6] + [0],\
- data[6:9] + [0],\
- [0,0,0,1])
- '''
-
- '''
- contextMatrix_rot = Blender.mathutils.Matrix(\
- data[:3] ,\
- data[3:6],\
- data[6:9])
- '''
-
- '''
- contextMatrix_rot = Blender.mathutils.Matrix()
- m = 0
- for j in xrange(4):
- for i in xrange(3):
- contextMatrix_rot[j][i] = data[m]
- m += 1
-
- contextMatrix_rot[0][3]=0;
- contextMatrix_rot[1][3]=0;
- contextMatrix_rot[2][3]=0;
- contextMatrix_rot[3][3]=1;
- '''
-
- #contextMatrix_rot.resize4x4()
- #print "MTX"
- #print contextMatrix_rot
- contextMatrix_rot.invert()
- #print contextMatrix_rot
- #contextMatrix_tx = mathutils.Matrix.Translation(0.5 * Blender.mathutils.Vector(data[9:]))
- #contextMatrix_tx.invert()
-
- #tx.invert()
-
- #contextMatrix = contextMatrix * tx
- #contextMatrix = contextMatrix *tx
-
- elif (new_chunk.ID == MAT_MAP_FILEPATH):
- texture_name = read_string(file)
- try:
- TEXTURE_DICT[contextMaterial.name]
- except:
- #img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILEPATH)
- img = TEXTURE_DICT[contextMaterial.name] = load_image(texture_name, dirname)
-# img = TEXTURE_DICT[contextMaterial.name]= BPyImage.comprehensiveImageLoad(texture_name, FILEPATH, PLACE_HOLDER=False, RECURSIVE=IMAGE_SEARCH)
-
- new_chunk.bytes_read += len(texture_name)+1 #plus one for the null character that gets removed
-
- else: #(new_chunk.ID!=VERSION or new_chunk.ID!=OBJECTINFO or new_chunk.ID!=OBJECT or new_chunk.ID!=MATERIAL):
- # print 'skipping to end of this chunk'
- buffer_size = new_chunk.length - new_chunk.bytes_read
- binary_format='%ic' % buffer_size
- temp_data = file.read(struct.calcsize(binary_format))
- new_chunk.bytes_read += buffer_size
-
-
- #update the previous chunk bytes read
- # print 'previous_chunk.bytes_read += new_chunk.bytes_read'
- # print previous_chunk.bytes_read, new_chunk.bytes_read
- previous_chunk.bytes_read += new_chunk.bytes_read
- ## print 'Bytes left in this chunk: ', previous_chunk.length - previous_chunk.bytes_read
-
- # FINISHED LOOP
- # There will be a number of objects still not added
- if CreateBlenderObject:
- putContextMesh(contextMesh_vertls, contextMesh_facels, contextMeshMaterials)
-
-def load_3ds(filepath, context, IMPORT_CONSTRAIN_BOUNDS=10.0, IMAGE_SEARCH=True, APPLY_MATRIX=False):
- global SCN
-
- # XXX
-# if BPyMessages.Error_NoFile(filepath):
-# return
-
- print('\n\nImporting 3DS: %r' % (filepath))
-
- time1 = time.clock()
-# time1 = Blender.sys.time()
-
- current_chunk = chunk()
-
- file = open(filepath, 'rb')
-
- #here we go!
- # print 'reading the first chunk'
- read_chunk(file, current_chunk)
- if (current_chunk.ID!=PRIMARY):
- print('\tFatal Error: Not a valid 3ds file: %r' % filepath)
- file.close()
- return
-
-
- # IMPORT_AS_INSTANCE = Blender.Draw.Create(0)
-# IMPORT_CONSTRAIN_BOUNDS = Blender.Draw.Create(10.0)
-# IMAGE_SEARCH = Blender.Draw.Create(1)
-# APPLY_MATRIX = Blender.Draw.Create(0)
-
- # Get USER Options
-# pup_block = [\
-# ('Size Constraint:', IMPORT_CONSTRAIN_BOUNDS, 0.0, 1000.0, 'Scale the model by 10 until it reacehs the size constraint. Zero Disables.'),\
-# ('Image Search', IMAGE_SEARCH, 'Search subdirs for any assosiated images (Warning, may be slow)'),\
-# ('Transform Fix', APPLY_MATRIX, 'Workaround for object transformations importing incorrectly'),\
-# #('Group Instance', IMPORT_AS_INSTANCE, 'Import objects into a new scene and group, creating an instance in the current scene.'),\
-# ]
-
-# if PREF_UI:
-# if not Blender.Draw.PupBlock('Import 3DS...', pup_block):
-# return
-
-# Blender.Window.WaitCursor(1)
-
-# IMPORT_CONSTRAIN_BOUNDS = IMPORT_CONSTRAIN_BOUNDS.val
-# # IMPORT_AS_INSTANCE = IMPORT_AS_INSTANCE.val
-# IMAGE_SEARCH = IMAGE_SEARCH.val
-# APPLY_MATRIX = APPLY_MATRIX.val
-
- if IMPORT_CONSTRAIN_BOUNDS:
- BOUNDS_3DS[:]= [1<<30, 1<<30, 1<<30, -1<<30, -1<<30, -1<<30]
- else:
- BOUNDS_3DS[:]= []
-
- ##IMAGE_SEARCH
-
- scn = context.scene
-# scn = bpy.data.scenes.active
- SCN = scn
-# SCN_OBJECTS = scn.objects
-# SCN_OBJECTS.selected = [] # de select all
-
- importedObjects = [] # Fill this list with objects
- process_next_chunk(file, current_chunk, importedObjects, IMAGE_SEARCH)
-
-
- # Link the objects into this scene.
- # Layers = scn.Layers
-
- # REMOVE DUMMYVERT, - remove this in the next release when blenders internal are fixed.
-
- for ob in importedObjects:
- if ob.type == 'MESH':
- me = ob.data
-# me.vertices.delete([me.vertices[0],]) # XXX, todo
- if not APPLY_MATRIX:
- me.transform(ob.matrix_world.copy().invert())
-
- # Done DUMMYVERT
- """
- if IMPORT_AS_INSTANCE:
- name = filepath.split('\\')[-1].split('/')[-1]
- # Create a group for this import.
- group_scn = Scene.New(name)
- for ob in importedObjects:
- group_scn.link(ob) # dont worry about the layers
-
- grp = Blender.Group.New(name)
- grp.objects = importedObjects
-
- grp_ob = Object.New('Empty', name)
- grp_ob.enableDupGroup = True
- grp_ob.DupGroup = grp
- scn.link(grp_ob)
- grp_ob.Layers = Layers
- grp_ob.sel = 1
- else:
- # Select all imported objects.
- for ob in importedObjects:
- scn.link(ob)
- ob.Layers = Layers
- ob.sel = 1
- """
-
- if 0:
-# if IMPORT_CONSTRAIN_BOUNDS!=0.0:
- # Set bounds from objecyt bounding box
- for ob in importedObjects:
- if ob.type == 'MESH':
-# if ob.type=='Mesh':
- ob.makeDisplayList() # Why dosnt this update the bounds?
- for v in ob.getBoundBox():
- for i in (0,1,2):
- if v[i] < BOUNDS_3DS[i]:
- BOUNDS_3DS[i]= v[i] # min
-
- if v[i] > BOUNDS_3DS[i + 3]:
- BOUNDS_3DS[i + 3]= v[i] # min
-
- # Get the max axis x/y/z
- max_axis = max(BOUNDS_3DS[3]-BOUNDS_3DS[0], BOUNDS_3DS[4]-BOUNDS_3DS[1], BOUNDS_3DS[5]-BOUNDS_3DS[2])
- # print max_axis
- if max_axis < 1 << 30: # Should never be false but just make sure.
-
- # Get a new scale factor if set as an option
- SCALE = 1.0
- while (max_axis * SCALE) > IMPORT_CONSTRAIN_BOUNDS:
- 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])
-
- for ob in importedObjects:
- ob.matrix_world = ob.matrix_world * SCALE_MAT
-
- # Done constraining to bounds.
-
- # Select all new objects.
- print('finished importing: %r in %.4f sec.' % (filepath, (time.clock()-time1)))
- file.close()
-
-
-def load(operator, context, filepath="", constrain_size=0.0, use_image_search=True, use_apply_transform=True):
- load_3ds(filepath, context, IMPORT_CONSTRAIN_BOUNDS=constrain_size, IMAGE_SEARCH=use_image_search, APPLY_MATRIX=use_apply_transform)
- return {'FINISHED'}
diff --git a/release/scripts/op/io_scene_fbx/__init__.py b/release/scripts/op/io_scene_fbx/__init__.py
deleted file mode 100644
index 75d302153f7..00000000000
--- a/release/scripts/op/io_scene_fbx/__init__.py
+++ /dev/null
@@ -1,122 +0,0 @@
-# ##### 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>
-
-# To support reload properly, try to access a package var, if it's there, reload everything
-if "bpy" in locals():
- # only reload if we alredy loaded, highly annoying
- import sys
- reload(sys.modules.get("io_scene_fbx.export_fbx", sys))
-
-
-import bpy
-from bpy.props import *
-from io_utils import ExportHelper
-
-
-class ExportFBX(bpy.types.Operator, ExportHelper):
- '''Selection to an ASCII Autodesk FBX'''
- bl_idname = "export_scene.fbx"
- bl_label = "Export FBX"
-
- filename_ext = ".fbx"
-
- # List of operator properties, the attributes will be assigned
- # to the class instance from the operator settings before calling.
-
- EXP_OBS_SELECTED = BoolProperty(name="Selected Objects", description="Export selected objects on visible layers", default=True)
-# EXP_OBS_SCENE = BoolProperty(name="Scene Objects", description="Export all objects in this scene", default=True)
- TX_SCALE = FloatProperty(name="Scale", description="Scale all data, (Note! some imports dont support scaled armatures)", min=0.01, max=1000.0, soft_min=0.01, soft_max=1000.0, default=1.0)
- TX_XROT90 = BoolProperty(name="Rot X90", description="Rotate all objects 90 degrees about the X axis", default=True)
- TX_YROT90 = BoolProperty(name="Rot Y90", description="Rotate all objects 90 degrees about the Y axis", default=False)
- TX_ZROT90 = BoolProperty(name="Rot Z90", description="Rotate all objects 90 degrees about the Z axis", default=False)
- EXP_EMPTY = BoolProperty(name="Empties", description="Export empty objects", default=True)
- EXP_CAMERA = BoolProperty(name="Cameras", description="Export camera objects", default=True)
- EXP_LAMP = BoolProperty(name="Lamps", description="Export lamp objects", default=True)
- EXP_ARMATURE = BoolProperty(name="Armatures", description="Export armature objects", default=True)
- EXP_MESH = BoolProperty(name="Meshes", description="Export mesh objects", default=True)
- EXP_MESH_APPLY_MOD = BoolProperty(name="Modifiers", description="Apply modifiers to mesh objects", default=True)
- EXP_MESH_HQ_NORMALS = BoolProperty(name="HQ Normals", description="Generate high quality normals", default=True)
- EXP_IMAGE_COPY = BoolProperty(name="Copy Image Files", description="Copy image files to the destination path", default=False)
- # armature animation
- ANIM_ENABLE = BoolProperty(name="Enable Animation", description="Export keyframe animation", default=True)
- ANIM_OPTIMIZE = BoolProperty(name="Optimize Keyframes", description="Remove double keyframes", default=True)
- ANIM_OPTIMIZE_PRECISSION = FloatProperty(name="Precision", description="Tolerence for comparing double keyframes (higher for greater accuracy)", min=1, max=16, soft_min=1, soft_max=16, default=6.0)
-# ANIM_ACTION_ALL = BoolProperty(name="Current Action", description="Use actions currently applied to the armatures (use scene start/end frame)", default=True)
- ANIM_ACTION_ALL = BoolProperty(name="All Actions", description="Use all actions for armatures, if false, use current action", default=False)
- # batch
- BATCH_ENABLE = BoolProperty(name="Enable Batch", description="Automate exporting multiple scenes or groups to files", default=False)
- BATCH_GROUP = BoolProperty(name="Group > File", description="Export each group as an FBX file, if false, export each scene as an FBX file", default=False)
- BATCH_OWN_DIR = BoolProperty(name="Own Dir", description="Create a dir for each exported file", default=True)
- BATCH_FILE_PREFIX = StringProperty(name="Prefix", description="Prefix each file with this name", maxlen=1024, default="")
-
- def execute(self, context):
- import math
- from mathutils import Matrix
- if not self.filepath:
- raise Exception("filepath not set")
-
- mtx4_x90n = Matrix.Rotation(-math.pi / 2.0, 4, 'X')
- mtx4_y90n = Matrix.Rotation(-math.pi / 2.0, 4, 'Y')
- mtx4_z90n = Matrix.Rotation(-math.pi / 2.0, 4, 'Z')
-
- GLOBAL_MATRIX = Matrix()
- GLOBAL_MATRIX[0][0] = GLOBAL_MATRIX[1][1] = GLOBAL_MATRIX[2][2] = self.TX_SCALE
- if self.TX_XROT90:
- GLOBAL_MATRIX = mtx4_x90n * GLOBAL_MATRIX
- if self.TX_YROT90:
- GLOBAL_MATRIX = mtx4_y90n * GLOBAL_MATRIX
- if self.TX_ZROT90:
- GLOBAL_MATRIX = mtx4_z90n * GLOBAL_MATRIX
-
- import io_scene_fbx.export_fbx
- return io_scene_fbx.export_fbx.save(self, context, self.filepath,
- GLOBAL_MATRIX=GLOBAL_MATRIX,
- EXP_OBS_SELECTED=self.EXP_OBS_SELECTED,
- EXP_MESH=self.EXP_MESH,
- EXP_MESH_APPLY_MOD=self.EXP_MESH_APPLY_MOD,
- EXP_ARMATURE=self.EXP_ARMATURE,
- EXP_LAMP=self.EXP_LAMP,
- EXP_CAMERA=self.EXP_CAMERA,
- EXP_EMPTY=self.EXP_EMPTY,
- EXP_IMAGE_COPY=self.EXP_IMAGE_COPY,
- ANIM_ENABLE=self.ANIM_ENABLE,
- ANIM_OPTIMIZE=self.ANIM_OPTIMIZE,
- ANIM_OPTIMIZE_PRECISSION=self.ANIM_OPTIMIZE_PRECISSION,
- ANIM_ACTION_ALL=self.ANIM_ACTION_ALL,
- BATCH_ENABLE=self.BATCH_ENABLE,
- BATCH_GROUP=self.BATCH_GROUP,
- BATCH_FILE_PREFIX=self.BATCH_FILE_PREFIX,
- BATCH_OWN_DIR=self.BATCH_OWN_DIR,
- )
-
-
-def menu_func(self, context):
- self.layout.operator(ExportFBX.bl_idname, text="Autodesk FBX (.fbx)")
-
-
-def register():
- bpy.types.INFO_MT_file_export.append(menu_func)
-
-
-def unregister():
- bpy.types.INFO_MT_file_export.remove(menu_func)
-
-if __name__ == "__main__":
- register()
diff --git a/release/scripts/op/io_scene_fbx/export_fbx.py b/release/scripts/op/io_scene_fbx/export_fbx.py
deleted file mode 100644
index 4859e87620f..00000000000
--- a/release/scripts/op/io_scene_fbx/export_fbx.py
+++ /dev/null
@@ -1,2892 +0,0 @@
-# ##### 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>
-
-# Script copyright (C) Campbell Barton
-
-"""
-This script is an exporter to the FBX file format.
-
-http://wiki.blender.org/index.php/Scripts/Manual/Export/autodesk_fbx
-"""
-
-import os
-import time
-import math # math.pi
-import shutil # for file copying
-
-import bpy
-from mathutils import Vector, Euler, Matrix
-
-# XXX not used anymore, images are copied one at a time
-def copy_images(dest_dir, textures):
- import shutil
-
- if not dest_dir.endswith(os.sep):
- dest_dir += os.sep
-
- image_paths = set()
- for tex in textures:
- image_paths.add(bpy.path.abspath(tex.filepath))
-
- # Now copy images
- copyCount = 0
- for image_path in image_paths:
- if Blender.sys.exists(image_path):
- # Make a name for the target path.
- dest_image_path = dest_dir + image_path.split('\\')[-1].split('/')[-1]
- if not Blender.sys.exists(dest_image_path): # Image isnt already there
- print("\tCopying %r > %r" % (image_path, dest_image_path))
- try:
- shutil.copy(image_path, dest_image_path)
- copyCount+=1
- except:
- print("\t\tWarning, file failed to copy, skipping.")
-
- print('\tCopied %d images' % copyCount)
-
-# I guess FBX uses degrees instead of radians (Arystan).
-# Call this function just before writing to FBX.
-def eulerRadToDeg(eul):
- ret = Euler()
-
- ret.x = 180 / math.pi * eul[0]
- ret.y = 180 / math.pi * eul[1]
- ret.z = 180 / math.pi * eul[2]
-
- return ret
-
-
-# def strip_path(p):
-# return p.split('\\')[-1].split('/')[-1]
-
-# Used to add the scene name into the filepath without using odd chars
-sane_name_mapping_ob = {}
-sane_name_mapping_mat = {}
-sane_name_mapping_tex = {}
-sane_name_mapping_take = {}
-sane_name_mapping_group = {}
-
-# Make sure reserved names are not used
-sane_name_mapping_ob['Scene'] = 'Scene_'
-sane_name_mapping_ob['blend_root'] = 'blend_root_'
-
-def increment_string(t):
- name = t
- num = ''
- while name and name[-1].isdigit():
- num = name[-1] + num
- name = name[:-1]
- if num: return '%s%d' % (name, int(num)+1)
- else: return name + '_0'
-
-
-
-# todo - Disallow the name 'Scene' and 'blend_root' - it will bugger things up.
-def sane_name(data, dct):
- #if not data: return None
-
- if type(data)==tuple: # materials are paired up with images
- data, other = data
- use_other = True
- else:
- other = None
- use_other = False
-
- if data: name = data.name
- else: name = None
- orig_name = name
-
- if other:
- orig_name_other = other.name
- name = '%s #%s' % (name, orig_name_other)
- else:
- orig_name_other = None
-
- # dont cache, only ever call once for each data type now,
- # so as to avoid namespace collision between types - like with objects <-> bones
- #try: return dct[name]
- #except: pass
-
- if not name:
- name = 'unnamed' # blank string, ASKING FOR TROUBLE!
- else:
-
- name = bpy.path.clean_name(name) # use our own
-
- while name in iter(dct.values()): name = increment_string(name)
-
- if use_other: # even if other is None - orig_name_other will be a string or None
- dct[orig_name, orig_name_other] = name
- else:
- dct[orig_name] = name
-
- return name
-
-def sane_obname(data): return sane_name(data, sane_name_mapping_ob)
-def sane_matname(data): return sane_name(data, sane_name_mapping_mat)
-def sane_texname(data): return sane_name(data, sane_name_mapping_tex)
-def sane_takename(data): return sane_name(data, sane_name_mapping_take)
-def sane_groupname(data): return sane_name(data, sane_name_mapping_group)
-
-# def derived_paths(fname_orig, basepath, FORCE_CWD=False):
-# '''
-# fname_orig - blender path, can be relative
-# basepath - fname_rel will be relative to this
-# FORCE_CWD - dont use the basepath, just add a ./ to the filepath.
-# use when we know the file will be in the basepath.
-# '''
-# fname = bpy.path.abspath(fname_orig)
-# # fname = Blender.sys.expandpath(fname_orig)
-# fname_strip = os.path.basename(fname)
-# # fname_strip = strip_path(fname)
-# if FORCE_CWD:
-# fname_rel = '.' + os.sep + fname_strip
-# else:
-# fname_rel = bpy.path.relpath(fname, basepath)
-# # fname_rel = Blender.sys.relpath(fname, basepath)
-# if fname_rel.startswith('//'): fname_rel = '.' + os.sep + fname_rel[2:]
-# return fname, fname_strip, fname_rel
-
-
-def mat4x4str(mat):
- return '%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f,%.15f' % tuple([ f for v in mat for f in v ])
-
-# XXX not used
-# duplicated in OBJ exporter
-def getVertsFromGroup(me, group_index):
- ret = []
-
- for i, v in enumerate(me.vertices):
- for g in v.groups:
- if g.group == group_index:
- ret.append((i, g.weight))
-
- return ret
-
-# ob must be OB_MESH
-def BPyMesh_meshWeight2List(ob, me):
- ''' Takes a mesh and return its group names and a list of lists, one list per vertex.
- aligning the each vert list with the group names, each list contains float value for the weight.
- These 2 lists can be modified and then used with list2MeshWeight to apply the changes.
- '''
-
- # Clear the vert group.
- groupNames= [g.name for g in ob.vertex_groups]
- len_groupNames= len(groupNames)
-
- if not len_groupNames:
- # no verts? return a vert aligned empty list
- return [[] for i in range(len(me.vertices))], []
- else:
- vWeightList= [[0.0]*len_groupNames for i in range(len(me.vertices))]
-
- for i, v in enumerate(me.vertices):
- for g in v.groups:
- vWeightList[i][g.group] = g.weight
-
- return groupNames, vWeightList
-
-def meshNormalizedWeights(ob, me):
- try: # account for old bad BPyMesh
- groupNames, vWeightList = BPyMesh_meshWeight2List(ob, me)
-# groupNames, vWeightList = BPyMesh.meshWeight2List(me)
- except:
- return [],[]
-
- if not groupNames:
- return [],[]
-
- for i, vWeights in enumerate(vWeightList):
- tot = 0.0
- for w in vWeights:
- tot+=w
-
- if tot:
- for j, w in enumerate(vWeights):
- vWeights[j] = w/tot
-
- return groupNames, vWeightList
-
-header_comment = \
-'''; FBX 6.1.0 project file
-; Created by Blender FBX Exporter
-; for support mail: ideasman42@gmail.com
-; ----------------------------------------------------
-
-'''
-
-# This func can be called with just the filepath
-def save(operator, context, filepath="",
- GLOBAL_MATRIX = None,
- EXP_OBS_SELECTED = True,
- EXP_MESH = True,
- EXP_MESH_APPLY_MOD = True,
- EXP_ARMATURE = True,
- EXP_LAMP = True,
- EXP_CAMERA = True,
- EXP_EMPTY = True,
- EXP_IMAGE_COPY = False,
- ANIM_ENABLE = True,
- ANIM_OPTIMIZE = True,
- ANIM_OPTIMIZE_PRECISSION = 6,
- ANIM_ACTION_ALL = False,
- BATCH_ENABLE = False,
- BATCH_GROUP = True,
- BATCH_FILE_PREFIX = '',
- BATCH_OWN_DIR = False
- ):
-
- #XXX, missing arg
- batch_objects = None
-
- # testing
- mtx_x90 = Matrix.Rotation( math.pi/2.0, 3, 'X') # used
- mtx4_z90 = Matrix.Rotation( math.pi/2.0, 4, 'Z')
-
- if GLOBAL_MATRIX is None:
- GLOBAL_MATRIX = Matrix()
-
- if bpy.ops.object.mode_set.poll():
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # ----------------- Batch support!
- if BATCH_ENABLE:
- fbxpath = filepath
-
- # get the path component of filepath
- tmp_exists = bpy.utils.exists(fbxpath)
-# tmp_exists = Blender.sys.exists(fbxpath)
-
- if tmp_exists != 2: # a file, we want a path
- fbxpath = os.path.dirname(fbxpath)
-# while fbxpath and fbxpath[-1] not in ('/', '\\'):
-# fbxpath = fbxpath[:-1]
- if not fbxpath:
-# if not filepath:
- # XXX
- print('Error%t|Directory does not exist!')
-# Draw.PupMenu('Error%t|Directory does not exist!')
- return
-
- tmp_exists = bpy.utils.exists(fbxpath)
-# tmp_exists = Blender.sys.exists(fbxpath)
-
- if tmp_exists != 2:
- # XXX
- print('Error%t|Directory does not exist!')
-# Draw.PupMenu('Error%t|Directory does not exist!')
- return
-
- if not fbxpath.endswith(os.sep):
- fbxpath += os.sep
- del tmp_exists
-
-
- if BATCH_GROUP:
- data_seq = bpy.data.groups
- else:
- data_seq = bpy.data.scenes
-
- # call this function within a loop with BATCH_ENABLE == False
- 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.path.clean_name(data.name)
-
-
- if BATCH_OWN_DIR:
- new_fbxpath = fbxpath + newname + os.sep
- # path may already exist
- # TODO - might exist but be a file. unlikely but should probably account for it.
-
- if bpy.utils.exists(new_fbxpath) == 0:
-# if Blender.sys.exists(new_fbxpath) == 0:
- os.mkdir(new_fbxpath)
-
-
- filepath = new_fbxpath + newname + '.fbx'
-
- print('\nBatch exporting %s as...\n\t%r' % (data, filepath))
-
- # XXX don't know what to do with this, probably do the same? (Arystan)
- if BATCH_GROUP: #group
- # group, so objects update properly, add a dummy scene.
- scene = bpy.data.scenes.new()
- scene.Layers = (1<<20) -1
- bpy.data.scenes.active = scene
- for ob_base in data.objects:
- scene.objects.link(ob_base)
-
- scene.update(1)
-
- # TODO - BUMMER! Armatures not in the group wont animate the mesh
-
- else:# scene
-
-
- data_seq.active = data
-
-
- # Call self with modified args
- # Dont pass batch options since we already usedt them
- write(filepath, data.objects,
- context,
- False,
- EXP_MESH,
- EXP_MESH_APPLY_MOD,
- EXP_ARMATURE,
- EXP_LAMP,
- EXP_CAMERA,
- EXP_EMPTY,
- EXP_IMAGE_COPY,
- GLOBAL_MATRIX,
- ANIM_ENABLE,
- ANIM_OPTIMIZE,
- ANIM_OPTIMIZE_PRECISSION,
- ANIM_ACTION_ALL
- )
-
- if BATCH_GROUP:
- # remove temp group scene
- bpy.data.scenes.unlink(scene)
-
- bpy.data.scenes.active = orig_sce
-
- return # so the script wont run after we have batch exported.
-
- # end batch support
-
- # Use this for working out paths relative to the export location
- basepath = os.path.dirname(filepath) or '.'
- basepath += os.sep
-# basepath = Blender.sys.dirname(filepath)
-
- # ----------------------------------------------
- # storage classes
- class my_bone_class:
- __slots__ =(\
- 'blenName',\
- 'blenBone',\
- 'blenMeshes',\
- 'restMatrix',\
- 'parent',\
- 'blenName',\
- 'fbxName',\
- 'fbxArm',\
- '__pose_bone',\
- '__anim_poselist')
-
- def __init__(self, blenBone, fbxArm):
-
- # This is so 2 armatures dont have naming conflicts since FBX bones use object namespace
- self.fbxName = sane_obname(blenBone)
-
- self.blenName = blenBone.name
- self.blenBone = blenBone
- self.blenMeshes = {} # fbxMeshObName : mesh
- self.fbxArm = fbxArm
- self.restMatrix = blenBone.matrix_local
-# self.restMatrix = blenBone.matrix['ARMATURESPACE']
-
- # not used yet
- # self.restMatrixInv = self.restMatrix.copy().invert()
- # self.restMatrixLocal = None # set later, need parent matrix
-
- self.parent = None
-
- # not public
- pose = fbxArm.blenObject.pose
-# pose = fbxArm.blenObject.getPose()
- self.__pose_bone = pose.bones[self.blenName]
-
- # store a list if matricies here, (poseMatrix, head, tail)
- # {frame:posematrix, frame:posematrix, ...}
- self.__anim_poselist = {}
-
- '''
- def calcRestMatrixLocal(self):
- if self.parent:
- self.restMatrixLocal = self.restMatrix * self.parent.restMatrix.copy().invert()
- else:
- self.restMatrixLocal = self.restMatrix.copy()
- '''
- def setPoseFrame(self, f):
- # cache pose info here, frame must be set beforehand
-
- # Didnt end up needing head or tail, if we do - here it is.
- '''
- self.__anim_poselist[f] = (\
- self.__pose_bone.poseMatrix.copy(),\
- self.__pose_bone.head.copy(),\
- self.__pose_bone.tail.copy() )
- '''
-
- self.__anim_poselist[f] = self.__pose_bone.matrix.copy()
-# self.__anim_poselist[f] = self.__pose_bone.poseMatrix.copy()
-
- # get pose from frame.
- def getPoseMatrix(self, f):# ----------------------------------------------
- return self.__anim_poselist[f]
- '''
- def getPoseHead(self, f):
- #return self.__pose_bone.head.copy()
- return self.__anim_poselist[f][1].copy()
- def getPoseTail(self, f):
- #return self.__pose_bone.tail.copy()
- return self.__anim_poselist[f][2].copy()
- '''
- # end
-
- def getAnimParRelMatrix(self, frame):
- #arm_mat = self.fbxArm.matrixWorld
- #arm_mat = self.fbxArm.parRelMatrix()
- if not self.parent:
- #return mtx4_z90 * (self.getPoseMatrix(frame) * arm_mat) # dont apply arm matrix anymore
- 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 (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):
- return self.getAnimParRelMatrix(frame)
-
- def flushAnimData(self):
- self.__anim_poselist.clear()
-
-
- class my_object_generic:
- # Other settings can be applied for each type - mesh, armature etc.
- def __init__(self, ob, matrixWorld = None):
- self.fbxName = sane_obname(ob)
- self.blenObject = ob
- self.fbxGroupNames = []
- self.fbxParent = None # set later on IF the parent is in the selection.
- 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.fbxParent.matrixWorld.copy().invert() * self.matrixWorld
- else:
- return self.matrixWorld
-
- def setPoseFrame(self, f):
- 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 (GLOBAL_MATRIX * self.fbxParent.__anim_poselist[frame]).invert() * (GLOBAL_MATRIX * self.__anim_poselist[frame])
- else:
- return GLOBAL_MATRIX * self.__anim_poselist[frame]
-
- def getAnimParRelMatrixRot(self, frame):
- obj_type = self.blenObject.type
- if self.fbxParent:
- matrix_rot = ((GLOBAL_MATRIX * self.fbxParent.__anim_poselist[frame]).invert() * (GLOBAL_MATRIX * self.__anim_poselist[frame])).rotation_part()
- else:
- matrix_rot = (GLOBAL_MATRIX * self.__anim_poselist[frame]).rotation_part()
-
- # Lamps need to be rotated
- if obj_type =='LAMP':
- matrix_rot = matrix_rot * mtx_x90
- elif obj_type =='CAMERA':
- y = matrix_rot * Vector((0.0, 1.0, 0.0))
- matrix_rot = Matrix.Rotation(math.pi/2, 3, y) * matrix_rot
-
- return matrix_rot
-
- # ----------------------------------------------
-
-
-
-
-
- print('\nFBX export starting... %r' % filepath)
- start_time = time.clock()
- try:
- file = open(filepath, 'w')
- except:
- return False
-
- scene = context.scene
- world = scene.world
-
-
- # ---------------------------- Write the header first
- file.write(header_comment)
- if time:
- curtime = time.localtime()[0:6]
- else:
- curtime = (0,0,0,0,0,0)
- #
- file.write(\
-'''FBXHeaderExtension: {
- FBXHeaderVersion: 1003
- FBXVersion: 6100
- CreationTimeStamp: {
- Version: 1000
- Year: %.4i
- Month: %.2i
- Day: %.2i
- Hour: %.2i
- Minute: %.2i
- Second: %.2i
- Millisecond: 0
- }
- Creator: "FBX SDK/FBX Plugins build 20070228"
- OtherFlags: {
- FlagPLE: 0
- }
-}''' % (curtime))
-
- file.write('\nCreationTime: "%.4i-%.2i-%.2i %.2i:%.2i:%.2i:000"' % curtime)
- 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
-
- # --------------- funcs for exporting
- def object_tx(ob, loc, matrix, matrix_mod = None):
- '''
- Matrix mod is so armature objects can modify their bone matricies
- '''
- if isinstance(ob, bpy.types.Bone):
-# if isinstance(ob, Blender.Types.BoneType):
-
- # we know we have a matrix
- # matrix = mtx4_z90 * (ob.matrix['ARMATURESPACE'] * matrix_mod)
- 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 = parent.matrix_local * mtx4_z90 # dont apply armature matrix anymore
-# par_matrix = mtx4_z90 * parent.matrix['ARMATURESPACE'] # dont apply armature matrix anymore
- matrix = par_matrix.copy().invert() * matrix
-
- matrix_rot = matrix.rotation_part()
-
- loc = tuple(matrix.translation_part())
- scale = tuple(matrix.scale_part())
- rot = tuple(matrix_rot.to_euler())
-
- 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.matrix_world * GLOBAL_MATRIX
- if ob and not matrix: raise Exception("error: this should never happen!")
-
- matrix_rot = matrix
- #if matrix:
- # matrix = matrix_scale * matrix
-
- if matrix:
- loc = tuple(matrix.translation_part())
- scale = tuple(matrix.scale_part())
-
- matrix_rot = matrix.rotation_part()
- # Lamps need to be rotated
- if ob and ob.type =='LAMP':
- matrix_rot = matrix_rot * mtx_x90
- rot = tuple(matrix_rot.to_euler())
- elif ob and ob.type =='CAMERA':
- y = matrix_rot * Vector((0.0, 1.0, 0.0))
- matrix_rot = Matrix.Rotation(math.pi/2, 3, y) * matrix_rot
- rot = tuple(matrix_rot.to_euler())
- else:
- rot = tuple(matrix_rot.to_euler())
- else:
- if not loc:
- loc = 0,0,0
- scale = 1,1,1
- rot = 0,0,0
-
- return loc, rot, scale, matrix, matrix_rot
-
- def write_object_tx(ob, loc, matrix, matrix_mod= None):
- '''
- We have loc to set the location if non blender objects that have a location
-
- matrix_mod is only used for bones at the moment
- '''
- loc, rot, scale, matrix, matrix_rot = object_tx(ob, loc, matrix, matrix_mod)
-
- file.write('\n\t\t\tProperty: "Lcl Translation", "Lcl Translation", "A+",%.15f,%.15f,%.15f' % loc)
- file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % tuple(eulerRadToDeg(rot)))
-# file.write('\n\t\t\tProperty: "Lcl Rotation", "Lcl Rotation", "A+",%.15f,%.15f,%.15f' % rot)
- file.write('\n\t\t\tProperty: "Lcl Scaling", "Lcl Scaling", "A+",%.15f,%.15f,%.15f' % scale)
- return loc, rot, scale, matrix, matrix_rot
-
- def write_object_props(ob=None, loc=None, matrix=None, matrix_mod=None):
- # if the type is 0 its an empty otherwise its a mesh
- # only difference at the moment is one has a color
- file.write('''
- Properties60: {
- Property: "QuaternionInterpolate", "bool", "",0
- Property: "Visibility", "Visibility", "A+",1''')
-
- loc, rot, scale, matrix, matrix_rot = write_object_tx(ob, loc, matrix, matrix_mod)
-
- # Rotation order, note, for FBX files Iv loaded normal order is 1
- # setting to zero.
- # eEULER_XYZ = 0
- # eEULER_XZY
- # eEULER_YZX
- # eEULER_YXZ
- # eEULER_ZXY
- # eEULER_ZYX
-
- file.write('''
- Property: "RotationOffset", "Vector3D", "",0,0,0
- Property: "RotationPivot", "Vector3D", "",0,0,0
- Property: "ScalingOffset", "Vector3D", "",0,0,0
- Property: "ScalingPivot", "Vector3D", "",0,0,0
- Property: "TranslationActive", "bool", "",0
- Property: "TranslationMin", "Vector3D", "",0,0,0
- Property: "TranslationMax", "Vector3D", "",0,0,0
- Property: "TranslationMinX", "bool", "",0
- Property: "TranslationMinY", "bool", "",0
- Property: "TranslationMinZ", "bool", "",0
- Property: "TranslationMaxX", "bool", "",0
- Property: "TranslationMaxY", "bool", "",0
- Property: "TranslationMaxZ", "bool", "",0
- Property: "RotationOrder", "enum", "",0
- Property: "RotationSpaceForLimitOnly", "bool", "",0
- Property: "AxisLen", "double", "",10
- Property: "PreRotation", "Vector3D", "",0,0,0
- Property: "PostRotation", "Vector3D", "",0,0,0
- Property: "RotationActive", "bool", "",0
- Property: "RotationMin", "Vector3D", "",0,0,0
- Property: "RotationMax", "Vector3D", "",0,0,0
- Property: "RotationMinX", "bool", "",0
- Property: "RotationMinY", "bool", "",0
- Property: "RotationMinZ", "bool", "",0
- Property: "RotationMaxX", "bool", "",0
- Property: "RotationMaxY", "bool", "",0
- Property: "RotationMaxZ", "bool", "",0
- Property: "RotationStiffnessX", "double", "",0
- Property: "RotationStiffnessY", "double", "",0
- Property: "RotationStiffnessZ", "double", "",0
- Property: "MinDampRangeX", "double", "",0
- Property: "MinDampRangeY", "double", "",0
- Property: "MinDampRangeZ", "double", "",0
- Property: "MaxDampRangeX", "double", "",0
- Property: "MaxDampRangeY", "double", "",0
- Property: "MaxDampRangeZ", "double", "",0
- Property: "MinDampStrengthX", "double", "",0
- Property: "MinDampStrengthY", "double", "",0
- Property: "MinDampStrengthZ", "double", "",0
- Property: "MaxDampStrengthX", "double", "",0
- Property: "MaxDampStrengthY", "double", "",0
- Property: "MaxDampStrengthZ", "double", "",0
- Property: "PreferedAngleX", "double", "",0
- Property: "PreferedAngleY", "double", "",0
- Property: "PreferedAngleZ", "double", "",0
- Property: "InheritType", "enum", "",0
- Property: "ScalingActive", "bool", "",0
- Property: "ScalingMin", "Vector3D", "",1,1,1
- Property: "ScalingMax", "Vector3D", "",1,1,1
- Property: "ScalingMinX", "bool", "",0
- Property: "ScalingMinY", "bool", "",0
- Property: "ScalingMinZ", "bool", "",0
- Property: "ScalingMaxX", "bool", "",0
- Property: "ScalingMaxY", "bool", "",0
- Property: "ScalingMaxZ", "bool", "",0
- Property: "GeometricTranslation", "Vector3D", "",0,0,0
- Property: "GeometricRotation", "Vector3D", "",0,0,0
- Property: "GeometricScaling", "Vector3D", "",1,1,1
- Property: "LookAtProperty", "object", ""
- Property: "UpVectorProperty", "object", ""
- Property: "Show", "bool", "",1
- Property: "NegativePercentShapeSupport", "bool", "",1
- Property: "DefaultAttributeIndex", "int", "",0''')
- if ob and not isinstance(ob, bpy.types.Bone):
- # Only mesh objects have color
- file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8')
- file.write('\n\t\t\tProperty: "Size", "double", "",100')
- file.write('\n\t\t\tProperty: "Look", "enum", "",1')
-
- return loc, rot, scale, matrix, matrix_rot
-
-
- # -------------------------------------------- Armatures
- #def write_bone(bone, name, matrix_mod):
- def write_bone(my_bone):
- file.write('\n\tModel: "Model::%s", "Limb" {' % my_bone.fbxName)
- file.write('\n\t\tVersion: 232')
-
- #poseMatrix = write_object_props(my_bone.blenBone, None, None, my_bone.fbxArm.parRelMatrix())[3]
- poseMatrix = write_object_props(my_bone.blenBone)[3] # dont apply bone matricies anymore
- pose_items.append( (my_bone.fbxName, poseMatrix) )
-
-
- # file.write('\n\t\t\tProperty: "Size", "double", "",%.6f' % ((my_bone.blenData.head['ARMATURESPACE'] - my_bone.blenData.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length)
- file.write('\n\t\t\tProperty: "Size", "double", "",1')
-
- #((my_bone.blenData.head['ARMATURESPACE'] * my_bone.fbxArm.matrixWorld) - (my_bone.blenData.tail['ARMATURESPACE'] * my_bone.fbxArm.parRelMatrix())).length)
-
- """
- file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %\
- ((my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']) * my_bone.fbxArm.parRelMatrix()).length)
- """
-
- file.write('\n\t\t\tProperty: "LimbLength", "double", "",%.6f' %
- (my_bone.blenBone.head_local - my_bone.blenBone.tail_local).length)
-# (my_bone.blenBone.head['ARMATURESPACE'] - my_bone.blenBone.tail['ARMATURESPACE']).length)
-
- #file.write('\n\t\t\tProperty: "LimbLength", "double", "",1')
- file.write('\n\t\t\tProperty: "Color", "ColorRGB", "",0.8,0.8,0.8')
- file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8')
- file.write('\n\t\t}')
- file.write('\n\t\tMultiLayer: 0')
- file.write('\n\t\tMultiTake: 1')
- file.write('\n\t\tShading: Y')
- file.write('\n\t\tCulling: "CullingOff"')
- file.write('\n\t\tTypeFlags: "Skeleton"')
- file.write('\n\t}')
-
- def write_camera_switch():
- file.write('''
- Model: "Model::Camera Switcher", "CameraSwitcher" {
- Version: 232''')
-
- write_object_props()
- file.write('''
- Property: "Color", "Color", "A",0.8,0.8,0.8
- Property: "Camera Index", "Integer", "A+",100
- }
- MultiLayer: 0
- MultiTake: 1
- Hidden: "True"
- Shading: W
- Culling: "CullingOff"
- Version: 101
- Name: "Model::Camera Switcher"
- CameraId: 0
- CameraName: 100
- CameraIndexName:
- }''')
-
- def write_camera_dummy(name, loc, near, far, proj_type, up):
- file.write('\n\tModel: "Model::%s", "Camera" {' % name )
- file.write('\n\t\tVersion: 232')
- write_object_props(None, loc)
-
- file.write('\n\t\t\tProperty: "Color", "Color", "A",0.8,0.8,0.8')
- file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0')
- file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",40')
- file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1')
- file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1')
- file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",0')
- file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",0')
- file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0.63,0.63,0.63')
- file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0')
- file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1')
- file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1')
- file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0')
- file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1')
- file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0')
- file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2')
- file.write('\n\t\t\tProperty: "GateFit", "enum", "",0')
- file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",21.3544940948486')
- file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0')
- file.write('\n\t\t\tProperty: "AspectW", "double", "",320')
- file.write('\n\t\t\tProperty: "AspectH", "double", "",200')
- file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",1')
- file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0')
- file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3')
- file.write('\n\t\t\tProperty: "ShowName", "bool", "",1')
- file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1')
- file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0')
- file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1')
- file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0')
- file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % near)
- file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % far)
- file.write('\n\t\t\tProperty: "FilmWidth", "double", "",0.816')
- file.write('\n\t\t\tProperty: "FilmHeight", "double", "",0.612')
- file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",1.33333333333333')
- file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1')
- file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",4')
- file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1')
- file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0')
- file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2')
- file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100')
- file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0')
- file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1')
- file.write('\n\t\t\tProperty: "LockMode", "bool", "",0')
- file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0')
- file.write('\n\t\t\tProperty: "FitImage", "bool", "",0')
- file.write('\n\t\t\tProperty: "Crop", "bool", "",0')
- file.write('\n\t\t\tProperty: "Center", "bool", "",1')
- file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1')
- file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0')
- file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5')
- file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1')
- file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0')
- file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1')
- file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",1.33333333333333')
- file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0')
- file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100')
- file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50')
- file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50')
- file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",%i' % proj_type)
- file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0')
- file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0')
- file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0')
- file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5')
- file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200')
- file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0')
- file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777')
- file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0')
- file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7')
- file.write('\n\t\t}')
- file.write('\n\t\tMultiLayer: 0')
- file.write('\n\t\tMultiTake: 0')
- file.write('\n\t\tHidden: "True"')
- file.write('\n\t\tShading: Y')
- file.write('\n\t\tCulling: "CullingOff"')
- 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: %i,%i,%i' % up)
- file.write('\n\t\tLookAt: 0,0,0')
- file.write('\n\t\tShowInfoOnMoving: 1')
- file.write('\n\t\tShowAudio: 0')
- file.write('\n\t\tAudioColor: 0,1,0')
- file.write('\n\t\tCameraOrthoZoom: 1')
- file.write('\n\t}')
-
- def write_camera_default():
- # This sucks but to match FBX converter its easier to
- # write the cameras though they are not needed.
- write_camera_dummy('Producer Perspective', (0,71.3,287.5), 10, 4000, 0, (0,1,0))
- write_camera_dummy('Producer Top', (0,4000,0), 1, 30000, 1, (0,0,-1))
- write_camera_dummy('Producer Bottom', (0,-4000,0), 1, 30000, 1, (0,0,-1))
- write_camera_dummy('Producer Front', (0,0,4000), 1, 30000, 1, (0,1,0))
- write_camera_dummy('Producer Back', (0,0,-4000), 1, 30000, 1, (0,1,0))
- write_camera_dummy('Producer Right', (4000,0,0), 1, 30000, 1, (0,1,0))
- write_camera_dummy('Producer Left', (-4000,0,0), 1, 30000, 1, (0,1,0))
-
- def write_camera(my_cam):
- '''
- Write a blender camera
- '''
- render = scene.render
- width = render.resolution_x
- height = render.resolution_y
- aspect = width / height
-
- data = my_cam.blenObject.data
-
- file.write('\n\tModel: "Model::%s", "Camera" {' % my_cam.fbxName )
- file.write('\n\t\tVersion: 232')
- loc, rot, scale, matrix, matrix_rot = write_object_props(my_cam.blenObject, None, my_cam.parRelMatrix())
-
- file.write('\n\t\t\tProperty: "Roll", "Roll", "A+",0')
- file.write('\n\t\t\tProperty: "FieldOfView", "FieldOfView", "A+",%.6f' % math.degrees(data.angle))
- file.write('\n\t\t\tProperty: "FieldOfViewX", "FieldOfView", "A+",1')
- file.write('\n\t\t\tProperty: "FieldOfViewY", "FieldOfView", "A+",1')
- # file.write('\n\t\t\tProperty: "FocalLength", "Real", "A+",14.0323972702026')
- file.write('\n\t\t\tProperty: "OpticalCenterX", "Real", "A+",%.6f' % data.shift_x) # not sure if this is in the correct units?
- file.write('\n\t\t\tProperty: "OpticalCenterY", "Real", "A+",%.6f' % data.shift_y) # ditto
- file.write('\n\t\t\tProperty: "BackgroundColor", "Color", "A+",0,0,0')
- file.write('\n\t\t\tProperty: "TurnTable", "Real", "A+",0')
- file.write('\n\t\t\tProperty: "DisplayTurnTableIcon", "bool", "",1')
- file.write('\n\t\t\tProperty: "Motion Blur Intensity", "Real", "A+",1')
- file.write('\n\t\t\tProperty: "UseMotionBlur", "bool", "",0')
- file.write('\n\t\t\tProperty: "UseRealTimeMotionBlur", "bool", "",1')
- file.write('\n\t\t\tProperty: "ResolutionMode", "enum", "",0')
- file.write('\n\t\t\tProperty: "ApertureMode", "enum", "",2')
- file.write('\n\t\t\tProperty: "GateFit", "enum", "",2')
- file.write('\n\t\t\tProperty: "CameraFormat", "enum", "",0')
- file.write('\n\t\t\tProperty: "AspectW", "double", "",%i' % width)
- file.write('\n\t\t\tProperty: "AspectH", "double", "",%i' % height)
-
- '''Camera aspect ratio modes.
- 0 If the ratio mode is eWINDOW_SIZE, both width and height values aren't relevant.
- 1 If the ratio mode is eFIXED_RATIO, the height value is set to 1.0 and the width value is relative to the height value.
- 2 If the ratio mode is eFIXED_RESOLUTION, both width and height values are in pixels.
- 3 If the ratio mode is eFIXED_WIDTH, the width value is in pixels and the height value is relative to the width value.
- 4 If the ratio mode is eFIXED_HEIGHT, the height value is in pixels and the width value is relative to the height value.
-
- Definition at line 234 of file kfbxcamera.h. '''
-
- file.write('\n\t\t\tProperty: "PixelAspectRatio", "double", "",2')
-
- file.write('\n\t\t\tProperty: "UseFrameColor", "bool", "",0')
- file.write('\n\t\t\tProperty: "FrameColor", "ColorRGB", "",0.3,0.3,0.3')
- file.write('\n\t\t\tProperty: "ShowName", "bool", "",1')
- file.write('\n\t\t\tProperty: "ShowGrid", "bool", "",1')
- file.write('\n\t\t\tProperty: "ShowOpticalCenter", "bool", "",0')
- file.write('\n\t\t\tProperty: "ShowAzimut", "bool", "",1')
- file.write('\n\t\t\tProperty: "ShowTimeCode", "bool", "",0')
- file.write('\n\t\t\tProperty: "NearPlane", "double", "",%.6f' % data.clip_start)
- file.write('\n\t\t\tProperty: "FarPlane", "double", "",%.6f' % data.clip_end)
- file.write('\n\t\t\tProperty: "FilmWidth", "double", "",1.0')
- file.write('\n\t\t\tProperty: "FilmHeight", "double", "",1.0')
- file.write('\n\t\t\tProperty: "FilmAspectRatio", "double", "",%.6f' % aspect)
- file.write('\n\t\t\tProperty: "FilmSqueezeRatio", "double", "",1')
- file.write('\n\t\t\tProperty: "FilmFormatIndex", "enum", "",0')
- file.write('\n\t\t\tProperty: "ViewFrustum", "bool", "",1')
- file.write('\n\t\t\tProperty: "ViewFrustumNearFarPlane", "bool", "",0')
- file.write('\n\t\t\tProperty: "ViewFrustumBackPlaneMode", "enum", "",2')
- file.write('\n\t\t\tProperty: "BackPlaneDistance", "double", "",100')
- file.write('\n\t\t\tProperty: "BackPlaneDistanceMode", "enum", "",0')
- file.write('\n\t\t\tProperty: "ViewCameraToLookAt", "bool", "",1')
- file.write('\n\t\t\tProperty: "LockMode", "bool", "",0')
- file.write('\n\t\t\tProperty: "LockInterestNavigation", "bool", "",0')
- file.write('\n\t\t\tProperty: "FitImage", "bool", "",0')
- file.write('\n\t\t\tProperty: "Crop", "bool", "",0')
- file.write('\n\t\t\tProperty: "Center", "bool", "",1')
- file.write('\n\t\t\tProperty: "KeepRatio", "bool", "",1')
- file.write('\n\t\t\tProperty: "BackgroundMode", "enum", "",0')
- file.write('\n\t\t\tProperty: "BackgroundAlphaTreshold", "double", "",0.5')
- file.write('\n\t\t\tProperty: "ForegroundTransparent", "bool", "",1')
- file.write('\n\t\t\tProperty: "DisplaySafeArea", "bool", "",0')
- file.write('\n\t\t\tProperty: "SafeAreaDisplayStyle", "enum", "",1')
- file.write('\n\t\t\tProperty: "SafeAreaAspectRatio", "double", "",%.6f' % aspect)
- file.write('\n\t\t\tProperty: "Use2DMagnifierZoom", "bool", "",0')
- file.write('\n\t\t\tProperty: "2D Magnifier Zoom", "Real", "A+",100')
- file.write('\n\t\t\tProperty: "2D Magnifier X", "Real", "A+",50')
- file.write('\n\t\t\tProperty: "2D Magnifier Y", "Real", "A+",50')
- file.write('\n\t\t\tProperty: "CameraProjectionType", "enum", "",0')
- file.write('\n\t\t\tProperty: "UseRealTimeDOFAndAA", "bool", "",0')
- file.write('\n\t\t\tProperty: "UseDepthOfField", "bool", "",0')
- file.write('\n\t\t\tProperty: "FocusSource", "enum", "",0')
- file.write('\n\t\t\tProperty: "FocusAngle", "double", "",3.5')
- file.write('\n\t\t\tProperty: "FocusDistance", "double", "",200')
- file.write('\n\t\t\tProperty: "UseAntialiasing", "bool", "",0')
- file.write('\n\t\t\tProperty: "AntialiasingIntensity", "double", "",0.77777')
- file.write('\n\t\t\tProperty: "UseAccumulationBuffer", "bool", "",0')
- file.write('\n\t\t\tProperty: "FrameSamplingCount", "int", "",7')
-
- file.write('\n\t\t}')
- file.write('\n\t\tMultiLayer: 0')
- file.write('\n\t\tMultiTake: 0')
- file.write('\n\t\tShading: Y')
- file.write('\n\t\tCulling: "CullingOff"')
- 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(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' )
-
- file.write('\n\t\tShowInfoOnMoving: 1')
- file.write('\n\t\tShowAudio: 0')
- file.write('\n\t\tAudioColor: 0,1,0')
- file.write('\n\t\tCameraOrthoZoom: 1')
- file.write('\n\t}')
-
- def write_light(my_light):
- light = my_light.blenObject.data
- file.write('\n\tModel: "Model::%s", "Light" {' % my_light.fbxName)
- file.write('\n\t\tVersion: 232')
-
- write_object_props(my_light.blenObject, None, my_light.parRelMatrix())
-
- # Why are these values here twice?????? - oh well, follow the holy sdk's output
-
- # Blender light types match FBX's, funny coincidence, we just need to
- # be sure that all unsupported types are made into a point light
- #ePOINT,
- #eDIRECTIONAL
- #eSPOT
- light_type_items = {'POINT': 0, 'SUN': 1, 'SPOT': 2, 'HEMI': 3, 'AREA': 4}
- light_type = light_type_items[light.type]
-
- if light_type > 2: light_type = 1 # hemi and area lights become directional
-
-# mode = light.mode
- if light.shadow_method == 'RAY_SHADOW' or light.shadow_method == 'BUFFER_SHADOW':
-# if mode & Blender.Lamp.Modes.RayShadow or mode & Blender.Lamp.Modes.Shadows:
- do_shadow = 1
- else:
- do_shadow = 0
-
- if light.use_only_shadow or (not light.use_diffuse and not light.use_specular):
-# if mode & Blender.Lamp.Modes.OnlyShadow or (mode & Blender.Lamp.Modes.NoDiffuse and mode & Blender.Lamp.Modes.NoSpecular):
- do_light = 0
- else:
- do_light = 1
-
- scale = abs(GLOBAL_MATRIX.scale_part()[0]) # scale is always uniform in this case
-
- file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type)
- file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",1')
- file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1')
- file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1')
- file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0')
- file.write('\n\t\t\tProperty: "GoboProperty", "object", ""')
- file.write('\n\t\t\tProperty: "Color", "Color", "A+",1,1,1')
- file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200
- if light.type == 'SPOT':
- file.write('\n\t\t\tProperty: "Cone angle", "Cone angle", "A+",%.2f' % math.degrees(light.spot_size))
- file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50')
- file.write('\n\t\t\tProperty: "Color", "Color", "A",%.2f,%.2f,%.2f' % tuple(light.color))
-
- file.write('\n\t\t\tProperty: "Intensity", "Intensity", "A+",%.2f' % (min(light.energy*100, 200))) # clamp below 200
-
- file.write('\n\t\t\tProperty: "Fog", "Fog", "A+",50')
- file.write('\n\t\t\tProperty: "LightType", "enum", "",%i' % light_type)
- file.write('\n\t\t\tProperty: "CastLightOnObject", "bool", "",%i' % do_light)
- file.write('\n\t\t\tProperty: "DrawGroundProjection", "bool", "",1')
- file.write('\n\t\t\tProperty: "DrawFrontFacingVolumetricLight", "bool", "",0')
- file.write('\n\t\t\tProperty: "DrawVolumetricLight", "bool", "",1')
- file.write('\n\t\t\tProperty: "GoboProperty", "object", ""')
- file.write('\n\t\t\tProperty: "DecayType", "enum", "",0')
- file.write('\n\t\t\tProperty: "DecayStart", "double", "",%.2f' % light.distance)
- file.write('\n\t\t\tProperty: "EnableNearAttenuation", "bool", "",0')
- file.write('\n\t\t\tProperty: "NearAttenuationStart", "double", "",0')
- file.write('\n\t\t\tProperty: "NearAttenuationEnd", "double", "",0')
- file.write('\n\t\t\tProperty: "EnableFarAttenuation", "bool", "",0')
- file.write('\n\t\t\tProperty: "FarAttenuationStart", "double", "",0')
- file.write('\n\t\t\tProperty: "FarAttenuationEnd", "double", "",0')
- file.write('\n\t\t\tProperty: "CastShadows", "bool", "",%i' % do_shadow)
- file.write('\n\t\t\tProperty: "ShadowColor", "ColorRGBA", "",0,0,0,1')
- file.write('\n\t\t}')
- file.write('\n\t\tMultiLayer: 0')
- file.write('\n\t\tMultiTake: 0')
- file.write('\n\t\tShading: Y')
- file.write('\n\t\tCulling: "CullingOff"')
- file.write('\n\t\tTypeFlags: "Light"')
- file.write('\n\t\tGeometryVersion: 124')
- file.write('\n\t}')
-
- # matrixOnly is not used at the moment
- def write_null(my_null = None, fbxName = None, matrixOnly = None):
- # ob can be null
- if not fbxName: fbxName = my_null.fbxName
-
- file.write('\n\tModel: "Model::%s", "Null" {' % fbxName)
- file.write('\n\t\tVersion: 232')
-
- # only use this for the root matrix at the moment
- if matrixOnly:
- poseMatrix = write_object_props(None, None, matrixOnly)[3]
-
- else: # all other Null's
- if my_null: poseMatrix = write_object_props(my_null.blenObject, None, my_null.parRelMatrix())[3]
- else: poseMatrix = write_object_props()[3]
-
- pose_items.append((fbxName, poseMatrix))
-
- file.write('''
- }
- MultiLayer: 0
- MultiTake: 1
- Shading: Y
- Culling: "CullingOff"
- TypeFlags: "Null"
- }''')
-
- # Material Settings
- if world: world_amb = tuple(world.ambient_color)
-# if world: world_amb = world.getAmb()
- else: world_amb = (0,0,0) # Default value
-
- def write_material(matname, mat):
- file.write('\n\tMaterial: "Material::%s", "" {' % matname)
-
- # Todo, add more material Properties.
- if mat:
- mat_cold = tuple(mat.diffuse_color)
- mat_cols = tuple(mat.specular_color)
- #mat_colm = tuple(mat.mirCol) # we wont use the mirror color
- mat_colamb = world_amb
-
- mat_dif = mat.diffuse_intensity
- mat_amb = mat.ambient
- mat_hard = (float(mat.specular_hardness)-1)/5.10
- mat_spec = mat.specular_intensity/2.0
- mat_alpha = mat.alpha
- mat_emit = mat.emit
- mat_shadeless = mat.use_shadeless
- if mat_shadeless:
- mat_shader = 'Lambert'
- else:
- if mat.diffuse_shader == 'LAMBERT':
- mat_shader = 'Lambert'
- else:
- mat_shader = 'Phong'
- else:
- mat_cols = mat_cold = 0.8, 0.8, 0.8
- mat_colamb = 0.0,0.0,0.0
- # mat_colm
- mat_dif = 1.0
- mat_amb = 0.5
- mat_hard = 20.0
- mat_spec = 0.2
- mat_alpha = 1.0
- mat_emit = 0.0
- mat_shadeless = False
- mat_shader = 'Phong'
-
- file.write('\n\t\tVersion: 102')
- file.write('\n\t\tShadingModel: "%s"' % mat_shader.lower())
- file.write('\n\t\tMultiLayer: 0')
-
- file.write('\n\t\tProperties60: {')
- file.write('\n\t\t\tProperty: "ShadingModel", "KString", "", "%s"' % mat_shader)
- file.write('\n\t\t\tProperty: "MultiLayer", "bool", "",0')
- file.write('\n\t\t\tProperty: "EmissiveColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold) # emit and diffuse color are he same in blender
- file.write('\n\t\t\tProperty: "EmissiveFactor", "double", "",%.4f' % mat_emit)
-
- file.write('\n\t\t\tProperty: "AmbientColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_colamb)
- file.write('\n\t\t\tProperty: "AmbientFactor", "double", "",%.4f' % mat_amb)
- file.write('\n\t\t\tProperty: "DiffuseColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cold)
- file.write('\n\t\t\tProperty: "DiffuseFactor", "double", "",%.4f' % mat_dif)
- file.write('\n\t\t\tProperty: "Bump", "Vector3D", "",0,0,0')
- file.write('\n\t\t\tProperty: "TransparentColor", "ColorRGB", "",1,1,1')
- file.write('\n\t\t\tProperty: "TransparencyFactor", "double", "",%.4f' % (1.0 - mat_alpha))
- if not mat_shadeless:
- file.write('\n\t\t\tProperty: "SpecularColor", "ColorRGB", "",%.4f,%.4f,%.4f' % mat_cols)
- file.write('\n\t\t\tProperty: "SpecularFactor", "double", "",%.4f' % mat_spec)
- file.write('\n\t\t\tProperty: "ShininessExponent", "double", "",80.0')
- file.write('\n\t\t\tProperty: "ReflectionColor", "ColorRGB", "",0,0,0')
- file.write('\n\t\t\tProperty: "ReflectionFactor", "double", "",1')
- file.write('\n\t\t\tProperty: "Emissive", "ColorRGB", "",0,0,0')
- file.write('\n\t\t\tProperty: "Ambient", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_colamb)
- file.write('\n\t\t\tProperty: "Diffuse", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cold)
- if not mat_shadeless:
- file.write('\n\t\t\tProperty: "Specular", "ColorRGB", "",%.1f,%.1f,%.1f' % mat_cols)
- file.write('\n\t\t\tProperty: "Shininess", "double", "",%.1f' % mat_hard)
- file.write('\n\t\t\tProperty: "Opacity", "double", "",%.1f' % mat_alpha)
- if not mat_shadeless:
- file.write('\n\t\t\tProperty: "Reflectivity", "double", "",0')
-
- file.write('\n\t\t}')
- file.write('\n\t}')
-
- def copy_image(image):
- fn = bpy.path.abspath(image.filepath)
- fn_strip = os.path.basename(fn)
-
- if EXP_IMAGE_COPY:
- rel = fn_strip
- fn_abs_dest = os.path.join(basepath, fn_strip)
- if not os.path.exists(fn_abs_dest):
- shutil.copy(fn, fn_abs_dest)
- else:
- rel = os.path.relpath(fn, basepath)
-
- return (rel, fn_strip)
-
- # tex is an Image (Arystan)
- def write_video(texname, tex):
- # Same as texture really!
- file.write('\n\tVideo: "Video::%s", "Clip" {' % texname)
-
- file.write('''
- Type: "Clip"
- Properties60: {
- Property: "FrameRate", "double", "",0
- Property: "LastFrame", "int", "",0
- Property: "Width", "int", "",0
- Property: "Height", "int", "",0''')
- if tex:
- fname_rel, fname_strip = copy_image(tex)
-# fname, fname_strip, fname_rel = derived_paths(tex.filepath, basepath, EXP_IMAGE_COPY)
- else:
- fname = fname_strip = fname_rel = ''
-
- file.write('\n\t\t\tProperty: "Path", "charptr", "", "%s"' % fname_strip)
-
-
- file.write('''
- Property: "StartFrame", "int", "",0
- Property: "StopFrame", "int", "",0
- Property: "PlaySpeed", "double", "",1
- Property: "Offset", "KTime", "",0
- Property: "InterlaceMode", "enum", "",0
- Property: "FreeRunning", "bool", "",0
- Property: "Loop", "bool", "",0
- Property: "AccessMode", "enum", "",0
- }
- UseMipMap: 0''')
-
- file.write('\n\t\tFilename: "%s"' % fname_strip)
- if fname_strip: fname_strip = '/' + fname_strip
- file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # make relative
- file.write('\n\t}')
-
-
- def write_texture(texname, tex, num):
- # if tex is None then this is a dummy tex
- file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {' % texname)
- file.write('\n\t\tType: "TextureVideoClip"')
- file.write('\n\t\tVersion: 202')
- # TODO, rare case _empty_ exists as a name.
- file.write('\n\t\tTextureName: "Texture::%s"' % texname)
-
- file.write('''
- Properties60: {
- Property: "Translation", "Vector", "A+",0,0,0
- Property: "Rotation", "Vector", "A+",0,0,0
- Property: "Scaling", "Vector", "A+",1,1,1''')
- file.write('\n\t\t\tProperty: "Texture alpha", "Number", "A+",%i' % num)
-
-
- # WrapModeU/V 0==rep, 1==clamp, TODO add support
- file.write('''
- Property: "TextureTypeUse", "enum", "",0
- Property: "CurrentTextureBlendMode", "enum", "",1
- Property: "UseMaterial", "bool", "",0
- Property: "UseMipMap", "bool", "",0
- Property: "CurrentMappingType", "enum", "",0
- Property: "UVSwap", "bool", "",0''')
-
- file.write('\n\t\t\tProperty: "WrapModeU", "enum", "",%i' % tex.use_clamp_x)
- file.write('\n\t\t\tProperty: "WrapModeV", "enum", "",%i' % tex.use_clamp_y)
-
- file.write('''
- Property: "TextureRotationPivot", "Vector3D", "",0,0,0
- Property: "TextureScalingPivot", "Vector3D", "",0,0,0
- Property: "VideoProperty", "object", ""
- }''')
-
- file.write('\n\t\tMedia: "Video::%s"' % texname)
-
- if tex:
- fname_rel, fname_strip = copy_image(tex)
-# fname, fname_strip, fname_rel = derived_paths(tex.filepath, basepath, EXP_IMAGE_COPY)
- else:
- fname = fname_strip = fname_rel = ''
-
- file.write('\n\t\tFileName: "%s"' % fname_strip)
- file.write('\n\t\tRelativeFilename: "%s"' % fname_rel) # need some make relative command
-
- file.write('''
- ModelUVTranslation: 0,0
- ModelUVScaling: 1,1
- Texture_Alpha_Source: "None"
- Cropping: 0,0,0,0
- }''')
-
- def write_deformer_skin(obname):
- '''
- Each mesh has its own deformer
- '''
- file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {' % obname)
- file.write('''
- Version: 100
- MultiLayer: 0
- Type: "Skin"
- Properties60: {
- }
- Link_DeformAcuracy: 50
- }''')
-
- # in the example was 'Bip01 L Thigh_2'
- def write_sub_deformer_skin(my_mesh, my_bone, weights):
-
- '''
- Each subdeformer is spesific to a mesh, but the bone it links to can be used by many sub-deformers
- So the SubDeformer needs the mesh-object name as a prefix to make it unique
-
- Its possible that there is no matching vgroup in this mesh, in that case no verts are in the subdeformer,
- a but silly but dosnt really matter
- '''
- file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {' % (my_mesh.fbxName, my_bone.fbxName))
-
- file.write('''
- Version: 100
- MultiLayer: 0
- Type: "Cluster"
- Properties60: {
- Property: "SrcModel", "object", ""
- Property: "SrcModelReference", "object", ""
- }
- UserData: "", ""''')
-
- # Support for bone parents
- if my_mesh.fbxBoneParent:
- if my_mesh.fbxBoneParent == my_bone:
- # TODO - this is a bit lazy, we could have a simple write loop
- # for this case because all weights are 1.0 but for now this is ok
- # Parent Bones arent used all that much anyway.
- vgroup_data = [(j, 1.0) for j in range(len(my_mesh.blenData.vertices))]
- else:
- # This bone is not a parent of this mesh object, no weights
- vgroup_data = []
-
- else:
- # Normal weight painted mesh
- if my_bone.blenName in weights[0]:
- # Before we used normalized wright list
- #vgroup_data = me.getVertsFromGroup(bone.name, 1)
- group_index = weights[0].index(my_bone.blenName)
- vgroup_data = [(j, weight[group_index]) for j, weight in enumerate(weights[1]) if weight[group_index]]
- else:
- vgroup_data = []
-
- file.write('\n\t\tIndexes: ')
-
- i = -1
- for vg in vgroup_data:
- if i == -1:
- file.write('%i' % vg[0])
- i=0
- else:
- if i==23:
- file.write('\n\t\t')
- i=0
- file.write(',%i' % vg[0])
- i+=1
-
- file.write('\n\t\tWeights: ')
- i = -1
- for vg in vgroup_data:
- if i == -1:
- file.write('%.8f' % vg[1])
- i=0
- else:
- if i==38:
- file.write('\n\t\t')
- i=0
- file.write(',%.8f' % vg[1])
- i+=1
-
- if my_mesh.fbxParent:
- # TODO FIXME, this case is broken in some cases. skinned meshes just shouldnt have parents where possible!
- 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 = (my_mesh.matrixWorld.copy().invert() * my_bone.fbxArm.matrixWorld.copy() * my_bone.restMatrix) * mtx4_z90
-
- #m = mtx4_z90 * my_bone.restMatrix
- matstr = mat4x4str(m)
- matstr_i = mat4x4str(m.invert())
-
- file.write('\n\t\tTransform: %s' % matstr_i) # THIS IS __NOT__ THE GLOBAL MATRIX AS DOCUMENTED :/
- file.write('\n\t\tTransformLink: %s' % matstr)
- file.write('\n\t}')
-
- def write_mesh(my_mesh):
-
- me = my_mesh.blenData
-
- # if there are non NULL materials on this mesh
- if my_mesh.blenMaterials: do_materials = True
- else: do_materials = False
-
- if my_mesh.blenTextures: do_textures = True
- else: do_textures = False
-
- do_uvs = bool(me.uv_textures)
-
-
- file.write('\n\tModel: "Model::%s", "Mesh" {' % my_mesh.fbxName)
- file.write('\n\t\tVersion: 232') # newline is added in write_object_props
-
- poseMatrix = write_object_props(my_mesh.blenObject, None, my_mesh.parRelMatrix())[3]
- pose_items.append((my_mesh.fbxName, poseMatrix))
-
- file.write('\n\t\t}')
- file.write('\n\t\tMultiLayer: 0')
- file.write('\n\t\tMultiTake: 1')
- file.write('\n\t\tShading: Y')
- file.write('\n\t\tCulling: "CullingOff"')
-
-
- # Write the Real Mesh data here
- file.write('\n\t\tVertices: ')
- i=-1
-
- for v in me.vertices:
- if i==-1:
- file.write('%.6f,%.6f,%.6f' % tuple(v.co)); i=0
- else:
- if i==7:
- file.write('\n\t\t'); i=0
- file.write(',%.6f,%.6f,%.6f'% tuple(v.co))
- i+=1
-
- file.write('\n\t\tPolygonVertexIndex: ')
- i=-1
- for f in me.faces:
- fi = f.vertices[:]
-
- # 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 )
- else: file.write('%i,%i,%i,%i' % fi )
- i=0
- else:
- if i==13:
- file.write('\n\t\t')
- i=0
- if len(fi) == 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.is_loose:
- ed_val = ed.vertices[:]
- 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:
- if i==-1:
- file.write('%i,%i' % (ed.vertices[0], ed.vertices[1]))
- i=0
- else:
- if i==13:
- file.write('\n\t\t')
- i=0
- file.write(',%i,%i' % (ed.vertices[0], ed.vertices[1]))
- i+=1
-
- file.write('\n\t\tGeometryVersion: 124')
-
- file.write('''
- LayerElementNormal: 0 {
- Version: 101
- Name: ""
- MappingInformationType: "ByVertice"
- ReferenceInformationType: "Direct"
- Normals: ''')
-
- i=-1
- for v in me.vertices:
- if i==-1:
- file.write('%.15f,%.15f,%.15f' % tuple(v.normal)); i=0
- else:
- if i==2:
- file.write('\n '); i=0
- file.write(',%.15f,%.15f,%.15f' % tuple(v.normal))
- i+=1
- file.write('\n\t\t}')
-
- # Write Face Smoothing
- file.write('''
- LayerElementSmoothing: 0 {
- Version: 102
- Name: ""
- MappingInformationType: "ByPolygon"
- ReferenceInformationType: "Direct"
- Smoothing: ''')
-
- i=-1
- for f in me.faces:
- if i==-1:
- file.write('%i' % f.use_smooth); i=0
- else:
- if i==54:
- file.write('\n '); i=0
- file.write(',%i' % f.use_smooth)
- i+=1
-
- file.write('\n\t\t}')
-
- # Write Edge Smoothing
- file.write('''
- LayerElementSmoothing: 0 {
- Version: 101
- Name: ""
- MappingInformationType: "ByEdge"
- ReferenceInformationType: "Direct"
- Smoothing: ''')
-
- i=-1
- for ed in me.edges:
- if i==-1:
- file.write('%i' % (ed.use_edge_sharp)); i=0
- else:
- if i==54:
- file.write('\n '); i=0
- file.write(',%i' % (ed.use_edge_sharp))
- i+=1
-
- file.write('\n\t\t}')
-
- # small utility function
- # returns a slice of data depending on number of face verts
- # data is either a MeshTextureFace or MeshColor
- def face_data(data, face):
- totvert = len(f.vertices)
-
- return data[:totvert]
-
-
- # Write VertexColor Layers
- # note, no programs seem to use this info :/
- collayers = []
- if len(me.vertex_colors):
- collayers = me.vertex_colors
- for colindex, collayer in enumerate(collayers):
- file.write('\n\t\tLayerElementColor: %i {' % colindex)
- file.write('\n\t\t\tVersion: 101')
- file.write('\n\t\t\tName: "%s"' % collayer.name)
-
- file.write('''
- MappingInformationType: "ByPolygonVertex"
- ReferenceInformationType: "IndexToDirect"
- Colors: ''')
-
- i = -1
- ii = 0 # Count how many Colors we write
-
- for f, cf in zip(me.faces, collayer.data):
- colors = [cf.color1, cf.color2, cf.color3, cf.color4]
-
- # determine number of verts
- colors = face_data(colors, f)
-
- for col in colors:
- if i==-1:
- file.write('%.4f,%.4f,%.4f,1' % tuple(col))
- i=0
- else:
- if i==7:
- file.write('\n\t\t\t\t')
- i=0
- file.write(',%.4f,%.4f,%.4f,1' % tuple(col))
- i+=1
- ii+=1 # One more Color
-
- file.write('\n\t\t\tColorIndex: ')
- i = -1
- for j in range(ii):
- if i == -1:
- file.write('%i' % j)
- i=0
- else:
- if i==55:
- file.write('\n\t\t\t\t')
- i=0
- file.write(',%i' % j)
- i+=1
-
- file.write('\n\t\t}')
-
-
-
- # Write UV and texture layers.
- uvlayers = []
- if do_uvs:
- uvlayers = me.uv_textures
- uvlayer_orig = me.uv_textures.active
- for uvindex, uvlayer in enumerate(me.uv_textures):
- file.write('\n\t\tLayerElementUV: %i {' % uvindex)
- file.write('\n\t\t\tVersion: 101')
- file.write('\n\t\t\tName: "%s"' % uvlayer.name)
-
- file.write('''
- MappingInformationType: "ByPolygonVertex"
- ReferenceInformationType: "IndexToDirect"
- UV: ''')
-
- i = -1
- ii = 0 # Count how many UVs we write
-
- for uf in uvlayer.data:
- # workaround, since uf.uv iteration is wrong atm
- for uv in uf.uv:
- if i==-1:
- file.write('%.6f,%.6f' % tuple(uv))
- i=0
- else:
- if i==7:
- file.write('\n ')
- i=0
- file.write(',%.6f,%.6f' % tuple(uv))
- i+=1
- ii+=1 # One more UV
-
- file.write('\n\t\t\tUVIndex: ')
- i = -1
- for j in range(ii):
- if i == -1:
- file.write('%i' % j)
- i=0
- else:
- if i==55:
- file.write('\n\t\t\t\t')
- i=0
- file.write(',%i' % j)
- i+=1
-
- file.write('\n\t\t}')
-
- if do_textures:
- file.write('\n\t\tLayerElementTexture: %i {' % uvindex)
- file.write('\n\t\t\tVersion: 101')
- file.write('\n\t\t\tName: "%s"' % uvlayer.name)
-
- if len(my_mesh.blenTextures) == 1:
- file.write('\n\t\t\tMappingInformationType: "AllSame"')
- else:
- file.write('\n\t\t\tMappingInformationType: "ByPolygon"')
-
- file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"')
- file.write('\n\t\t\tBlendMode: "Translucent"')
- file.write('\n\t\t\tTextureAlpha: 1')
- file.write('\n\t\t\tTextureId: ')
-
- if len(my_mesh.blenTextures) == 1:
- file.write('0')
- else:
- texture_mapping_local = {None:-1}
-
- i = 0 # 1 for dummy
- for tex in my_mesh.blenTextures:
- if tex: # None is set above
- texture_mapping_local[tex] = i
- i+=1
-
- i=-1
- for f in uvlayer.data:
- img_key = f.image
-
- if i==-1:
- i=0
- file.write( '%s' % texture_mapping_local[img_key])
- else:
- if i==55:
- file.write('\n ')
- i=0
-
- file.write(',%s' % texture_mapping_local[img_key])
- i+=1
-
- else:
- file.write('''
- LayerElementTexture: 0 {
- Version: 101
- Name: ""
- MappingInformationType: "NoMappingInformation"
- ReferenceInformationType: "IndexToDirect"
- BlendMode: "Translucent"
- TextureAlpha: 1
- TextureId: ''')
- file.write('\n\t\t}')
-
-
- # Done with UV/textures.
-
- if do_materials:
- file.write('\n\t\tLayerElementMaterial: 0 {')
- file.write('\n\t\t\tVersion: 101')
- file.write('\n\t\t\tName: ""')
-
- if len(my_mesh.blenMaterials) == 1:
- file.write('\n\t\t\tMappingInformationType: "AllSame"')
- else:
- file.write('\n\t\t\tMappingInformationType: "ByPolygon"')
-
- file.write('\n\t\t\tReferenceInformationType: "IndexToDirect"')
- file.write('\n\t\t\tMaterials: ')
-
- if len(my_mesh.blenMaterials) == 1:
- file.write('0')
- else:
- # Build a material mapping for this
- material_mapping_local = {} # local-mat & tex : global index.
-
- for j, mat_tex_pair in enumerate(my_mesh.blenMaterials):
- material_mapping_local[mat_tex_pair] = j
-
- len_material_mapping_local = len(material_mapping_local)
-
- mats = my_mesh.blenMaterialList
-
- if me.uv_textures.active:
- uv_faces = me.uv_textures.active.data
- else:
- uv_faces = [None] * len(me.faces)
-
- i=-1
- for f, uf in zip(me.faces, uv_faces):
-# for f in me.faces:
- try: mat = mats[f.material_index]
- except:mat = None
-
- if do_uvs: tex = uf.image # WARNING - MULTI UV LAYER IMAGES NOT SUPPORTED :/
- else: tex = None
-
- if i==-1:
- i=0
- file.write( '%s' % (material_mapping_local[mat, tex])) # None for mat or tex is ok
- else:
- if i==55:
- file.write('\n\t\t\t\t')
- i=0
-
- file.write(',%s' % (material_mapping_local[mat, tex]))
- i+=1
-
- file.write('\n\t\t}')
-
- file.write('''
- Layer: 0 {
- Version: 100
- LayerElement: {
- Type: "LayerElementNormal"
- TypedIndex: 0
- }''')
-
- if do_materials:
- file.write('''
- LayerElement: {
- Type: "LayerElementMaterial"
- TypedIndex: 0
- }''')
-
- # Always write this
- if do_textures:
- file.write('''
- LayerElement: {
- Type: "LayerElementTexture"
- TypedIndex: 0
- }''')
-
- if me.vertex_colors:
- file.write('''
- LayerElement: {
- Type: "LayerElementColor"
- TypedIndex: 0
- }''')
-
- if do_uvs: # same as me.faceUV
- file.write('''
- LayerElement: {
- Type: "LayerElementUV"
- TypedIndex: 0
- }''')
-
-
- file.write('\n\t\t}')
-
- if len(uvlayers) > 1:
- for i in range(1, len(uvlayers)):
-
- file.write('\n\t\tLayer: %i {' % i)
- file.write('\n\t\t\tVersion: 100')
-
- file.write('''
- LayerElement: {
- Type: "LayerElementUV"''')
-
- file.write('\n\t\t\t\tTypedIndex: %i' % i)
- file.write('\n\t\t\t}')
-
- if do_textures:
-
- file.write('''
- LayerElement: {
- Type: "LayerElementTexture"''')
-
- file.write('\n\t\t\t\tTypedIndex: %i' % i)
- file.write('\n\t\t\t}')
-
- file.write('\n\t\t}')
-
- if len(collayers) > 1:
- # Take into account any UV layers
- layer_offset = 0
- if uvlayers: layer_offset = len(uvlayers)-1
-
- for i in range(layer_offset, len(collayers)+layer_offset):
- file.write('\n\t\tLayer: %i {' % i)
- file.write('\n\t\t\tVersion: 100')
-
- file.write('''
- LayerElement: {
- Type: "LayerElementColor"''')
-
- file.write('\n\t\t\t\tTypedIndex: %i' % i)
- file.write('\n\t\t\t}')
- file.write('\n\t\t}')
- file.write('\n\t}')
-
- def write_group(name):
- file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {' % name)
-
- file.write('''
- Properties60: {
- Property: "MultiLayer", "bool", "",0
- Property: "Pickable", "bool", "",1
- Property: "Transformable", "bool", "",1
- Property: "Show", "bool", "",1
- }
- MultiLayer: 0
- }''')
-
-
- # add meshes here to clear because they are not used anywhere.
- meshes_to_clear = []
-
- ob_meshes = []
- ob_lights = []
- ob_cameras = []
- # in fbx we export bones as children of the mesh
- # armatures not a part of a mesh, will be added to ob_arms
- ob_bones = []
- ob_arms = []
- ob_null = [] # emptys
-
- # List of types that have blender objects (not bones)
- ob_all_typegroups = [ob_meshes, ob_lights, ob_cameras, ob_arms, ob_null]
-
- groups = [] # blender groups, only add ones that have objects in the selections
- materials = {} # (mat, image) keys, should be a set()
- textures = {} # should be a set()
-
- tmp_ob_type = ob_type = None # incase no objects are exported, so as not to raise an error
-
- # if EXP_OBS_SELECTED is false, use sceens objects
- if not batch_objects:
- if EXP_OBS_SELECTED: tmp_objects = context.selected_objects
- else: tmp_objects = scene.objects
- else:
- tmp_objects = batch_objects
-
- if EXP_ARMATURE:
- # This is needed so applying modifiers dosnt apply the armature deformation, its also needed
- # ...so mesh objects return their rest worldspace matrix when bone-parents are exported as weighted meshes.
- # set every armature to its rest, backup the original values so we done mess up the scene
- ob_arms_orig_rest = [arm.pose_position for arm in bpy.data.armatures]
-
- for arm in bpy.data.armatures:
- arm.pose_position = 'REST'
-
- if ob_arms_orig_rest:
- for ob_base in bpy.data.objects:
- if ob_base.type == 'ARMATURE':
- ob_base.update(scene)
-
- # This causes the makeDisplayList command to effect the mesh
- scene.frame_set(scene.frame_current)
-
-
- for ob_base in tmp_objects:
-
- # ignore dupli children
- if ob_base.parent and ob_base.parent.dupli_type != 'NONE':
- continue
-
- obs = [(ob_base, ob_base.matrix_world)]
- if ob_base.dupli_type != 'NONE':
- ob_base.create_dupli_list(scene)
- obs = [(dob.object, dob.matrix) for dob in ob_base.dupli_list]
-
- for ob, mtx in obs:
-# for ob, mtx in BPyObject.getDerivedObjects(ob_base):
- tmp_ob_type = ob.type
- if tmp_ob_type == 'CAMERA':
- if EXP_CAMERA:
- ob_cameras.append(my_object_generic(ob, mtx))
- elif tmp_ob_type == 'LAMP':
- if EXP_LAMP:
- ob_lights.append(my_object_generic(ob, mtx))
- elif tmp_ob_type == 'ARMATURE':
- if EXP_ARMATURE:
- # TODO - armatures dont work in dupligroups!
- if ob not in ob_arms: ob_arms.append(ob)
- # ob_arms.append(ob) # replace later. was "ob_arms.append(sane_obname(ob), ob)"
- elif tmp_ob_type == 'EMPTY':
- if EXP_EMPTY:
- ob_null.append(my_object_generic(ob, mtx))
- elif EXP_MESH:
- origData = True
- if tmp_ob_type != 'MESH':
-# me = bpy.data.meshes.new()
- try: me = ob.create_mesh(scene, True, 'PREVIEW')
-# try: me.getFromObject(ob)
- except: me = None
- if me:
- meshes_to_clear.append( me )
- mats = me.materials
- origData = False
- else:
- # Mesh Type!
- if EXP_MESH_APPLY_MOD:
-# me = bpy.data.meshes.new()
- me = ob.create_mesh(scene, True, 'PREVIEW')
-# me.getFromObject(ob)
-
- # print ob, me, me.getVertGroupNames()
- meshes_to_clear.append( me )
- origData = False
- mats = me.materials
- else:
- me = ob.data
-# me = ob.getData(mesh=1)
- mats = me.materials
-
-# # Support object colors
-# tmp_colbits = ob.colbits
-# if tmp_colbits:
-# tmp_ob_mats = ob.getMaterials(1) # 1 so we get None's too.
-# for i in xrange(16):
-# if tmp_colbits & (1<<i):
-# mats[i] = tmp_ob_mats[i]
-# del tmp_ob_mats
-# del tmp_colbits
-
-
- if me:
-# # This WILL modify meshes in blender if EXP_MESH_APPLY_MOD is disabled.
-# # so strictly this is bad. but only in rare cases would it have negative results
-# # say with dupliverts the objects would rotate a bit differently
-# if EXP_MESH_HQ_NORMALS:
-# BPyMesh.meshCalcNormals(me) # high quality normals nice for realtime engines.
-
- texture_mapping_local = {}
- material_mapping_local = {}
- if me.uv_textures:
- for uvlayer in me.uv_textures:
- for f, uf in zip(me.faces, uvlayer.data):
- tex = uf.image
- textures[tex] = texture_mapping_local[tex] = None
-
- try: mat = mats[f.material_index]
- except: mat = None
-
- materials[mat, tex] = material_mapping_local[mat, tex] = None # should use sets, wait for blender 2.5
-
- else:
- for mat in mats:
- # 2.44 use mat.lib too for uniqueness
- materials[mat, None] = material_mapping_local[mat, None] = None
- else:
- materials[None, None] = None
-
- if EXP_ARMATURE:
- armob = ob.find_armature()
- blenParentBoneName = None
-
- # parent bone - special case
- if (not armob) and ob.parent and ob.parent.type == 'ARMATURE' and \
- ob.parent_type == 'BONE':
- armob = ob.parent
- blenParentBoneName = ob.parent_bone
-
-
- if armob and armob not in ob_arms:
- ob_arms.append(armob)
-
- else:
- blenParentBoneName = armob = None
-
- my_mesh = my_object_generic(ob, mtx)
- my_mesh.blenData = me
- my_mesh.origData = origData
- my_mesh.blenMaterials = list(material_mapping_local.keys())
- my_mesh.blenMaterialList = mats
- my_mesh.blenTextures = list(texture_mapping_local.keys())
-
- # if only 1 null texture then empty the list
- if len(my_mesh.blenTextures) == 1 and my_mesh.blenTextures[0] is None:
- my_mesh.blenTextures = []
-
- my_mesh.fbxArm = armob # replace with my_object_generic armature instance later
- my_mesh.fbxBoneParent = blenParentBoneName # replace with my_bone instance later
-
- ob_meshes.append( my_mesh )
-
- # not forgetting to free dupli_list
- if ob_base.dupli_list: ob_base.free_dupli_list()
-
-
- if EXP_ARMATURE:
- # now we have the meshes, restore the rest arm position
- for i, arm in enumerate(bpy.data.armatures):
- arm.pose_position = ob_arms_orig_rest[i]
-
- if ob_arms_orig_rest:
- for ob_base in bpy.data.objects:
- if ob_base.type == 'ARMATURE':
- ob_base.update(scene)
- # This causes the makeDisplayList command to effect the mesh
- scene.frame_set(scene.frame_current)
-
- del tmp_ob_type, tmp_objects
-
- # now we have collected all armatures, add bones
- for i, ob in enumerate(ob_arms):
-
- ob_arms[i] = my_arm = my_object_generic(ob)
-
- my_arm.fbxBones = []
- my_arm.blenData = ob.data
- if ob.animation_data:
- my_arm.blenAction = ob.animation_data.action
- else:
- my_arm.blenAction = None
-# my_arm.blenAction = ob.action
- my_arm.blenActionList = []
-
- # fbxName, blenderObject, my_bones, blenderActions
- #ob_arms[i] = fbxArmObName, ob, arm_my_bones, (ob.action, [])
-
- for bone in my_arm.blenData.bones:
- my_bone = my_bone_class(bone, my_arm)
- my_arm.fbxBones.append( my_bone )
- ob_bones.append( my_bone )
-
- # add the meshes to the bones and replace the meshes armature with own armature class
- #for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
- for my_mesh in ob_meshes:
- # Replace
- # ...this could be sped up with dictionary mapping but its unlikely for
- # it ever to be a bottleneck - (would need 100+ meshes using armatures)
- if my_mesh.fbxArm:
- for my_arm in ob_arms:
- if my_arm.blenObject == my_mesh.fbxArm:
- my_mesh.fbxArm = my_arm
- break
-
- for my_bone in ob_bones:
-
- # The mesh uses this bones armature!
- if my_bone.fbxArm == my_mesh.fbxArm:
- my_bone.blenMeshes[my_mesh.fbxName] = me
-
-
- # parent bone: replace bone names with our class instances
- # my_mesh.fbxBoneParent is None or a blender bone name initialy, replacing if the names match.
- if my_mesh.fbxBoneParent == my_bone.blenName:
- my_mesh.fbxBoneParent = my_bone
-
- bone_deformer_count = 0 # count how many bones deform a mesh
- my_bone_blenParent = None
- for my_bone in ob_bones:
- my_bone_blenParent = my_bone.blenBone.parent
- if my_bone_blenParent:
- for my_bone_parent in ob_bones:
- # Note 2.45rc2 you can compare bones normally
- if my_bone_blenParent.name == my_bone_parent.blenName and my_bone.fbxArm == my_bone_parent.fbxArm:
- my_bone.parent = my_bone_parent
- break
-
- # Not used at the moment
- # my_bone.calcRestMatrixLocal()
- bone_deformer_count += len(my_bone.blenMeshes)
-
- del my_bone_blenParent
-
-
- # Build blenObject -> fbxObject mapping
- # this is needed for groups as well as fbxParenting
- for ob in bpy.data.objects: ob.tag = False
-
- # using a list of object names for tagging (Arystan)
-
- tmp_obmapping = {}
- for ob_generic in ob_all_typegroups:
- for ob_base in ob_generic:
- ob_base.blenObject.tag = True
- tmp_obmapping[ob_base.blenObject] = ob_base
-
- # Build Groups from objects we export
- for blenGroup in bpy.data.groups:
- fbxGroupName = None
- for ob in blenGroup.objects:
- if ob.tag:
- if fbxGroupName is None:
- fbxGroupName = sane_groupname(blenGroup)
- groups.append((fbxGroupName, blenGroup))
-
- tmp_obmapping[ob].fbxGroupNames.append(fbxGroupName) # also adds to the objects fbxGroupNames
-
- groups.sort() # not really needed
-
- # Assign parents using this mapping
- for ob_generic in ob_all_typegroups:
- for my_ob in ob_generic:
- parent = my_ob.blenObject.parent
- if parent and parent.tag: # does it exist and is it in the mapping
- my_ob.fbxParent = tmp_obmapping[parent]
-
-
- del tmp_obmapping
- # Finished finding groups we use
-
-
- materials = [(sane_matname(mat_tex_pair), mat_tex_pair) for mat_tex_pair in materials.keys()]
- textures = [(sane_texname(tex), tex) for tex in textures.keys() if tex]
- materials.sort() # sort by name
- textures.sort()
-
- camera_count = 8
- file.write('''
-
-; Object definitions
-;------------------------------------------------------------------
-
-Definitions: {
- Version: 100
- Count: %i''' % (\
- 1+1+camera_count+\
- len(ob_meshes)+\
- len(ob_lights)+\
- len(ob_cameras)+\
- len(ob_arms)+\
- len(ob_null)+\
- len(ob_bones)+\
- bone_deformer_count+\
- len(materials)+\
- (len(textures)*2))) # add 1 for the root model 1 for global settings
-
- del bone_deformer_count
-
- file.write('''
- ObjectType: "Model" {
- Count: %i
- }''' % (\
- 1+camera_count+\
- len(ob_meshes)+\
- len(ob_lights)+\
- len(ob_cameras)+\
- len(ob_arms)+\
- len(ob_null)+\
- len(ob_bones))) # add 1 for the root model
-
- file.write('''
- ObjectType: "Geometry" {
- Count: %i
- }''' % len(ob_meshes))
-
- if materials:
- file.write('''
- ObjectType: "Material" {
- Count: %i
- }''' % len(materials))
-
- if textures:
- file.write('''
- ObjectType: "Texture" {
- Count: %i
- }''' % len(textures)) # add 1 for an empty tex
- file.write('''
- ObjectType: "Video" {
- Count: %i
- }''' % len(textures)) # add 1 for an empty tex
-
- tmp = 0
- # Add deformer nodes
- for my_mesh in ob_meshes:
- if my_mesh.fbxArm:
- tmp+=1
-
- # Add subdeformers
- for my_bone in ob_bones:
- tmp += len(my_bone.blenMeshes)
-
- if tmp:
- file.write('''
- ObjectType: "Deformer" {
- Count: %i
- }''' % tmp)
- del tmp
-
- # we could avoid writing this possibly but for now just write it
-
- file.write('''
- ObjectType: "Pose" {
- Count: 1
- }''')
-
- if groups:
- file.write('''
- ObjectType: "GroupSelection" {
- Count: %i
- }''' % len(groups))
-
- file.write('''
- ObjectType: "GlobalSettings" {
- Count: 1
- }
-}''')
-
- file.write('''
-
-; Object properties
-;------------------------------------------------------------------
-
-Objects: {''')
-
- # To comply with other FBX FILES
- write_camera_switch()
-
- # Write the null object
- write_null(None, 'blend_root')# , GLOBAL_MATRIX)
-
- for my_null in ob_null:
- write_null(my_null)
-
- for my_arm in ob_arms:
- write_null(my_arm)
-
- for my_cam in ob_cameras:
- write_camera(my_cam)
-
- for my_light in ob_lights:
- write_light(my_light)
-
- for my_mesh in ob_meshes:
- write_mesh(my_mesh)
-
- #for bonename, bone, obname, me, armob in ob_bones:
- for my_bone in ob_bones:
- write_bone(my_bone)
-
- write_camera_default()
-
- for matname, (mat, tex) in materials:
- write_material(matname, mat) # We only need to have a material per image pair, but no need to write any image info into the material (dumb fbx standard)
-
- # each texture uses a video, odd
- for texname, tex in textures:
- write_video(texname, tex)
- i = 0
- for texname, tex in textures:
- write_texture(texname, tex, i)
- i+=1
-
- for groupname, group in groups:
- write_group(groupname)
-
- # NOTE - c4d and motionbuilder dont need normalized weights, but deep-exploration 5 does and (max?) do.
-
- # Write armature modifiers
- # TODO - add another MODEL? - because of this skin definition.
- for my_mesh in ob_meshes:
- if my_mesh.fbxArm:
- write_deformer_skin(my_mesh.fbxName)
-
- # Get normalized weights for temorary use
- if my_mesh.fbxBoneParent:
- weights = None
- else:
- weights = meshNormalizedWeights(my_mesh.blenObject, my_mesh.blenData)
-
- #for bonename, bone, obname, bone_mesh, armob in ob_bones:
- for my_bone in ob_bones:
- if me in iter(my_bone.blenMeshes.values()):
- write_sub_deformer_skin(my_mesh, my_bone, weights)
-
- # Write pose's really weired, only needed when an armature and mesh are used together
- # each by themselves dont need pose data. for now only pose meshes and bones
-
- file.write('''
- Pose: "Pose::BIND_POSES", "BindPose" {
- Type: "BindPose"
- Version: 100
- Properties60: {
- }
- NbPoseNodes: ''')
- file.write(str(len(pose_items)))
-
-
- for fbxName, matrix in pose_items:
- file.write('\n\t\tPoseNode: {')
- file.write('\n\t\t\tNode: "Model::%s"' % fbxName )
- file.write('\n\t\t\tMatrix: %s' % mat4x4str(matrix if matrix else Matrix()))
- file.write('\n\t\t}')
-
- file.write('\n\t}')
-
-
- # Finish Writing Objects
- # Write global settings
- file.write('''
- GlobalSettings: {
- Version: 1000
- Properties60: {
- Property: "UpAxis", "int", "",1
- Property: "UpAxisSign", "int", "",1
- Property: "FrontAxis", "int", "",2
- Property: "FrontAxisSign", "int", "",1
- Property: "CoordAxis", "int", "",0
- Property: "CoordAxisSign", "int", "",1
- Property: "UnitScaleFactor", "double", "",100
- }
- }
-''')
- file.write('}')
-
- file.write('''
-
-; Object relations
-;------------------------------------------------------------------
-
-Relations: {''')
-
- file.write('\n\tModel: "Model::blend_root", "Null" {\n\t}')
-
- for my_null in ob_null:
- file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_null.fbxName)
-
- for my_arm in ob_arms:
- file.write('\n\tModel: "Model::%s", "Null" {\n\t}' % my_arm.fbxName)
-
- for my_mesh in ob_meshes:
- file.write('\n\tModel: "Model::%s", "Mesh" {\n\t}' % my_mesh.fbxName)
-
- # TODO - limbs can have the same name for multiple armatures, should prefix.
- #for bonename, bone, obname, me, armob in ob_bones:
- for my_bone in ob_bones:
- file.write('\n\tModel: "Model::%s", "Limb" {\n\t}' % my_bone.fbxName)
-
- for my_cam in ob_cameras:
- file.write('\n\tModel: "Model::%s", "Camera" {\n\t}' % my_cam.fbxName)
-
- for my_light in ob_lights:
- file.write('\n\tModel: "Model::%s", "Light" {\n\t}' % my_light.fbxName)
-
- file.write('''
- Model: "Model::Producer Perspective", "Camera" {
- }
- Model: "Model::Producer Top", "Camera" {
- }
- Model: "Model::Producer Bottom", "Camera" {
- }
- Model: "Model::Producer Front", "Camera" {
- }
- Model: "Model::Producer Back", "Camera" {
- }
- Model: "Model::Producer Right", "Camera" {
- }
- Model: "Model::Producer Left", "Camera" {
- }
- Model: "Model::Camera Switcher", "CameraSwitcher" {
- }''')
-
- for matname, (mat, tex) in materials:
- file.write('\n\tMaterial: "Material::%s", "" {\n\t}' % matname)
-
- if textures:
- for texname, tex in textures:
- file.write('\n\tTexture: "Texture::%s", "TextureVideoClip" {\n\t}' % texname)
- for texname, tex in textures:
- file.write('\n\tVideo: "Video::%s", "Clip" {\n\t}' % texname)
-
- # deformers - modifiers
- for my_mesh in ob_meshes:
- if my_mesh.fbxArm:
- file.write('\n\tDeformer: "Deformer::Skin %s", "Skin" {\n\t}' % my_mesh.fbxName)
-
- #for bonename, bone, obname, me, armob in ob_bones:
- for my_bone in ob_bones:
- for fbxMeshObName in my_bone.blenMeshes: # .keys() - fbxMeshObName
- # is this bone effecting a mesh?
- file.write('\n\tDeformer: "SubDeformer::Cluster %s %s", "Cluster" {\n\t}' % (fbxMeshObName, my_bone.fbxName))
-
- # This should be at the end
- # file.write('\n\tPose: "Pose::BIND_POSES", "BindPose" {\n\t}')
-
- for groupname, group in groups:
- file.write('\n\tGroupSelection: "GroupSelection::%s", "Default" {\n\t}' % groupname)
-
- file.write('\n}')
- file.write('''
-
-; Object connections
-;------------------------------------------------------------------
-
-Connections: {''')
-
- # NOTE - The FBX SDK dosnt care about the order but some importers DO!
- # for instance, defining the material->mesh connection
- # before the mesh->blend_root crashes cinema4d
-
-
- # write the fake root node
- file.write('\n\tConnect: "OO", "Model::blend_root", "Model::Scene"')
-
- for ob_generic in ob_all_typegroups: # all blender 'Object's we support
- for my_ob in ob_generic:
- if my_ob.fbxParent:
- file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_ob.fbxName, my_ob.fbxParent.fbxName))
- else:
- file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_ob.fbxName)
-
- if materials:
- for my_mesh in ob_meshes:
- # Connect all materials to all objects, not good form but ok for now.
- for mat, tex in my_mesh.blenMaterials:
- if mat: mat_name = mat.name
- else: mat_name = None
-
- if tex: tex_name = tex.name
- else: tex_name = None
-
- file.write('\n\tConnect: "OO", "Material::%s", "Model::%s"' % (sane_name_mapping_mat[mat_name, tex_name], my_mesh.fbxName))
-
- if textures:
- for my_mesh in ob_meshes:
- if my_mesh.blenTextures:
- # file.write('\n\tConnect: "OO", "Texture::_empty_", "Model::%s"' % my_mesh.fbxName)
- for tex in my_mesh.blenTextures:
- if tex:
- file.write('\n\tConnect: "OO", "Texture::%s", "Model::%s"' % (sane_name_mapping_tex[tex.name], my_mesh.fbxName))
-
- for texname, tex in textures:
- file.write('\n\tConnect: "OO", "Video::%s", "Texture::%s"' % (texname, texname))
-
- for my_mesh in ob_meshes:
- if my_mesh.fbxArm:
- file.write('\n\tConnect: "OO", "Deformer::Skin %s", "Model::%s"' % (my_mesh.fbxName, my_mesh.fbxName))
-
- #for bonename, bone, obname, me, armob in ob_bones:
- for my_bone in ob_bones:
- for fbxMeshObName in my_bone.blenMeshes: # .keys()
- file.write('\n\tConnect: "OO", "SubDeformer::Cluster %s %s", "Deformer::Skin %s"' % (fbxMeshObName, my_bone.fbxName, fbxMeshObName))
-
- # limbs -> deformers
- # for bonename, bone, obname, me, armob in ob_bones:
- for my_bone in ob_bones:
- for fbxMeshObName in my_bone.blenMeshes: # .keys()
- file.write('\n\tConnect: "OO", "Model::%s", "SubDeformer::Cluster %s %s"' % (my_bone.fbxName, fbxMeshObName, my_bone.fbxName))
-
-
- #for bonename, bone, obname, me, armob in ob_bones:
- for my_bone in ob_bones:
- # Always parent to armature now
- if my_bone.parent:
- file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.parent.fbxName) )
- else:
- # the armature object is written as an empty and all root level bones connect to it
- file.write('\n\tConnect: "OO", "Model::%s", "Model::%s"' % (my_bone.fbxName, my_bone.fbxArm.fbxName) )
-
- # groups
- if groups:
- for ob_generic in ob_all_typegroups:
- for ob_base in ob_generic:
- for fbxGroupName in ob_base.fbxGroupNames:
- file.write('\n\tConnect: "OO", "Model::%s", "GroupSelection::%s"' % (ob_base.fbxName, fbxGroupName))
-
- for my_arm in ob_arms:
- file.write('\n\tConnect: "OO", "Model::%s", "Model::blend_root"' % my_arm.fbxName)
-
- file.write('\n}')
-
-
- # Needed for scene footer as well as animation
- render = scene.render
-
- # from the FBX sdk
- #define KTIME_ONE_SECOND KTime (K_LONGLONG(46186158000))
- def fbx_time(t):
- # 0.5 + val is the same as rounding.
- return int(0.5 + ((t/fps) * 46186158000))
-
- fps = float(render.fps)
- start = scene.frame_start
- end = scene.frame_end
- if end < start: start, end = end, st
-
- # comment the following line, otherwise we dont get the pose
- # if start==end: ANIM_ENABLE = False
-
- # animations for these object types
- ob_anim_lists = ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms
-
- if ANIM_ENABLE and [tmp for tmp in ob_anim_lists if tmp]:
-
- frame_orig = scene.frame_current
-
- if ANIM_OPTIMIZE:
- ANIM_OPTIMIZE_PRECISSION_FLOAT = 0.1 ** ANIM_OPTIMIZE_PRECISSION
-
- # default action, when no actions are avaioable
- tmp_actions = []
- blenActionDefault = None
- action_lastcompat = None
-
- # instead of tagging
- tagged_actions = []
-
- if ANIM_ACTION_ALL:
-# bpy.data.actions.tag = False
- tmp_actions = bpy.data.actions[:]
-
-
- # find which actions are compatible with the armatures
- # blenActions is not yet initialized so do it now.
- tmp_act_count = 0
- for my_arm in ob_arms:
-
- # get the default name
- if not blenActionDefault:
- blenActionDefault = my_arm.blenAction
-
- arm_bone_names = set([my_bone.blenName for my_bone in my_arm.fbxBones])
-
- for action in tmp_actions:
-
- action_chan_names = arm_bone_names.intersection( set([g.name for g in action.groups]) )
-# action_chan_names = arm_bone_names.intersection( set(action.getChannelNames()) )
-
- if action_chan_names: # at least one channel matches.
- my_arm.blenActionList.append(action)
- tagged_actions.append(action.name)
-# action.tag = True
- tmp_act_count += 1
-
- # incase there is no actions applied to armatures
- action_lastcompat = action
-
- if tmp_act_count:
- # unlikely to ever happen but if no actions applied to armatures, just use the last compatible armature.
- if not blenActionDefault:
- blenActionDefault = action_lastcompat
-
- del action_lastcompat
-
- tmp_actions.insert(0, None) # None is the default action
-
- file.write('''
-;Takes and animation section
-;----------------------------------------------------
-
-Takes: {''')
-
- if blenActionDefault:
- file.write('\n\tCurrent: "%s"' % sane_takename(blenActionDefault))
- else:
- file.write('\n\tCurrent: "Default Take"')
-
- for blenAction in tmp_actions:
- # we have tagged all actious that are used be selected armatures
- if blenAction:
- if blenAction.name in tagged_actions:
-# if blenAction.tag:
- print('\taction: "%s" exporting...' % blenAction.name)
- else:
- print('\taction: "%s" has no armature using it, skipping' % blenAction.name)
- continue
-
- if blenAction is None:
- # Warning, this only accounts for tmp_actions being [None]
- file.write('\n\tTake: "Default Take" {')
- act_start = start
- act_end = end
- else:
- # use existing name
- if blenAction == blenActionDefault: # have we already got the name
- file.write('\n\tTake: "%s" {' % sane_name_mapping_take[blenAction.name])
- else:
- file.write('\n\tTake: "%s" {' % sane_takename(blenAction))
-
- act_start, act_end = blenAction.frame_range
- act_start = int(act_start)
- act_end = int(act_end)
-
- # Set the action active
- for my_bone in ob_arms:
- if ob.animation_data and blenAction in my_bone.blenActionList:
- ob.animation_data.action = blenAction
- # print '\t\tSetting Action!', blenAction
- # scene.update(1)
-
- file.write('\n\t\tFileName: "Default_Take.tak"') # ??? - not sure why this is needed
- file.write('\n\t\tLocalTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed
- file.write('\n\t\tReferenceTime: %i,%i' % (fbx_time(act_start-1), fbx_time(act_end-1))) # ??? - not sure why this is needed
-
- file.write('''
-
- ;Models animation
- ;----------------------------------------------------''')
-
-
- # set pose data for all bones
- # do this here incase the action changes
- '''
- for my_bone in ob_bones:
- my_bone.flushAnimData()
- '''
- i = act_start
- while i <= act_end:
- scene.frame_set(i)
- for ob_generic in ob_anim_lists:
- for my_ob in ob_generic:
- #Blender.Window.RedrawAll()
- if ob_generic == ob_meshes and my_ob.fbxArm:
- # We cant animate armature meshes!
- pass
- else:
- my_ob.setPoseFrame(i)
-
- i+=1
-
-
- #for bonename, bone, obname, me, armob in ob_bones:
- for ob_generic in (ob_bones, ob_meshes, ob_null, ob_cameras, ob_lights, ob_arms):
-
- for my_ob in ob_generic:
-
- if ob_generic == ob_meshes and my_ob.fbxArm:
- # do nothing,
- pass
- else:
-
- file.write('\n\t\tModel: "Model::%s" {' % my_ob.fbxName) # ??? - not sure why this is needed
- file.write('\n\t\t\tVersion: 1.1')
- file.write('\n\t\t\tChannel: "Transform" {')
-
- context_bone_anim_mats = [ (my_ob.getAnimParRelMatrix(frame), my_ob.getAnimParRelMatrixRot(frame)) for frame in range(act_start, act_end+1) ]
-
- # ----------------
- # ----------------
- for TX_LAYER, TX_CHAN in enumerate('TRS'): # transform, rotate, scale
-
- if TX_CHAN=='T': context_bone_anim_vecs = [mtx[0].translation_part() for mtx in context_bone_anim_mats]
- elif TX_CHAN=='S': context_bone_anim_vecs = [mtx[0].scale_part() for mtx in context_bone_anim_mats]
- elif TX_CHAN=='R':
- # Was....
- # elif TX_CHAN=='R': context_bone_anim_vecs = [mtx[1].to_euler() for mtx in context_bone_anim_mats]
- #
- # ...but we need to use the previous euler for compatible conversion.
- context_bone_anim_vecs = []
- prev_eul = None
- for mtx in context_bone_anim_mats:
- if prev_eul: prev_eul = mtx[1].to_euler('XYZ', prev_eul)
- else: prev_eul = mtx[1].to_euler()
- context_bone_anim_vecs.append(eulerRadToDeg(prev_eul))
-
- file.write('\n\t\t\t\tChannel: "%s" {' % TX_CHAN) # translation
-
- for i in range(3):
- # Loop on each axis of the bone
- file.write('\n\t\t\t\t\tChannel: "%s" {'% ('XYZ'[i])) # translation
- file.write('\n\t\t\t\t\t\tDefault: %.15f' % context_bone_anim_vecs[0][i] )
- file.write('\n\t\t\t\t\t\tKeyVer: 4005')
-
- if not ANIM_OPTIMIZE:
- # Just write all frames, simple but in-eficient
- file.write('\n\t\t\t\t\t\tKeyCount: %i' % (1 + act_end - act_start))
- file.write('\n\t\t\t\t\t\tKey: ')
- frame = act_start
- while frame <= act_end:
- if frame!=act_start:
- file.write(',')
-
- # Curve types are 'C,n' for constant, 'L' for linear
- # C,n is for bezier? - linear is best for now so we can do simple keyframe removal
- file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame-1), context_bone_anim_vecs[frame-act_start][i] ))
- frame+=1
- else:
- # remove unneeded keys, j is the frame, needed when some frames are removed.
- context_bone_anim_keys = [ (vec[i], j) for j, vec in enumerate(context_bone_anim_vecs) ]
-
- # last frame to fisrt frame, missing 1 frame on either side.
- # removeing in a backwards loop is faster
- #for j in xrange( (act_end-act_start)-1, 0, -1 ):
- # j = (act_end-act_start)-1
- j = len(context_bone_anim_keys)-2
- while j > 0 and len(context_bone_anim_keys) > 2:
- # print j, len(context_bone_anim_keys)
- # Is this key the same as the ones next to it?
-
- # co-linear horizontal...
- if abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j-1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT and\
- abs(context_bone_anim_keys[j][0] - context_bone_anim_keys[j+1][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT:
-
- del context_bone_anim_keys[j]
-
- else:
- frame_range = float(context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j-1][1])
- frame_range_fac1 = (context_bone_anim_keys[j+1][1] - context_bone_anim_keys[j][1]) / frame_range
- frame_range_fac2 = 1.0 - frame_range_fac1
-
- if abs(((context_bone_anim_keys[j-1][0]*frame_range_fac1 + context_bone_anim_keys[j+1][0]*frame_range_fac2)) - context_bone_anim_keys[j][0]) < ANIM_OPTIMIZE_PRECISSION_FLOAT:
- del context_bone_anim_keys[j]
- else:
- j-=1
-
- # keep the index below the list length
- if j > len(context_bone_anim_keys)-2:
- j = len(context_bone_anim_keys)-2
-
- if len(context_bone_anim_keys) == 2 and context_bone_anim_keys[0][0] == context_bone_anim_keys[1][0]:
-
- # This axis has no moton, its okay to skip KeyCount and Keys in this case
- # pass
-
- # better write one, otherwise we loose poses with no animation
- file.write('\n\t\t\t\t\t\tKeyCount: 1')
- file.write('\n\t\t\t\t\t\tKey: ')
- file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(start), context_bone_anim_keys[0][0]))
- else:
- # We only need to write these if there is at least one
- file.write('\n\t\t\t\t\t\tKeyCount: %i' % len(context_bone_anim_keys))
- file.write('\n\t\t\t\t\t\tKey: ')
- for val, frame in context_bone_anim_keys:
- if frame != context_bone_anim_keys[0][1]: # not the first
- file.write(',')
- # frame is already one less then blenders frame
- file.write('\n\t\t\t\t\t\t\t%i,%.15f,L' % (fbx_time(frame), val ))
-
- if i==0: file.write('\n\t\t\t\t\t\tColor: 1,0,0')
- elif i==1: file.write('\n\t\t\t\t\t\tColor: 0,1,0')
- elif i==2: file.write('\n\t\t\t\t\t\tColor: 0,0,1')
-
- file.write('\n\t\t\t\t\t}')
- file.write('\n\t\t\t\t\tLayerType: %i' % (TX_LAYER+1) )
- file.write('\n\t\t\t\t}')
-
- # ---------------
-
- file.write('\n\t\t\t}')
- file.write('\n\t\t}')
-
- # end the take
- file.write('\n\t}')
-
- # end action loop. set original actions
- # do this after every loop incase actions effect eachother.
- for my_bone in ob_arms:
- if my_bone.blenObject.animation_data:
- my_bone.blenObject.animation_data.action = my_bone.blenAction
-
- file.write('\n}')
-
- scene.frame_set(frame_orig)
-
- else:
- # no animation
- file.write('\n;Takes and animation section')
- file.write('\n;----------------------------------------------------')
- file.write('\n')
- file.write('\nTakes: {')
- file.write('\n\tCurrent: ""')
- file.write('\n}')
-
-
- # write meshes animation
- #for obname, ob, mtx, me, mats, arm, armname in ob_meshes:
-
-
- # Clear mesh data Only when writing with modifiers applied
- for me in meshes_to_clear:
- bpy.data.meshes.remove(me)
-
- # --------------------------- Footer
- if world:
- m = world.mist_settings
- has_mist = m.use_mist
- mist_intense = m.intensity
- mist_start = m.start
- mist_end = m.depth
- mist_height = m.height
- world_hor = world.horizon_color
- else:
- has_mist = mist_intense = mist_start = mist_end = mist_height = 0
- world_hor = 0, 0, 0
-
- file.write('\n;Version 5 settings')
- file.write('\n;------------------------------------------------------------------')
- file.write('\n')
- file.write('\nVersion5: {')
- file.write('\n\tAmbientRenderSettings: {')
- file.write('\n\t\tVersion: 101')
- file.write('\n\t\tAmbientLightColor: %.1f,%.1f,%.1f,0' % tuple(world_amb))
- file.write('\n\t}')
- file.write('\n\tFogOptions: {')
- file.write('\n\t\tFlogEnable: %i' % has_mist)
- file.write('\n\t\tFogMode: 0')
- file.write('\n\t\tFogDensity: %.3f' % mist_intense)
- file.write('\n\t\tFogStart: %.3f' % mist_start)
- file.write('\n\t\tFogEnd: %.3f' % mist_end)
- file.write('\n\t\tFogColor: %.1f,%.1f,%.1f,1' % tuple(world_hor))
- file.write('\n\t}')
- file.write('\n\tSettings: {')
- file.write('\n\t\tFrameRate: "%i"' % int(fps))
- file.write('\n\t\tTimeFormat: 1')
- file.write('\n\t\tSnapOnFrames: 0')
- file.write('\n\t\tReferenceTimeIndex: -1')
- file.write('\n\t\tTimeLineStartTime: %i' % fbx_time(start-1))
- file.write('\n\t\tTimeLineStopTime: %i' % fbx_time(end-1))
- file.write('\n\t}')
- file.write('\n\tRendererSetting: {')
- file.write('\n\t\tDefaultCamera: "Producer Perspective"')
- file.write('\n\t\tDefaultViewingMode: 0')
- file.write('\n\t}')
- file.write('\n}')
- file.write('\n')
-
- # Incase sombody imports this, clean up by clearing global dicts
- sane_name_mapping_ob.clear()
- sane_name_mapping_mat.clear()
- sane_name_mapping_tex.clear()
-
- ob_arms[:] = []
- ob_bones[:] = []
- ob_cameras[:] = []
- ob_lights[:] = []
- ob_meshes[:] = []
- ob_null[:] = []
-
-
- # copy images if enabled
-# if EXP_IMAGE_COPY:
-# # copy_images( basepath, [ tex[1] for tex in textures if tex[1] != None ])
-# bpy.util.copy_images( [ tex[1] for tex in textures if tex[1] != None ], basepath)
-
- print('export finished in %.4f sec.' % (time.clock() - start_time))
- return {'FINISHED'}
-
-
-# NOTES (all line numbers correspond to original export_fbx.py (under release/scripts)
-# - Draw.PupMenu alternative in 2.5?, temporarily replaced PupMenu with print
-# - get rid of bpy.path.clean_name somehow
-# + fixed: isinstance(inst, bpy.types.*) doesn't work on RNA objects: line 565
-# + get rid of BPyObject_getObjectArmature, move it in RNA?
-# - BATCH_ENABLE and BATCH_GROUP options: line 327
-# - implement all BPyMesh_* used here with RNA
-# - getDerivedObjects is not fully replicated with .dupli* funcs
-# - talk to Campbell, this code won't work? lines 1867-1875
-# - don't know what those colbits are, do we need them? they're said to be deprecated in DNA_object_types.h: 1886-1893
-# - no hq normals: 1900-1901
-
-# TODO
-
-# - bpy.data.remove_scene: line 366
-# - bpy.sys.time move to bpy.sys.util?
-# - new scene creation, activation: lines 327-342, 368
-# - uses bpy.path.abspath, *.relpath - replace at least relpath
diff --git a/release/scripts/op/io_scene_obj/__init__.py b/release/scripts/op/io_scene_obj/__init__.py
deleted file mode 100644
index 4d7da65a7b0..00000000000
--- a/release/scripts/op/io_scene_obj/__init__.py
+++ /dev/null
@@ -1,144 +0,0 @@
-# ##### 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>
-
-# To support reload properly, try to access a package var, if it's there, reload everything
-if "bpy" in locals():
- # only reload if we alredy loaded, highly annoying
- import sys
- reload(sys.modules.get("io_scene_obj.import_obj", sys))
- reload(sys.modules.get("io_scene_obj.export_obj", sys))
-
-
-import bpy
-from bpy.props import *
-from io_utils import ExportHelper, ImportHelper
-
-
-class ImportOBJ(bpy.types.Operator, ImportHelper):
- '''Load a Wavefront OBJ File'''
- bl_idname = "import_scene.obj"
- bl_label = "Import OBJ"
-
- filename_ext = ".obj"
- filter_glob = StringProperty(default="*.obj;*.mtl", options={'HIDDEN'})
-
- 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)
- # 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)
- ROTATE_X90 = BoolProperty(name="-X90", description="Rotate X 90.", default= True)
- CLAMP_SIZE = FloatProperty(name="Clamp Scale", description="Clamp the size to this maximum (Zero to Disable)", min=0.0, max=1000.0, soft_min=0.0, soft_max=1000.0, default=0.0)
- POLYGROUPS = BoolProperty(name="Poly Groups", description="Import OBJ groups as vertex groups.", default= True)
- IMAGE_SEARCH = BoolProperty(name="Image Search", description="Search subdirs for any assosiated images (Warning, may be slow)", default= True)
-
-
- def execute(self, context):
- # print("Selected: " + context.active_object.name)
- import io_scene_obj.import_obj
- return io_scene_obj.import_obj.load(self, context, **self.properties)
- '''
- load_obj(self.filepath,
- context,
- self.CLAMP_SIZE,
- self.CREATE_FGONS,
- self.CREATE_SMOOTH_GROUPS,
- self.CREATE_EDGES,
- self.SPLIT_OBJECTS,
- self.SPLIT_GROUPS,
- self.ROTATE_X90,
- self.IMAGE_SEARCH,
- self.POLYGROUPS)
- '''
-
- return {'FINISHED'}
-
-
-class ExportOBJ(bpy.types.Operator, ExportHelper):
- '''Save a Wavefront OBJ File'''
-
- bl_idname = "export_scene.obj"
- bl_label = 'Export OBJ'
-
- filename_ext = ".obj"
-
- # List of operator properties, the attributes will be assigned
- # to the class instance from the operator settings before calling.
-
- # context group
- use_selection = BoolProperty(name="Selection Only", description="Export selected objects only", default= False)
- use_all_scenes = BoolProperty(name="All Scenes", description="", default= False)
- use_animation = BoolProperty(name="Animation", description="", default= False)
-
- # object group
- use_modifiers = BoolProperty(name="Apply Modifiers", description="Apply modifiers (preview resolution)", default= True)
- use_rotate_x90 = BoolProperty(name="Rotate X90", description="", default= True)
-
- # extra data group
- use_edges = BoolProperty(name="Edges", description="", default=True)
- use_normals = BoolProperty(name="Normals", description="", default=False)
- use_hq_normals = BoolProperty(name="High Quality Normals", description="", default=True)
- use_uvs = BoolProperty(name="UVs", description="", default= True)
- use_materials = BoolProperty(name="Materials", description="", default=True)
- copy_images = BoolProperty(name="Copy Images", description="", default=False)
- use_triangles = BoolProperty(name="Triangulate", description="", default=False)
- use_vertex_groups = BoolProperty(name="Polygroups", description="", default=False)
- use_nurbs = BoolProperty(name="Nurbs", description="", default=False)
-
- # grouping group
- use_blen_objects = BoolProperty(name="Objects as OBJ Objects", description="", default= True)
- group_by_object = BoolProperty(name="Objects as OBJ Groups ", description="", default= False)
- group_by_material = BoolProperty(name="Material Groups", description="", default= False)
- keep_vertex_order = BoolProperty(name="Keep Vertex Order", description="", default= False)
-
-
- def execute(self, context):
- import io_scene_obj.export_obj
- return io_scene_obj.export_obj.save(self, context, **self.properties)
-
-
-def menu_func_import(self, context):
- self.layout.operator(ImportOBJ.bl_idname, text="Wavefront (.obj)")
-
-
-def menu_func_export(self, context):
- self.layout.operator(ExportOBJ.bl_idname, text="Wavefront (.obj)")
-
-
-def register():
- bpy.types.INFO_MT_file_import.append(menu_func_import)
- bpy.types.INFO_MT_file_export.append(menu_func_export)
-
-def unregister():
- bpy.types.INFO_MT_file_import.remove(menu_func_import)
- bpy.types.INFO_MT_file_export.remove(menu_func_export)
-
-
-# CONVERSION ISSUES
-# - matrix problem
-# - duplis - only tested dupliverts
-# - all scenes export
-# + normals calculation
-
-if __name__ == "__main__":
- register()
diff --git a/release/scripts/op/io_scene_obj/export_obj.py b/release/scripts/op/io_scene_obj/export_obj.py
deleted file mode 100644
index 23d9ab2aa06..00000000000
--- a/release/scripts/op/io_scene_obj/export_obj.py
+++ /dev/null
@@ -1,842 +0,0 @@
-# ##### 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 os
-import time
-import shutil
-
-import bpy
-import mathutils
-
-def fixName(name):
- if name is None:
- return 'None'
- else:
- return name.replace(' ', '_')
-
-def write_mtl(scene, filepath, copy_images, mtl_dict):
-
- world = scene.world
- worldAmb = world.ambient_color
-
- dest_dir = os.path.dirname(filepath)
-
- def copy_image(image):
- fn = bpy.path.abspath(image.filepath)
- fn_strip = os.path.basename(fn)
- if copy_images:
- rel = fn_strip
- fn_abs_dest = os.path.join(dest_dir, fn_strip)
- if not os.path.exists(fn_abs_dest):
- shutil.copy(fn, fn_abs_dest)
- else:
- rel = fn
-
- return rel
-
-
- file = open(filepath, "w")
- # XXX
-# 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():
-
- # Get the Blender data for the material and the image.
- # Having an image named None will make a bug, dont do it :)
-
- file.write('newmtl %s\n' % mtl_mat_name) # Define a new material: matname_imgname
-
- if mat:
- file.write('Ns %.6f\n' % ((mat.specular_hardness-1) * 1.9607843137254901) ) # Hardness, convert blenders 1-511 to MTL's
- file.write('Ka %.6f %.6f %.6f\n' % tuple([c*mat.ambient for c in worldAmb]) ) # Ambient, uses mirror colour,
- file.write('Kd %.6f %.6f %.6f\n' % tuple([c*mat.diffuse_intensity for c in mat.diffuse_color]) ) # Diffuse
- file.write('Ks %.6f %.6f %.6f\n' % tuple([c*mat.specular_intensity for c in mat.specular_color]) ) # Specular
- if hasattr(mat, "ior"):
- file.write('Ni %.6f\n' % mat.ior) # Refraction index
- else:
- file.write('Ni %.6f\n' % 1.0)
- file.write('d %.6f\n' % mat.alpha) # Alpha (obj uses 'd' for dissolve)
-
- # 0 to disable lighting, 1 for ambient & diffuse only (specular color set to black), 2 for full lighting.
- if mat.use_shadeless:
- file.write('illum 0\n') # ignore lighting
- elif mat.specular_intensity == 0:
- file.write('illum 1\n') # no specular.
- else:
- file.write('illum 2\n') # light normaly
-
- else:
- #write a dummy material here?
- file.write('Ns 0\n')
- file.write('Ka %.6f %.6f %.6f\n' % tuple([c for c in worldAmb]) ) # Ambient, uses mirror colour,
- file.write('Kd 0.8 0.8 0.8\n')
- file.write('Ks 0.8 0.8 0.8\n')
- file.write('d 1\n') # No alpha
- file.write('illum 2\n') # light normaly
-
- # Write images!
- if img: # We have an image on the face!
- # 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.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:
- filepath = copy_image(mtex.texture.image)
-# filepath = mtex.texture.image.filepath.split('\\')[-1].split('/')[-1]
- file.write('map_Kd %s\n' % repr(filepath)[1:-1]) # Diffuse mapping image
- break
- except:
- # Texture has no image though its an image type, best ignore.
- pass
-
- file.write('\n\n')
-
- file.close()
-
-# XXX not used
-def copy_file(source, dest):
- file = open(source, 'rb')
- data = file.read()
- file.close()
-
- file = open(dest, 'wb')
- file.write(data)
- file.close()
-
-
-# XXX not used
-def copy_images(dest_dir):
- if dest_dir[-1] != os.sep:
- dest_dir += os.sep
-# if dest_dir[-1] != sys.sep:
-# dest_dir += sys.sep
-
- # Get unique image names
- uniqueImages = {}
- 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.
-
- # Get MTex images
- if mat:
- for mtex in mat.texture_slots:
- if mtex and mtex.texture.type == 'IMAGE':
- image_tex = mtex.texture.image
- if image_tex:
- try:
- uniqueImages[image_tex] = image_tex
- except:
- pass
-
- # Now copy images
- copyCount = 0
-
-# for bImage in uniqueImages.values():
-# image_path = bpy.path.abspath(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]
-# if not bpy.utils.exists(dest_image_path): # Image isnt already there
-# print('\tCopying "%s" > "%s"' % (image_path, dest_image_path))
-# copy_file(image_path, dest_image_path)
-# copyCount+=1
-
-# paths= bpy.util.copy_images(uniqueImages.values(), dest_dir)
-
- print('\tCopied %d images' % copyCount)
-
-
-def test_nurbs_compat(ob):
- if ob.type != 'CURVE':
- return False
-
- for nu in ob.data.splines:
- if nu.point_count_v == 1 and nu.type != 'BEZIER': # not a surface and not bezier
- return True
-
- return False
-
-
-def write_nurb(file, ob, ob_mat):
- tot_verts = 0
- cu = ob.data
-
- # use negative indices
- for nu in cu.splines:
- if nu.type == 'POLY':
- DEG_ORDER_U = 1
- else:
- DEG_ORDER_U = nu.order_u - 1 # odd but tested to be correct
-
- if nu.type == 'BEZIER':
- print("\tWarning, bezier curve:", ob.name, "only poly and nurbs curves supported")
- continue
-
- if nu.point_count_v > 1:
- print("\tWarning, surface:", ob.name, "only poly and nurbs curves supported")
- continue
-
- if len(nu.points) <= DEG_ORDER_U:
- print("\tWarning, order_u is lower then vert count, skipping:", ob.name)
- continue
-
- pt_num = 0
- do_closed = nu.use_cyclic_u
- do_endpoints = (do_closed == 0) and nu.use_endpoint_u
-
- for pt in nu.points:
- pt = ob_mat * pt.co.copy().resize3D()
- file.write('v %.6f %.6f %.6f\n' % (pt[0], pt[1], pt[2]))
- pt_num += 1
- tot_verts += pt_num
-
- file.write('g %s\n' % (fixName(ob.name))) # fixName(ob.getData(1)) could use the data name too
- file.write('cstype bspline\n') # not ideal, hard coded
- file.write('deg %d\n' % DEG_ORDER_U) # not used for curves but most files have it still
-
- curve_ls = [-(i+1) for i in range(pt_num)]
-
- # 'curv' keyword
- if do_closed:
- if DEG_ORDER_U == 1:
- pt_num += 1
- curve_ls.append(-1)
- else:
- pt_num += DEG_ORDER_U
- curve_ls = curve_ls + curve_ls[0:DEG_ORDER_U]
-
- file.write('curv 0.0 1.0 %s\n' % (' '.join([str(i) for i in curve_ls]))) # Blender has no U and V values for the curve
-
- # 'parm' keyword
- tot_parm = (DEG_ORDER_U + 1) + pt_num
- tot_parm_div = float(tot_parm-1)
- parm_ls = [(i/tot_parm_div) for i in range(tot_parm)]
-
- if do_endpoints: # end points, force param
- for i in range(DEG_ORDER_U+1):
- parm_ls[i] = 0.0
- parm_ls[-(1+i)] = 1.0
-
- file.write('parm u %s\n' % ' '.join( [str(i) for i in parm_ls] ))
-
- file.write('end\n')
-
- return tot_verts
-
-def write_file(filepath, objects, scene,
- EXPORT_TRI=False,
- EXPORT_EDGES=False,
- EXPORT_NORMALS=False,
- EXPORT_NORMALS_HQ=False,
- EXPORT_UV=True,
- EXPORT_MTL=True,
- EXPORT_COPY_IMAGES=False,
- EXPORT_APPLY_MODIFIERS=True,
- EXPORT_ROTX90=True,
- EXPORT_BLEN_OBS=True,
- EXPORT_GROUP_BY_OB=False,
- EXPORT_GROUP_BY_MAT=False,
- EXPORT_KEEP_VERT_ORDER=False,
- EXPORT_POLYGROUPS=False,
- EXPORT_CURVE_AS_NURBS=True):
- '''
- Basic write function. The context and options must be already set
- This can be accessed externaly
- eg.
- write( 'c:\\test\\foobar.obj', Blender.Object.GetSelected() ) # Using default options.
- '''
-
- # XXX
- import math
-
- def veckey3d(v):
- return round(v.x, 6), round(v.y, 6), round(v.z, 6)
-
- def veckey2d(v):
- return round(v[0], 6), round(v[1], 6)
- # return round(v.x, 6), round(v.y, 6)
-
- def findVertexGroupName(face, vWeightMap):
- """
- Searches the vertexDict to see what groups is assigned to a given face.
- We use a frequency system in order to sort out the name because a given vetex can
- belong to two or more groups at the same time. To find the right name for the face
- we list all the possible vertex group names with their frequency and then sort by
- frequency in descend order. The top element is the one shared by the highest number
- of vertices is the face's group
- """
- weightDict = {}
- for vert_index in face.vertices:
-# for vert in face:
- vWeights = vWeightMap[vert_index]
-# vWeights = vWeightMap[vert]
- for vGroupName, weight in vWeights:
- weightDict[vGroupName] = weightDict.get(vGroupName, 0) + weight
-
- if weightDict:
- alist = [(weight,vGroupName) for vGroupName, weight in weightDict.items()] # sort least to greatest amount of weight
- alist.sort()
- return(alist[-1][1]) # highest value last
- else:
- return '(null)'
-
- print('OBJ Export path: %r' % filepath)
- temp_mesh_name = '~tmp-mesh'
-
- time1 = time.clock()
-# time1 = sys.time()
-# scn = Scene.GetCurrent()
-
- file = open(filepath, "w")
-
- # Write Header
- file.write('# Blender v%s OBJ File: %r\n' % (bpy.app.version_string, os.path.basename(bpy.data.filepath)))
- file.write('# www.blender.org\n')
-
- # Tell the obj file what material file to use.
- if EXPORT_MTL:
- mtlfilepath = os.path.splitext(filepath)[0] + ".mtl"
- file.write('mtllib %s\n' % repr(os.path.basename(mtlfilepath))[1:-1]) # filepath can contain non utf8 chars, use repr
-
- if EXPORT_ROTX90:
- mat_xrot90= mathutils.Matrix.Rotation(-math.pi/2, 4, 'X')
-
- # Initialize totals, these are updated each object
- totverts = totuvco = totno = 1
-
- face_vert_index = 1
-
- 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:
-
- # ignore dupli children
- if ob_main.parent and ob_main.parent.dupli_type != 'NONE':
- # XXX
- print(ob_main.name, 'is a dupli child - ignoring')
- continue
-
- obs = []
- if ob_main.dupli_type != 'NONE':
- # XXX
- print('creating dupli_list on', ob_main.name)
- 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_world)]
-
- for ob, ob_mat in obs:
-
- # Nurbs curve support
- if EXPORT_CURVE_AS_NURBS and test_nurbs_compat(ob):
- if EXPORT_ROTX90:
- ob_mat = ob_mat * mat_xrot90
- totverts += write_nurb(file, ob, ob_mat)
- continue
- # END NURBS
-
- if ob.type != 'MESH':
- continue
-
- me = ob.create_mesh(scene, EXPORT_APPLY_MODIFIERS, 'PREVIEW')
-
- if EXPORT_ROTX90:
- me.transform(mat_xrot90 * ob_mat)
- else:
- me.transform(ob_mat)
-
-# # Will work for non meshes now! :)
-# me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, EXPORT_POLYGROUPS, scn)
-# if not me:
-# continue
-
- if EXPORT_UV:
- faceuv = len(me.uv_textures) > 0
- if faceuv:
- uv_layer = me.uv_textures.active.data[:]
- else:
- faceuv = False
-
- me_verts = me.vertices[:]
-
- # Make our own list so it can be sorted to reduce context switching
- face_index_pairs = [ (face, index) for index, face in enumerate(me.faces)]
- # faces = [ f for f in me.faces ]
-
- if EXPORT_EDGES:
- edges = me.edges
- else:
- edges = []
-
- if not (len(face_index_pairs)+len(edges)+len(me.vertices)): # Make sure there is somthing to write
-
- # clean up
- bpy.data.meshes.remove(me)
-
- continue # dont bother with this mesh.
-
- # XXX
- # High Quality Normals
- if EXPORT_NORMALS and face_index_pairs:
- me.calc_normals()
-# if EXPORT_NORMALS_HQ:
-# BPyMesh.meshCalcNormals(me)
-# else:
-# # transforming normals is incorrect
-# # when the matrix is scaled,
-# # better to recalculate them
-# me.calcNormals()
-
- materials = me.materials
-
- materialNames = []
- materialItems = [m for m in materials]
- if materials:
- for mat in materials:
- if mat:
- materialNames.append(mat.name)
- else:
- materialNames.append(None)
- # Cant use LC because some materials are None.
- # materialNames = map(lambda mat: mat.name, materials) # Bug Blender, dosent account for null materials, still broken.
-
- # Possible there null materials, will mess up indicies
- # but at least it will export, wait until Blender gets fixed.
- materialNames.extend((16-len(materialNames)) * [None])
- materialItems.extend((16-len(materialItems)) * [None])
-
- # Sort by Material, then images
- # so we dont over context switch in the obj file.
- if EXPORT_KEEP_VERT_ORDER:
- pass
- elif faceuv:
- face_index_pairs.sort(key=lambda a: (a[0].material_index, hash(uv_layer[a[1]].image), a[0].use_smooth))
- elif len(materials) > 1:
- face_index_pairs.sort(key = lambda a: (a[0].material_index, a[0].use_smooth))
- else:
- # no materials
- face_index_pairs.sort(key = lambda a: a[0].use_smooth)
-# if EXPORT_KEEP_VERT_ORDER:
-# pass
-# elif faceuv:
-# try: faces.sort(key = lambda a: (a.mat, a.image, a.use_smooth))
-# except: faces.sort(lambda a,b: cmp((a.mat, a.image, a.use_smooth), (b.mat, b.image, b.use_smooth)))
-# elif len(materials) > 1:
-# try: faces.sort(key = lambda a: (a.mat, a.use_smooth))
-# except: faces.sort(lambda a,b: cmp((a.mat, a.use_smooth), (b.mat, b.use_smooth)))
-# else:
-# # no materials
-# try: faces.sort(key = lambda a: a.use_smooth)
-# except: faces.sort(lambda a,b: cmp(a.use_smooth, b.use_smooth))
-
- # Set the default mat to no material and no image.
- contextMat = (0, 0) # Can never be this, so we will label a new material teh first chance we get.
- contextSmooth = None # Will either be true or false, set bad to force initialization switch.
-
- if EXPORT_BLEN_OBS or EXPORT_GROUP_BY_OB:
- name1 = ob.name
- name2 = ob.data.name
- if name1 == name2:
- obnamestring = fixName(name1)
- else:
- obnamestring = '%s_%s' % (fixName(name1), fixName(name2))
-
- if EXPORT_BLEN_OBS:
- file.write('o %s\n' % obnamestring) # Write Object name
- else: # if EXPORT_GROUP_BY_OB:
- file.write('g %s\n' % obnamestring)
-
-
- # Vert
- for v in me_verts:
- file.write('v %.6f %.6f %.6f\n' % tuple(v.co))
-
- # UV
- if faceuv:
- uv_face_mapping = [[0,0,0,0] for i in range(len(face_index_pairs))] # a bit of a waste for tri's :/
-
- uv_dict = {} # could use a set() here
- uv_layer = me.uv_textures.active.data
- for f, f_index in face_index_pairs:
- for uv_index, uv in enumerate(uv_layer[f_index].uv):
- uvkey = veckey2d(uv)
- try:
- uv_face_mapping[f_index][uv_index] = uv_dict[uvkey]
- except:
- uv_face_mapping[f_index][uv_index] = uv_dict[uvkey] = len(uv_dict)
- file.write('vt %.6f %.6f\n' % tuple(uv))
-
- uv_unique_count = len(uv_dict)
-# del uv, uvkey, uv_dict, f_index, uv_index
- # Only need uv_unique_count and uv_face_mapping
-
- # NORMAL, Smooth/Non smoothed.
- if EXPORT_NORMALS:
- for f, f_index in face_index_pairs:
- if f.use_smooth:
- for v_idx in f.vertices:
- v = me_verts[v_idx]
- noKey = veckey3d(v.normal)
- if noKey not in globalNormals:
- globalNormals[noKey] = totno
- totno +=1
- file.write('vn %.6f %.6f %.6f\n' % noKey)
- else:
- # Hard, 1 normal from the face.
- noKey = veckey3d(f.normal)
- if noKey not in globalNormals:
- globalNormals[noKey] = totno
- totno +=1
- file.write('vn %.6f %.6f %.6f\n' % noKey)
-
- if not faceuv:
- f_image = None
-
- # XXX
- if EXPORT_POLYGROUPS:
- # Retrieve the list of vertex groups
- vertGroupNames = [g.name for g in ob.vertex_groups]
-
- currentVGroup = ''
- # Create a dictionary keyed by face id and listing, for each vertex, the vertex groups it belongs to
- vgroupsMap = [[] for _i in range(len(me_verts))]
- for v_idx, v in enumerate(me.vertices):
- for g in v.groups:
- vgroupsMap[v_idx].append((vertGroupNames[g.group], g.weight))
-
- for f, f_index in face_index_pairs:
- f_smooth= f.use_smooth
- f_mat = min(f.material_index, len(materialNames)-1)
-# f_mat = min(f.mat, len(materialNames)-1)
- if faceuv:
-
- tface = uv_layer[f_index]
-
- f_image = tface.image
- f_uv = tface.uv
- # f_uv= [tface.uv1, tface.uv2, tface.uv3]
- # if len(f.vertices) == 4:
- # f_uv.append(tface.uv4)
-# f_image = f.image
-# f_uv= f.uv
-
- # MAKE KEY
- if faceuv and f_image: # Object is always true.
- key = materialNames[f_mat], f_image.name
- else:
- key = materialNames[f_mat], None # No image, use None instead.
-
- # Write the vertex group
- if EXPORT_POLYGROUPS:
- if ob.vertex_groups:
- # find what vertext group the face belongs to
- theVGroup = findVertexGroupName(f,vgroupsMap)
- if theVGroup != currentVGroup:
- currentVGroup = theVGroup
- file.write('g %s\n' % theVGroup)
-
- # CHECK FOR CONTEXT SWITCH
- if key == contextMat:
- pass # Context already switched, dont do anything
- else:
- if key[0] is None and key[1] is None:
- # Write a null material, since we know the context has changed.
- if EXPORT_GROUP_BY_MAT:
- # can be mat_image or (null)
- file.write('g %s_%s\n' % (fixName(ob.name), fixName(ob.data.name)) ) # can be mat_image or (null)
- file.write('usemtl (null)\n') # mat, image
-
- else:
- mat_data= mtl_dict.get(key)
- if not mat_data:
- # First add to global dict so we can export to mtl
- # Then write mtl
-
- # Make a new names from the mat and image name,
- # converting any spaces to underscores with fixName.
-
- # If none image dont bother adding it to the name
- if key[1] is None:
- 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
-
- 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)
-
- file.write('usemtl %s\n' % mat_data[0]) # can be mat_image or (null)
-
- contextMat = key
- if f_smooth != contextSmooth:
- if f_smooth: # on now off
- file.write('s 1\n')
- contextSmooth = f_smooth
- else: # was off now on
- file.write('s off\n')
- contextSmooth = f_smooth
-
- f_v_orig = [me_verts[v_idx] for v_idx in f.vertices]
-
- if not EXPORT_TRI or len(f_v_orig) == 3:
- f_v_iter = (f_v_orig, )
- else:
- f_v_iter = (f_v_orig[0], f_v_orig[1], f_v_orig[2]), (f_v_orig[0], f_v_orig[2], f_v_orig[3])
-
- # support for triangulation
- for f_v in f_v_iter:
- file.write('f')
-
- if faceuv:
- if EXPORT_NORMALS:
- if f_smooth: # Smoothed, use vertex normals
- for vi, v in enumerate(f_v):
- file.write( ' %d/%d/%d' % \
- (v.index + totverts,
- totuvco + uv_face_mapping[f_index][vi],
- globalNormals[ veckey3d(v.normal) ]) ) # vert, uv, normal
-
- else: # No smoothing, face normals
- no = globalNormals[ veckey3d(f.normal) ]
- for vi, v in enumerate(f_v):
- file.write( ' %d/%d/%d' % \
- (v.index + totverts,
- totuvco + uv_face_mapping[f_index][vi],
- no) ) # vert, uv, normal
- else: # No Normals
- for vi, v in enumerate(f_v):
- file.write( ' %d/%d' % (\
- v.index + totverts,\
- totuvco + uv_face_mapping[f_index][vi])) # vert, uv
-
- face_vert_index += len(f_v)
-
- else: # No UV's
- if EXPORT_NORMALS:
- if f_smooth: # Smoothed, use vertex normals
- for v in f_v:
- file.write( ' %d//%d' %
- (v.index + totverts, globalNormals[ veckey3d(v.normal) ]) )
- else: # No smoothing, face normals
- no = globalNormals[ veckey3d(f.normal) ]
- for v in f_v:
- file.write( ' %d//%d' % (v.index + totverts, no) )
- else: # No Normals
- for v in f_v:
- file.write( ' %d' % (v.index + totverts) )
-
- file.write('\n')
-
- # Write edges.
- if EXPORT_EDGES:
- for ed in edges:
- if ed.is_loose:
- file.write('f %d %d\n' % (ed.vertices[0] + totverts, ed.vertices[1] + totverts))
-
- # Make the indicies global rather then per mesh
- totverts += len(me_verts)
- if faceuv:
- totuvco += uv_unique_count
-
- # clean up
- bpy.data.meshes.remove(me)
-
- if ob_main.dupli_type != 'NONE':
- ob_main.free_dupli_list()
-
- file.close()
-
-
- # Now we have all our materials, save them
- if EXPORT_MTL:
- write_mtl(scene, mtlfilepath, EXPORT_COPY_IMAGES, mtl_dict)
-# if EXPORT_COPY_IMAGES:
-# 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, mtl_dict)
-# else:
-# print('\tError: "%s" could not be used as a base for an image path.' % filepath)
-
- print("OBJ Export time: %.2f" % (time.clock() - time1))
-
-#
-def _write(context, filepath,
- EXPORT_TRI, # ok
- EXPORT_EDGES,
- EXPORT_NORMALS, # not yet
- EXPORT_NORMALS_HQ, # not yet
- EXPORT_UV, # ok
- EXPORT_MTL,
- EXPORT_COPY_IMAGES,
- EXPORT_APPLY_MODIFIERS, # ok
- EXPORT_ROTX90, # wrong
- EXPORT_BLEN_OBS,
- EXPORT_GROUP_BY_OB,
- EXPORT_GROUP_BY_MAT,
- EXPORT_KEEP_VERT_ORDER,
- EXPORT_POLYGROUPS,
- EXPORT_CURVE_AS_NURBS,
- EXPORT_SEL_ONLY, # ok
- EXPORT_ALL_SCENES, # XXX not working atm
- EXPORT_ANIMATION): # Not used
-
- base_name, ext = os.path.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.
- if bpy.ops.object.mode_set.poll():
- bpy.ops.object.mode_set(mode='OBJECT')
-
-# if EXPORT_ALL_SCENES:
-# export_scenes = bpy.data.scenes
-# else:
-# export_scenes = [orig_scene]
-
- # XXX only exporting one scene atm since changing
- # current scene is not possible.
- # Brecht says that ideally in 2.5 we won't need such a function,
- # allowing multiple scenes open at once.
- export_scenes = [orig_scene]
-
- # Export all scenes.
- for scene in export_scenes:
- # scene.makeCurrent() # If already current, this is not slow.
- # context = scene.getRenderingContext()
- orig_frame = scene.frame_current
-
- if EXPORT_ALL_SCENES: # Add scene name into the context_name
- context_name[1] = '_%s' % bpy.path.clean_name(scene.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(scene.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 filepath.
- context_name[2] = '_%.6d' % frame
-
- scene.frame_current = frame
- if EXPORT_SEL_ONLY:
- objects = context.selected_objects
- else:
- objects = scene.objects
-
- full_path= ''.join(context_name)
-
- # erm... bit of a problem here, this can overwrite files when exporting frames. not too bad.
- # EXPORT THE FILE.
- write_file(full_path, objects, scene,
- EXPORT_TRI,
- EXPORT_EDGES,
- EXPORT_NORMALS,
- EXPORT_NORMALS_HQ,
- EXPORT_UV,
- EXPORT_MTL,
- EXPORT_COPY_IMAGES,
- EXPORT_APPLY_MODIFIERS,
- EXPORT_ROTX90,
- EXPORT_BLEN_OBS,
- EXPORT_GROUP_BY_OB,
- EXPORT_GROUP_BY_MAT,
- EXPORT_KEEP_VERT_ORDER,
- EXPORT_POLYGROUPS,
- EXPORT_CURVE_AS_NURBS)
-
-
- scene.frame_current = orig_frame
-
- # Restore old active scene.
-# orig_scene.makeCurrent()
-# Window.WaitCursor(0)
-
-
-'''
-Currently the exporter lacks these features:
-* multiple scene export (only active scene is written)
-* particles
-'''
-
-
-def save(operator, context, filepath="",
- use_triangles=False,
- use_edges=False,
- use_normals=False,
- use_hq_normals=False,
- use_uvs=True,
- use_materials=True,
- copy_images=False,
- use_modifiers=True,
- use_rotate_x90=True,
- use_blen_objects=True,
- group_by_object=False,
- group_by_material=False,
- keep_vertex_order=False,
- use_vertex_groups=False,
- use_nurbs=True,
- use_selection=True,
- use_all_scenes=False,
- use_animation=False,
- ):
-
- _write(context, filepath,
- EXPORT_TRI=use_triangles,
- EXPORT_EDGES=use_edges,
- EXPORT_NORMALS=use_normals,
- EXPORT_NORMALS_HQ=use_hq_normals,
- EXPORT_UV=use_uvs,
- EXPORT_MTL=use_materials,
- EXPORT_COPY_IMAGES=copy_images,
- EXPORT_APPLY_MODIFIERS=use_modifiers,
- EXPORT_ROTX90=use_rotate_x90,
- EXPORT_BLEN_OBS=use_blen_objects,
- EXPORT_GROUP_BY_OB=group_by_object,
- EXPORT_GROUP_BY_MAT=group_by_material,
- EXPORT_KEEP_VERT_ORDER=keep_vertex_order,
- EXPORT_POLYGROUPS=use_vertex_groups,
- EXPORT_CURVE_AS_NURBS=use_nurbs,
- EXPORT_SEL_ONLY=use_selection,
- EXPORT_ALL_SCENES=use_all_scenes,
- EXPORT_ANIMATION=use_animation,
- )
-
- return {'FINISHED'}
diff --git a/release/scripts/op/io_scene_obj/import_obj.py b/release/scripts/op/io_scene_obj/import_obj.py
deleted file mode 100644
index f6c5e625fb0..00000000000
--- a/release/scripts/op/io_scene_obj/import_obj.py
+++ /dev/null
@@ -1,1219 +0,0 @@
-# ##### 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>
-
-# Script copyright (C) Campbell Barton
-# Contributors: Campbell Barton, Jiri Hnidek, Paolo Ciccone
-
-"""
-This script imports a Wavefront OBJ files to Blender.
-
-Usage:
-Run this script from "File->Import" menu and then load the desired OBJ file.
-Note, This loads mesh objects and materials only, nurbs and curves are not supported.
-
-http://wiki.blender.org/index.php/Scripts/Manual/Import/wavefront_obj
-"""
-
-import os
-import time
-import bpy
-import mathutils
-from geometry import PolyFill
-from io_utils import load_image, unpack_list, unpack_face_list
-
-
-def BPyMesh_ngon(from_data, indices, PREF_FIX_LOOPS= True):
- '''
- Takes a polyline of indices (fgon)
- and returns a list of face indicie lists.
- Designed to be used for importers that need indices for an fgon to create from existing verts.
-
- from_data: either a mesh, or a list/tuple of vectors.
- indices: a list of indicies to use this list is the ordered closed polyline to fill, and can be a subset of the data given.
- PREF_FIX_LOOPS: If this is enabled polylines that use loops to make multiple polylines are delt with correctly.
- '''
-
- if not set: # Need sets for this, otherwise do a normal fill.
- PREF_FIX_LOOPS= False
-
- Vector= mathutils.Vector
- if not indices:
- return []
-
- # return []
- def rvec(co): return round(co.x, 6), round(co.y, 6), round(co.z, 6)
- def mlen(co): return abs(co[0])+abs(co[1])+abs(co[2]) # manhatten length of a vector, faster then length
-
- def vert_treplet(v, i):
- return v, rvec(v), i, mlen(v)
-
- def ed_key_mlen(v1, v2):
- if v1[3] > v2[3]:
- return v2[1], v1[1]
- else:
- return v1[1], v2[1]
-
-
- if not PREF_FIX_LOOPS:
- '''
- Normal single concave loop filling
- '''
- if type(from_data) in (tuple, list):
- verts= [Vector(from_data[i]) for ii, i in enumerate(indices)]
- else:
- verts= [from_data.vertices[i].co for ii, i in enumerate(indices)]
-
- for i in range(len(verts)-1, 0, -1): # same as reversed(xrange(1, len(verts))):
- if verts[i][1]==verts[i-1][0]:
- verts.pop(i-1)
-
- fill= PolyFill([verts])
-
- else:
- '''
- Seperate this loop into multiple loops be finding edges that are used twice
- This is used by lightwave LWO files a lot
- '''
-
- if type(from_data) in (tuple, list):
- verts= [vert_treplet(Vector(from_data[i]), ii) for ii, i in enumerate(indices)]
- else:
- verts= [vert_treplet(from_data.vertices[i].co, ii) for ii, i in enumerate(indices)]
-
- edges= [(i, i-1) for i in range(len(verts))]
- if edges:
- edges[0]= (0,len(verts)-1)
-
- if not verts:
- return []
-
-
- edges_used= set()
- edges_doubles= set()
- # We need to check if any edges are used twice location based.
- for ed in edges:
- edkey= ed_key_mlen(verts[ed[0]], verts[ed[1]])
- if edkey in edges_used:
- edges_doubles.add(edkey)
- else:
- edges_used.add(edkey)
-
- # Store a list of unconnected loop segments split by double edges.
- # will join later
- loop_segments= []
-
- v_prev= verts[0]
- context_loop= [v_prev]
- loop_segments= [context_loop]
-
- for v in verts:
- if v!=v_prev:
- # Are we crossing an edge we removed?
- if ed_key_mlen(v, v_prev) in edges_doubles:
- context_loop= [v]
- loop_segments.append(context_loop)
- else:
- if context_loop and context_loop[-1][1]==v[1]:
- #raise "as"
- pass
- else:
- context_loop.append(v)
-
- v_prev= v
- # Now join loop segments
-
- def join_seg(s1,s2):
- if s2[-1][1]==s1[0][1]: #
- s1,s2= s2,s1
- elif s1[-1][1]==s2[0][1]:
- pass
- else:
- return False
-
- # If were stuill here s1 and s2 are 2 segments in the same polyline
- s1.pop() # remove the last vert from s1
- s1.extend(s2) # add segment 2 to segment 1
-
- if s1[0][1]==s1[-1][1]: # remove endpoints double
- s1.pop()
-
- s2[:]= [] # Empty this segment s2 so we dont use it again.
- return True
-
- joining_segments= True
- while joining_segments:
- joining_segments= False
- segcount= len(loop_segments)
-
- for j in range(segcount-1, -1, -1): #reversed(range(segcount)):
- seg_j= loop_segments[j]
- if seg_j:
- for k in range(j-1, -1, -1): # reversed(range(j)):
- if not seg_j:
- break
- seg_k= loop_segments[k]
-
- if seg_k and join_seg(seg_j, seg_k):
- joining_segments= True
-
- loop_list= loop_segments
-
- for verts in loop_list:
- while verts and verts[0][1]==verts[-1][1]:
- verts.pop()
-
- loop_list= [verts for verts in loop_list if len(verts)>2]
- # DONE DEALING WITH LOOP FIXING
-
-
- # vert mapping
- vert_map= [None]*len(indices)
- ii=0
- for verts in loop_list:
- if len(verts)>2:
- for i, vert in enumerate(verts):
- vert_map[i+ii]= vert[2]
- ii+=len(verts)
-
- fill= PolyFill([ [v[0] for v in loop] for loop in loop_list ])
- #draw_loops(loop_list)
- #raise 'done loop'
- # map to original indicies
- fill= [[vert_map[i] for i in reversed(f)] for f in fill]
-
-
- if not fill:
- print('Warning Cannot scanfill, fallback on a triangle fan.')
- fill= [ [0, i-1, i] for i in range(2, len(indices)) ]
- else:
- # Use real scanfill.
- # See if its flipped the wrong way.
- flip= None
- for fi in fill:
- if flip != None:
- break
- for i, vi in enumerate(fi):
- if vi==0 and fi[i-1]==1:
- flip= False
- break
- elif vi==1 and fi[i-1]==0:
- flip= True
- break
-
- if not flip:
- for i, fi in enumerate(fill):
- fill[i]= tuple([ii for ii in reversed(fi)])
-
- return fill
-
-def line_value(line_split):
- '''
- Returns 1 string represneting the value for this line
- None will be returned if theres only 1 word
- '''
- length= len(line_split)
- if length == 1:
- return None
-
- elif length == 2:
- return line_split[1]
-
- elif length > 2:
- return ' '.join( line_split[1:] )
-
-
-def obj_image_load(imagepath, DIR, IMAGE_SEARCH):
- if '_' in imagepath:
- image= load_image(imagepath.replace('_', ' '), DIR)
- if image:
- return image
-
- image = load_image(imagepath, DIR)
- if image:
- return image
-
- print("failed to load '%s' doesn't exist", imagepath)
- return None
-
-# def obj_image_load(imagepath, DIR, IMAGE_SEARCH):
-# '''
-# Mainly uses comprehensiveImageLoad
-# but tries to replace '_' with ' ' for Max's exporter replaces spaces with underscores.
-# '''
-
-# if '_' in imagepath:
-# image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
-# if image: return image
-# # Did the exporter rename the image?
-# image= BPyImage.comprehensiveImageLoad(imagepath.replace('_', ' '), DIR, PLACE_HOLDER= False, RECURSIVE= IMAGE_SEARCH)
-# if image: return image
-
-# # Return an image, placeholder if it dosnt exist
-# image= BPyImage.comprehensiveImageLoad(imagepath, DIR, PLACE_HOLDER= True, RECURSIVE= IMAGE_SEARCH)
-# return image
-
-
-def create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH):
- '''
- Create all the used materials in this obj,
- assign colors and images to the materials from all referenced material libs
- '''
- DIR= os.path.dirname(filepath)
-
- #==================================================================================#
- # This function sets textures defined in .mtl file #
- #==================================================================================#
- def load_material_image(blender_material, context_material_name, imagepath, type):
-
- texture= bpy.data.textures.new(name=type, type='IMAGE')
-
- # Absolute path - c:\.. etc would work here
- image = obj_image_load(imagepath, DIR, IMAGE_SEARCH)
- has_data = False
-
- if image:
- texture.image = image
- has_data = image.has_data
-
- # Adds textures for materials (rendering)
- if type == 'Kd':
- if has_data and image.depth == 32:
- # Image has alpha
-
- mtex = blender_material.texture_slots.add()
- mtex.texture = texture
- mtex.texture_coords = 'UV'
- mtex.use_map_color_diffuse = True
- mtex.use_map_alpha = True
-
- texture.mipmap = True
- texture.interpolation = True
- texture.use_alpha = True
- blender_material.use_transparency = True
- blender_material.alpha = 0.0
- else:
- mtex = blender_material.texture_slots.add()
- mtex.texture = texture
- mtex.texture_coords = 'UV'
- mtex.use_map_color_diffuse = True
-
- # adds textures to faces (Textured/Alt-Z mode)
- # Only apply the diffuse texture to the face if the image has not been set with the inline usemat func.
- unique_material_images[context_material_name]= image, has_data # set the texface image
-
- elif type == 'Ka':
- mtex = blender_material.texture_slots.add()
- mtex.texture = texture
- mtex.texture_coords = 'UV'
- mtex.use_map_ambient = True
-
- elif type == 'Ks':
- mtex = blender_material.texture_slots.add()
- mtex.texture = texture
- mtex.texture_coords = 'UV'
- mtex.use_map_specular = True
-
- elif type == 'Bump':
- mtex = blender_material.texture_slots.add()
- mtex.texture = texture
- mtex.texture_coords = 'UV'
- mtex.use_map_normal = True
-
- elif type == 'D':
- mtex = blender_material.texture_slots.add()
- mtex.texture = texture
- mtex.texture_coords = 'UV'
- mtex.use_map_alpha = True
- blender_material.use_transparency = True
- blender_material.transparency_method = 'Z_TRANSPARENCY'
- blender_material.alpha = 0.0
- # Todo, unset deffuse material alpha if it has an alpha channel
-
- elif type == 'refl':
- mtex = blender_material.texture_slots.add()
- mtex.texture = texture
- mtex.texture_coords = 'UV'
- mtex.use_map_reflect = True
-
-
- # Add an MTL with the same name as the obj if no MTLs are spesified.
- temp_mtl = os.path.splitext((os.path.basename(filepath)))[0] + '.mtl'
-
- if os.path.exists(os.path.join(DIR, temp_mtl)) and temp_mtl not in material_libs:
- material_libs.append( temp_mtl )
- del temp_mtl
-
- #Create new materials
- for name in unique_materials: # .keys()
- if name != None:
- unique_materials[name]= bpy.data.materials.new(name)
- unique_material_images[name]= None, False # assign None to all material images to start with, add to later.
-
- unique_materials[None]= None
- unique_material_images[None]= None, False
-
- for libname in material_libs:
- mtlpath= os.path.join(DIR, libname)
- if not os.path.exists(mtlpath):
- print ("\tError Missing MTL: '%s'" % mtlpath)
- else:
- #print '\t\tloading mtl: "%s"' % mtlpath
- context_material= None
- mtl= open(mtlpath, 'rU')
- for line in mtl: #.xreadlines():
- if line.startswith('newmtl'):
- context_material_name= line_value(line.split())
- if context_material_name in unique_materials:
- context_material = unique_materials[ context_material_name ]
- else:
- context_material = None
-
- elif context_material:
- # we need to make a material to assign properties to it.
- line_split= line.split()
- line_lower= line.lower().lstrip()
- if line_lower.startswith('ka'):
- context_material.mirror_color = float(line_split[1]), float(line_split[2]), float(line_split[3])
- elif line_lower.startswith('kd'):
- context_material.diffuse_color = float(line_split[1]), float(line_split[2]), float(line_split[3])
- elif line_lower.startswith('ks'):
- context_material.specular_color = float(line_split[1]), float(line_split[2]), float(line_split[3])
- elif line_lower.startswith('ns'):
- context_material.specular_hardness = int((float(line_split[1]) * 0.51))
- elif line_lower.startswith('ni'): # Refraction index
- context_material.raytrace_transparency.ior = max(1, min(float(line_split[1]), 3)) # between 1 and 3
- elif line_lower.startswith('d') or line_lower.startswith('tr'):
- context_material.alpha = float(line_split[1])
- context_material.use_transparency = True
- context_material.transparency_method = 'Z_TRANSPARENCY'
- elif line_lower.startswith('map_ka'):
- img_filepath= line_value(line.split())
- if img_filepath:
- load_material_image(context_material, context_material_name, img_filepath, 'Ka')
- elif line_lower.startswith('map_ks'):
- img_filepath= line_value(line.split())
- if img_filepath:
- load_material_image(context_material, context_material_name, img_filepath, 'Ks')
- elif line_lower.startswith('map_kd'):
- img_filepath= line_value(line.split())
- if img_filepath:
- load_material_image(context_material, context_material_name, img_filepath, 'Kd')
- elif line_lower.startswith('map_bump'):
- img_filepath= line_value(line.split())
- if img_filepath:
- load_material_image(context_material, context_material_name, img_filepath, 'Bump')
- elif line_lower.startswith('map_d') or line_lower.startswith('map_tr'): # Alpha map - Dissolve
- img_filepath= line_value(line.split())
- if img_filepath:
- load_material_image(context_material, context_material_name, img_filepath, 'D')
-
- elif line_lower.startswith('refl'): # reflectionmap
- img_filepath= line_value(line.split())
- if img_filepath:
- load_material_image(context_material, context_material_name, img_filepath, 'refl')
- mtl.close()
-
-
-
-
-def split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP):
- '''
- Takes vert_loc and faces, and separates into multiple sets of
- (verts_loc, faces, unique_materials, dataname)
- '''
-
- filename = os.path.splitext((os.path.basename(filepath)))[0]
-
- if not SPLIT_OB_OR_GROUP:
- # use the filename for the object name since we arnt chopping up the mesh.
- return [(verts_loc, faces, unique_materials, filename)]
-
- def key_to_name(key):
- # if the key is a tuple, join it to make a string
- if not key:
- return filename # assume its a string. make sure this is true if the splitting code is changed
- else:
- return key
-
- # Return a key that makes the faces unique.
- face_split_dict= {}
-
- oldkey= -1 # initialize to a value that will never match the key
-
- for face in faces:
- key= face[4]
-
- if oldkey != key:
- # Check the key has changed.
- try:
- verts_split, faces_split, unique_materials_split, vert_remap= face_split_dict[key]
- except KeyError:
- faces_split= []
- verts_split= []
- unique_materials_split= {}
- vert_remap= [-1]*len(verts_loc)
-
- face_split_dict[key]= (verts_split, faces_split, unique_materials_split, vert_remap)
-
- oldkey= key
-
- face_vert_loc_indicies= face[0]
-
- # Remap verts to new vert list and add where needed
- for enum, i in enumerate(face_vert_loc_indicies):
- if vert_remap[i] == -1:
- new_index= len(verts_split)
- vert_remap[i]= new_index # set the new remapped index so we only add once and can reference next time.
- face_vert_loc_indicies[enum] = new_index # remap to the local index
- verts_split.append( verts_loc[i] ) # add the vert to the local verts
- else:
- face_vert_loc_indicies[enum] = vert_remap[i] # remap to the local index
-
- matname= face[2]
- if matname and matname not in unique_materials_split:
- unique_materials_split[matname] = unique_materials[matname]
-
- faces_split.append(face)
-
- # remove one of the itemas and reorder
- return [(value[0], value[1], value[2], key_to_name(key)) for key, value in list(face_split_dict.items())]
-
-
-def create_mesh(new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc, verts_tex, faces, unique_materials, unique_material_images, unique_smooth_groups, vertex_groups, dataname):
- '''
- Takes all the data gathered and generates a mesh, adding the new object to new_objects
- deals with fgons, sharp edges and assigning materials
- '''
- if not has_ngons:
- CREATE_FGONS= False
-
- if unique_smooth_groups:
- sharp_edges= {}
- 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
- fgon_edges= {} # Used for storing fgon keys
- if CREATE_EDGES:
- edges= []
-
- context_object= None
-
- # reverse loop through face indicies
- for f_idx in range(len(faces)-1, -1, -1):
-
- face_vert_loc_indicies,\
- face_vert_tex_indicies,\
- context_material,\
- context_smooth_group,\
- context_object= faces[f_idx]
-
- len_face_vert_loc_indicies = len(face_vert_loc_indicies)
-
- if len_face_vert_loc_indicies==1:
- faces.pop(f_idx)# cant add single vert faces
-
- elif not face_vert_tex_indicies or len_face_vert_loc_indicies == 2: # faces that have no texture coords are lines
- if CREATE_EDGES:
- # generators are better in python 2.4+ but can't be used in 2.3
- # edges.extend( (face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in xrange(len_face_vert_loc_indicies-1) )
- edges.extend( [(face_vert_loc_indicies[i], face_vert_loc_indicies[i+1]) for i in range(len_face_vert_loc_indicies-1)] )
-
- faces.pop(f_idx)
- else:
-
- # Smooth Group
- if unique_smooth_groups and context_smooth_group:
- # Is a part of of a smooth group and is a face
- if context_smooth_group_old is not context_smooth_group:
- edge_dict= smooth_group_users[context_smooth_group]
- context_smooth_group_old= context_smooth_group
-
- for i in range(len_face_vert_loc_indicies):
- i1= face_vert_loc_indicies[i]
- i2= face_vert_loc_indicies[i-1]
- if i1>i2: i1,i2= i2,i1
-
- try:
- edge_dict[i1,i2]+= 1
- except KeyError:
- edge_dict[i1,i2]= 1
-
- # FGons into triangles
- if has_ngons and len_face_vert_loc_indicies > 4:
-
- ngon_face_indices= BPyMesh_ngon(verts_loc, face_vert_loc_indicies)
- faces.extend(
- [(
- [face_vert_loc_indicies[ngon[0]], face_vert_loc_indicies[ngon[1]], face_vert_loc_indicies[ngon[2]] ],
- [face_vert_tex_indicies[ngon[0]], face_vert_tex_indicies[ngon[1]], face_vert_tex_indicies[ngon[2]] ],
- context_material,
- context_smooth_group,
- context_object)
- for ngon in ngon_face_indices]
- )
-
- # edges to make fgons
- if CREATE_FGONS:
- edge_users= {}
- for ngon in ngon_face_indices:
- for i in (0,1,2):
- i1= face_vert_loc_indicies[ngon[i ]]
- i2= face_vert_loc_indicies[ngon[i-1]]
- if i1>i2: i1,i2= i2,i1
-
- try:
- edge_users[i1,i2]+=1
- except KeyError:
- edge_users[i1,i2]= 1
-
- for key, users in edge_users.items():
- if users>1:
- fgon_edges[key]= None
-
- # remove all after 3, means we dont have to pop this one.
- faces.pop(f_idx)
-
-
- # Build sharp edges
- if unique_smooth_groups:
- for edge_dict in list(smooth_group_users.values()):
- for key, users in list(edge_dict.items()):
- if users==1: # This edge is on the boundry of a group
- sharp_edges[key]= None
-
-
- # map the material names to an index
- material_mapping = {name: i for i, name in enumerate(unique_materials)} # enumerate over unique_materials keys()
-
- materials= [None] * len(unique_materials)
-
- for name, index in list(material_mapping.items()):
- materials[index]= unique_materials[name]
-
- me= bpy.data.meshes.new(dataname)
-
- # make sure the list isnt too big
- for material in materials:
- me.materials.append(material)
-
- me.vertices.add(len(verts_loc))
- me.faces.add(len(faces))
-
- # verts_loc is a list of (x, y, z) tuples
- me.vertices.foreach_set("co", unpack_list(verts_loc))
-
- # faces is a list of (vert_indices, texco_indices, ...) tuples
- # XXX faces should contain either 3 or 4 verts
- # XXX no check for valid face indices
- me.faces.foreach_set("vertices_raw", unpack_face_list([f[0] for f in faces]))
-
- if verts_tex and me.faces:
- me.uv_textures.new()
-
- context_material_old= -1 # avoid a dict lookup
- mat= 0 # rare case it may be un-initialized.
- me_faces= me.faces
-
- for i, face in enumerate(faces):
- if len(face[0]) < 2:
- pass #raise "bad face"
- elif len(face[0])==2:
- if CREATE_EDGES:
- edges.append(face[0])
- else:
-
- blender_face = me.faces[i]
-
- face_vert_loc_indicies,\
- face_vert_tex_indicies,\
- context_material,\
- context_smooth_group,\
- context_object= face
-
-
-
- if context_smooth_group:
- blender_face.use_smooth = True
-
- if context_material:
- if context_material_old is not context_material:
- mat= material_mapping[context_material]
- context_material_old= context_material
-
- blender_face.material_index= mat
-# blender_face.mat= mat
-
-
- if verts_tex:
-
- blender_tface= me.uv_textures[0].data[i]
-
- if context_material:
- image, has_data = unique_material_images[context_material]
- if image: # Can be none if the material dosnt have an image.
- blender_tface.image = image
- blender_tface.use_image = True
- if has_data and image.depth == 32:
- blender_tface.blend_type = 'ALPHA'
-
- # BUG - Evil eekadoodle problem where faces that have vert index 0 location at 3 or 4 are shuffled.
- if len(face_vert_loc_indicies)==4:
- if face_vert_loc_indicies[2]==0 or face_vert_loc_indicies[3]==0:
- face_vert_tex_indicies= face_vert_tex_indicies[2], face_vert_tex_indicies[3], face_vert_tex_indicies[0], face_vert_tex_indicies[1]
- else: # length of 3
- if face_vert_loc_indicies[2]==0:
- face_vert_tex_indicies= face_vert_tex_indicies[1], face_vert_tex_indicies[2], face_vert_tex_indicies[0]
- # END EEEKADOODLE FIX
-
- # assign material, uv's and image
- blender_tface.uv1= verts_tex[face_vert_tex_indicies[0]]
- blender_tface.uv2= verts_tex[face_vert_tex_indicies[1]]
- blender_tface.uv3= verts_tex[face_vert_tex_indicies[2]]
-
- if len(face_vert_loc_indicies)==4:
- blender_tface.uv4= verts_tex[face_vert_tex_indicies[3]]
-
-# for ii, uv in enumerate(blender_face.uv):
-# uv.x, uv.y= verts_tex[face_vert_tex_indicies[ii]]
- del me_faces
-# del ALPHA
-
- if CREATE_EDGES and not edges:
- CREATE_EDGES = False
-
- if CREATE_EDGES:
- me.edges.add(len(edges))
-
- # edges should be a list of (a, b) tuples
- me.edges.foreach_set("vertices", unpack_list(edges))
-# me_edges.extend( edges )
-
-# del me_edges
-
- # Add edge faces.
-# me_edges= me.edges
-
- def edges_match(e1, e2):
- return (e1[0] == e2[0] and e1[1] == e2[1]) or (e1[0] == e2[1] and e1[1] == e2[0])
-
- # XXX slow
-# if CREATE_FGONS and fgon_edges:
-# for fgon_edge in fgon_edges.keys():
-# for ed in me.edges:
-# if edges_match(fgon_edge, ed.vertices):
-# ed.is_fgon = True
-
-# if CREATE_FGONS and fgon_edges:
-# FGON= Mesh.EdgeFlags.FGON
-# for ed in me.findEdges( fgon_edges.keys() ):
-# if ed is not None:
-# me_edges[ed].flag |= FGON
-# del FGON
-
- # XXX slow
-# if unique_smooth_groups and sharp_edges:
-# for sharp_edge in sharp_edges.keys():
-# for ed in me.edges:
-# if edges_match(sharp_edge, ed.vertices):
-# ed.use_edge_sharp = True
-
-# if unique_smooth_groups and sharp_edges:
-# SHARP= Mesh.EdgeFlags.SHARP
-# for ed in me.findEdges( sharp_edges.keys() ):
-# if ed is not None:
-# me_edges[ed].flag |= SHARP
-# del SHARP
-
- me.update(calc_edges=CREATE_EDGES)
-# me.calcNormals()
-
- ob= bpy.data.objects.new("Mesh", me)
- new_objects.append(ob)
-
- # Create the vertex groups. No need to have the flag passed here since we test for the
- # content of the vertex_groups. If the user selects to NOT have vertex groups saved then
- # the following test will never run
- for group_name, group_indicies in vertex_groups.items():
- group= ob.vertex_groups.new(group_name)
- ob.vertex_groups.assign(group_indicies, group, 1.0, 'REPLACE')
-
-
-def create_nurbs(context_nurbs, vert_loc, new_objects):
- '''
- Add nurbs object to blender, only support one type at the moment
- '''
- deg = context_nurbs.get('deg', (3,))
- curv_range = context_nurbs.get('curv_range')
- curv_idx = context_nurbs.get('curv_idx', [])
- parm_u = context_nurbs.get('parm_u', [])
- parm_v = context_nurbs.get('parm_v', [])
- name = context_nurbs.get('name', 'ObjNurb')
- cstype = context_nurbs.get('cstype')
-
- if cstype is None:
- print('\tWarning, cstype not found')
- return
- if cstype != 'bspline':
- print('\tWarning, cstype is not supported (only bspline)')
- return
- if not curv_idx:
- print('\tWarning, curv argument empty or not set')
- return
- if len(deg) > 1 or parm_v:
- print('\tWarning, surfaces not supported')
- return
-
- cu = bpy.data.curves.new(name, 'CURVE')
- cu.dimensions = '3D'
-
- nu = cu.splines.new('NURBS')
- nu.points.add(len(curv_idx) - 1) # a point is added to start with
- nu.points.foreach_set("co", [co_axis for vt_idx in curv_idx for co_axis in (vert_loc[vt_idx] + (1.0,))])
-
- nu.order_u = deg[0] + 1
-
- # get for endpoint flag from the weighting
- if curv_range and len(parm_u) > deg[0]+1:
- do_endpoints = True
- for i in range(deg[0]+1):
-
- if abs(parm_u[i]-curv_range[0]) > 0.0001:
- do_endpoints = False
- break
-
- if abs(parm_u[-(i+1)]-curv_range[1]) > 0.0001:
- do_endpoints = False
- break
-
- else:
- do_endpoints = False
-
- if do_endpoints:
- nu.use_endpoint_u = True
-
-
- # close
- '''
- do_closed = False
- if len(parm_u) > deg[0]+1:
- for i in xrange(deg[0]+1):
- #print curv_idx[i], curv_idx[-(i+1)]
-
- if curv_idx[i]==curv_idx[-(i+1)]:
- do_closed = True
- break
-
- if do_closed:
- nu.use_cyclic_u = True
- '''
-
- ob= bpy.data.objects.new("Nurb", cu)
-
- new_objects.append(ob)
-
-
-def strip_slash(line_split):
- if line_split[-1][-1]== '\\':
- if len(line_split[-1])==1:
- line_split.pop() # remove the \ item
- else:
- line_split[-1]= line_split[-1][:-1] # remove the \ from the end last number
- return True
- return False
-
-
-
-def get_float_func(filepath):
- '''
- find the float function for this obj file
- - whether to replace commas or not
- '''
- file= open(filepath, 'rU')
- for line in file: #.xreadlines():
- line = line.lstrip()
- if line.startswith('v'): # vn vt v
- if ',' in line:
- return lambda f: float(f.replace(',', '.'))
- elif '.' in line:
- return float
-
- # incase all vert values were ints
- return float
-
-def load(operator, context, filepath,
- CLAMP_SIZE= 0.0,
- CREATE_FGONS= True,
- CREATE_SMOOTH_GROUPS= True,
- CREATE_EDGES= True,
- SPLIT_OBJECTS= True,
- SPLIT_GROUPS= True,
- ROTATE_X90= True,
- IMAGE_SEARCH=True,
- POLYGROUPS=False):
- '''
- Called by the user interface or another script.
- load_obj(path) - should give acceptable results.
- This function passes the file and sends the data off
- to be split into objects and then converted into mesh objects
- '''
- print('\nimporting obj %r' % filepath)
-
- if SPLIT_OBJECTS or SPLIT_GROUPS:
- POLYGROUPS = False
-
- time_main= time.time()
-# time_main= sys.time()
-
- verts_loc= []
- verts_tex= []
- faces= [] # tuples of the faces
- material_libs= [] # filanems to material libs this uses
- vertex_groups = {} # when POLYGROUPS is true
-
- # Get the string to float conversion func for this file- is 'float' for almost all files.
- float_func= get_float_func(filepath)
-
- # Context variables
- context_material= None
- context_smooth_group= None
- context_object= None
- context_vgroup = None
-
- # Nurbs
- context_nurbs = {}
- nurbs = []
- context_parm = '' # used by nurbs too but could be used elsewhere
-
- has_ngons= False
- # has_smoothgroups= False - is explicit with len(unique_smooth_groups) being > 0
-
- # Until we can use sets
- unique_materials= {}
- unique_material_images= {}
- unique_smooth_groups= {}
- # unique_obects= {} - no use for this variable since the objects are stored in the face.
-
- # when there are faces that end with \
- # it means they are multiline-
- # since we use xreadline we cant skip to the next line
- # so we need to know whether
- context_multi_line= ''
-
- print("\tparsing obj file...")
- time_sub= time.time()
-# time_sub= sys.time()
-
- file= open(filepath, 'rU')
- for line in file: #.xreadlines():
- line = line.lstrip() # rare cases there is white space at the start of the line
-
- if line.startswith('v '):
- line_split= line.split()
- # rotate X90: (x,-z,y)
- verts_loc.append( (float_func(line_split[1]), -float_func(line_split[3]), float_func(line_split[2])) )
-
- elif line.startswith('vn '):
- pass
-
- elif line.startswith('vt '):
- line_split= line.split()
- verts_tex.append( (float_func(line_split[1]), float_func(line_split[2])) )
-
- # Handel faces lines (as faces) and the second+ lines of fa multiline face here
- # use 'f' not 'f ' because some objs (very rare have 'fo ' for faces)
- elif line.startswith('f') or context_multi_line == 'f':
-
- if context_multi_line:
- # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face
- line_split= line.split()
-
- else:
- line_split= line[2:].split()
- face_vert_loc_indicies= []
- face_vert_tex_indicies= []
-
- # Instance a face
- faces.append((\
- face_vert_loc_indicies,\
- face_vert_tex_indicies,\
- context_material,\
- context_smooth_group,\
- context_object\
- ))
-
- if strip_slash(line_split):
- context_multi_line = 'f'
- else:
- context_multi_line = ''
-
- for v in line_split:
- obj_vert= v.split('/')
-
- vert_loc_index= int(obj_vert[0])-1
- # Add the vertex to the current group
- # *warning*, this wont work for files that have groups defined around verts
- if POLYGROUPS and context_vgroup:
- vertex_groups[context_vgroup].append(vert_loc_index)
-
- # Make relative negative vert indicies absolute
- if vert_loc_index < 0:
- vert_loc_index= len(verts_loc) + vert_loc_index + 1
-
- face_vert_loc_indicies.append(vert_loc_index)
-
- if len(obj_vert)>1 and obj_vert[1]:
- # formatting for faces with normals and textures us
- # loc_index/tex_index/nor_index
-
- vert_tex_index= int(obj_vert[1])-1
- # Make relative negative vert indicies absolute
- if vert_tex_index < 0:
- vert_tex_index= len(verts_tex) + vert_tex_index + 1
-
- face_vert_tex_indicies.append(vert_tex_index)
- else:
- # dummy
- face_vert_tex_indicies.append(0)
-
- if len(face_vert_loc_indicies) > 4:
- has_ngons= True
-
- elif CREATE_EDGES and (line.startswith('l ') or context_multi_line == 'l'):
- # very similar to the face load function above with some parts removed
-
- if context_multi_line:
- # use face_vert_loc_indicies and face_vert_tex_indicies previously defined and used the obj_face
- line_split= line.split()
-
- else:
- line_split= line[2:].split()
- face_vert_loc_indicies= []
- face_vert_tex_indicies= []
-
- # Instance a face
- faces.append((\
- face_vert_loc_indicies,\
- face_vert_tex_indicies,\
- context_material,\
- context_smooth_group,\
- context_object\
- ))
-
- if strip_slash(line_split):
- context_multi_line = 'l'
- else:
- context_multi_line = ''
-
- isline= line.startswith('l')
-
- for v in line_split:
- vert_loc_index= int(v)-1
-
- # Make relative negative vert indicies absolute
- if vert_loc_index < 0:
- vert_loc_index= len(verts_loc) + vert_loc_index + 1
-
- face_vert_loc_indicies.append(vert_loc_index)
-
- elif line.startswith('s'):
- if CREATE_SMOOTH_GROUPS:
- context_smooth_group= line_value(line.split())
- if context_smooth_group=='off':
- context_smooth_group= None
- elif context_smooth_group: # is not None
- unique_smooth_groups[context_smooth_group]= None
-
- elif line.startswith('o'):
- if SPLIT_OBJECTS:
- context_object= line_value(line.split())
- # unique_obects[context_object]= None
-
- elif line.startswith('g'):
- if SPLIT_GROUPS:
- context_object= line_value(line.split())
- # print 'context_object', context_object
- # unique_obects[context_object]= None
- elif POLYGROUPS:
- context_vgroup = line_value(line.split())
- if context_vgroup and context_vgroup != '(null)':
- vertex_groups.setdefault(context_vgroup, [])
- else:
- context_vgroup = None # dont assign a vgroup
-
- elif line.startswith('usemtl'):
- context_material= line_value(line.split())
- unique_materials[context_material]= None
- elif line.startswith('mtllib'): # usemap or usemat
- material_libs = list(set(material_libs) | set(line.split()[1:])) # can have multiple mtllib filenames per line, mtllib can appear more than once, so make sure only occurance of material exists
-
- # Nurbs support
- elif line.startswith('cstype '):
- context_nurbs['cstype']= line_value(line.split()) # 'rat bspline' / 'bspline'
- elif line.startswith('curv ') or context_multi_line == 'curv':
- line_split= line.split()
-
- curv_idx = context_nurbs['curv_idx'] = context_nurbs.get('curv_idx', []) # incase were multiline
-
- if not context_multi_line:
- context_nurbs['curv_range'] = float_func(line_split[1]), float_func(line_split[2])
- line_split[0:3] = [] # remove first 3 items
-
- if strip_slash(line_split):
- context_multi_line = 'curv'
- else:
- context_multi_line = ''
-
-
- for i in line_split:
- vert_loc_index = int(i)-1
-
- if vert_loc_index < 0:
- vert_loc_index= len(verts_loc) + vert_loc_index + 1
-
- curv_idx.append(vert_loc_index)
-
- elif line.startswith('parm') or context_multi_line == 'parm':
- line_split= line.split()
-
- if context_multi_line:
- context_multi_line = ''
- else:
- context_parm = line_split[1]
- line_split[0:2] = [] # remove first 2
-
- if strip_slash(line_split):
- context_multi_line = 'parm'
- else:
- context_multi_line = ''
-
- if context_parm.lower() == 'u':
- context_nurbs.setdefault('parm_u', []).extend( [float_func(f) for f in line_split] )
- elif context_parm.lower() == 'v': # surfaces not suported yet
- context_nurbs.setdefault('parm_v', []).extend( [float_func(f) for f in line_split] )
- # else: # may want to support other parm's ?
-
- elif line.startswith('deg '):
- context_nurbs['deg']= [int(i) for i in line.split()[1:]]
- elif line.startswith('end'):
- # Add the nurbs curve
- if context_object:
- context_nurbs['name'] = context_object
- nurbs.append(context_nurbs)
- context_nurbs = {}
- context_parm = ''
-
- ''' # How to use usemap? depricated?
- elif line.startswith('usema'): # usemap or usemat
- context_image= line_value(line.split())
- '''
-
- file.close()
- time_new= time.time()
-# time_new= sys.time()
- print('%.4f sec' % (time_new-time_sub))
- time_sub= time_new
-
-
- print('\tloading materials and images...')
- create_materials(filepath, material_libs, unique_materials, unique_material_images, IMAGE_SEARCH)
-
- time_new= time.time()
-# time_new= sys.time()
- print('%.4f sec' % (time_new-time_sub))
- time_sub= time_new
-
- if not ROTATE_X90:
- verts_loc[:] = [(v[0], v[2], -v[1]) for v in verts_loc]
-
- # deselect all
- bpy.ops.object.select_all(action='DESELECT')
-
- scene = context.scene
-# scn.objects.selected = []
- new_objects= [] # put new objects here
-
- print('\tbuilding geometry...\n\tverts:%i faces:%i materials: %i smoothgroups:%i ...' % ( len(verts_loc), len(faces), len(unique_materials), len(unique_smooth_groups) ))
- # Split the mesh by objects/materials, may
- if SPLIT_OBJECTS or SPLIT_GROUPS: SPLIT_OB_OR_GROUP = True
- else: SPLIT_OB_OR_GROUP = False
-
- for verts_loc_split, faces_split, unique_materials_split, dataname in split_mesh(verts_loc, faces, unique_materials, filepath, SPLIT_OB_OR_GROUP):
- # Create meshes from the data, warning 'vertex_groups' wont support splitting
- create_mesh(new_objects, has_ngons, CREATE_FGONS, CREATE_EDGES, verts_loc_split, verts_tex, faces_split, unique_materials_split, unique_material_images, unique_smooth_groups, vertex_groups, dataname)
-
- # nurbs support
- for context_nurbs in nurbs:
- create_nurbs(context_nurbs, verts_loc, new_objects)
-
- # Create new obj
- for obj in new_objects:
- base = scene.objects.link(obj)
- base.select = True
-
- scene.update()
-
-
- axis_min= [ 1000000000]*3
- axis_max= [-1000000000]*3
-
-# if CLAMP_SIZE:
-# # Get all object bounds
-# for ob in new_objects:
-# for v in ob.getBoundBox():
-# for axis, value in enumerate(v):
-# if axis_min[axis] > value: axis_min[axis]= value
-# if axis_max[axis] < value: axis_max[axis]= value
-
-# # Scale objects
-# max_axis= max(axis_max[0]-axis_min[0], axis_max[1]-axis_min[1], axis_max[2]-axis_min[2])
-# scale= 1.0
-
-# while CLAMP_SIZE < max_axis * scale:
-# scale= scale/10.0
-
-# for ob in new_objects:
-# ob.setSize(scale, scale, scale)
-
- # Better rotate the vert locations
- #if not ROTATE_X90:
- # for ob in new_objects:
- # ob.RotX = -1.570796326794896558
-
- time_new= time.time()
-# time_new= sys.time()
-
- print('finished importing: %r in %.4f sec.' % (filepath, (time_new-time_main)))
- return {'FINISHED'}
-
-
-# NOTES (all line numbers refer to 2.4x import_obj.py, not this file)
-# check later: line 489
-# can convert now: edge flags, edges: lines 508-528
-# ngon (uses python module BPyMesh): 384-414
-# NEXT clamp size: get bound box with RNA
-# get back to l 140 (here)
-# search image in bpy.config.textureDir - load_image
-# replaced BPyImage.comprehensiveImageLoad with a simplified version that only checks additional directory specified, but doesn't search dirs recursively (obj_image_load)
-# bitmask won't work? - 132
-# uses bpy.sys.time()
-
-if __name__ == "__main__":
- register()
diff --git a/release/scripts/op/io_scene_x3d/__init__.py b/release/scripts/op/io_scene_x3d/__init__.py
deleted file mode 100644
index 4ccd29808bf..00000000000
--- a/release/scripts/op/io_scene_x3d/__init__.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# ##### 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 #####
-
-# To support reload properly, try to access a package var, if it's there, reload everything
-if "bpy" in locals():
- # only reload if we alredy loaded, highly annoying
- import sys
- reload(sys.modules.get("io_scene_x3d.export_x3d", sys))
-
-
-import bpy
-from bpy.props import *
-from io_utils import ExportHelper
-
-
-class ExportX3D(bpy.types.Operator, ExportHelper):
- '''Export selection to Extensible 3D file (.x3d)'''
- bl_idname = "export_scene.x3d"
- bl_label = 'Export X3D'
-
- filename_ext = ".x3d"
-
- use_apply_modifiers = BoolProperty(name="Apply Modifiers", description="Use transformed mesh data from each object", default=True)
- use_triangulate = BoolProperty(name="Triangulate", description="Triangulate quads.", default=False)
- use_compress = BoolProperty(name="Compress", description="GZip the resulting file, requires a full python install", default=False)
-
- def execute(self, context):
- import io_scene_x3d.export_x3d
- return io_scene_x3d.export_x3d.save(self, context, **self.properties)
-
-
-def menu_func(self, context):
- self.layout.operator(ExportX3D.bl_idname, text="X3D Extensible 3D (.x3d)")
-
-
-def register():
- bpy.types.INFO_MT_file_export.append(menu_func)
-
-def unregister():
- bpy.types.INFO_MT_file_export.remove(menu_func)
-
-# NOTES
-# - blender version is hardcoded
-
-if __name__ == "__main__":
- register()
diff --git a/release/scripts/op/io_scene_x3d/export_x3d.py b/release/scripts/op/io_scene_x3d/export_x3d.py
deleted file mode 100644
index 3159d0c9acd..00000000000
--- a/release/scripts/op/io_scene_x3d/export_x3d.py
+++ /dev/null
@@ -1,1123 +0,0 @@
-# ##### 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>
-
-# Contributors: bart:neeneenee*de, http://www.neeneenee.de/vrml, Campbell Barton
-
-"""
-This script exports to X3D format.
-
-Usage:
-Run this script from "File->Export" menu. A pop-up will ask whether you
-want to export only selected or all relevant objects.
-
-Known issues:
- Doesn't handle multiple materials (don't use material indices);<br>
- Doesn't handle multiple UV textures on a single mesh (create a mesh for each texture);<br>
- Can't get the texture array associated with material * not the UV ones;
-"""
-
-import math
-import os
-
-import bpy
-import mathutils
-
-from io_utils import create_derived_objects, free_derived_objects
-
-DEG2RAD=0.017453292519943295
-MATWORLD= mathutils.Matrix.Rotation(-90, 4, 'X')
-
-####################################
-# Global Variables
-####################################
-
-filepath = ""
-_safeOverwrite = True
-
-extension = ''
-
-##########################################################
-# Functions for writing output file
-##########################################################
-
-class x3d_class:
-
- def __init__(self, filepath):
- #--- public you can change these ---
- self.writingcolor = 0
- self.writingtexture = 0
- self.writingcoords = 0
- self.proto = 1
- self.matonly = 0
- self.share = 0
- self.billnode = 0
- self.halonode = 0
- self.collnode = 0
- self.tilenode = 0
- self.verbose=2 # level of verbosity in console 0-none, 1-some, 2-most
- self.cp=3 # decimals for material color values 0.000 - 1.000
- self.vp=3 # decimals for vertex coordinate values 0.000 - n.000
- self.tp=3 # decimals for texture coordinate values 0.000 - 1.000
- self.it=3
-
- #--- class private don't touch ---
- self.texNames={} # dictionary of textureNames
- self.matNames={} # dictionary of materiaNames
- self.meshNames={} # dictionary of meshNames
- self.indentLevel=0 # keeps track of current indenting
- self.filepath=filepath
- self.file = None
- if filepath.lower().endswith('.x3dz'):
- try:
- import gzip
- self.file = gzip.open(filepath, "w")
- except:
- print("failed to import compression modules, exporting uncompressed")
- self.filepath = filepath[:-1] # remove trailing z
-
- if self.file is None:
- self.file = open(self.filepath, "w")
-
- self.bNav=0
- self.nodeID=0
- self.namesReserved=[ "Anchor","Appearance","Arc2D","ArcClose2D","AudioClip","Background","Billboard",
- "BooleanFilter","BooleanSequencer","BooleanToggle","BooleanTrigger","Box","Circle2D",
- "Collision","Color","ColorInterpolator","ColorRGBA","component","Cone","connect",
- "Contour2D","ContourPolyline2D","Coordinate","CoordinateDouble","CoordinateInterpolator",
- "CoordinateInterpolator2D","Cylinder","CylinderSensor","DirectionalLight","Disk2D",
- "ElevationGrid","EspduTransform","EXPORT","ExternProtoDeclare","Extrusion","field",
- "fieldValue","FillProperties","Fog","FontStyle","GeoCoordinate","GeoElevationGrid",
- "GeoLocationLocation","GeoLOD","GeoMetadata","GeoOrigin","GeoPositionInterpolator",
- "GeoTouchSensor","GeoViewpoint","Group","HAnimDisplacer","HAnimHumanoid","HAnimJoint",
- "HAnimSegment","HAnimSite","head","ImageTexture","IMPORT","IndexedFaceSet",
- "IndexedLineSet","IndexedTriangleFanSet","IndexedTriangleSet","IndexedTriangleStripSet",
- "Inline","IntegerSequencer","IntegerTrigger","IS","KeySensor","LineProperties","LineSet",
- "LoadSensor","LOD","Material","meta","MetadataDouble","MetadataFloat","MetadataInteger",
- "MetadataSet","MetadataString","MovieTexture","MultiTexture","MultiTextureCoordinate",
- "MultiTextureTransform","NavigationInfo","Normal","NormalInterpolator","NurbsCurve",
- "NurbsCurve2D","NurbsOrientationInterpolator","NurbsPatchSurface",
- "NurbsPositionInterpolator","NurbsSet","NurbsSurfaceInterpolator","NurbsSweptSurface",
- "NurbsSwungSurface","NurbsTextureCoordinate","NurbsTrimmedSurface","OrientationInterpolator",
- "PixelTexture","PlaneSensor","PointLight","PointSet","Polyline2D","Polypoint2D",
- "PositionInterpolator","PositionInterpolator2D","ProtoBody","ProtoDeclare","ProtoInstance",
- "ProtoInterface","ProximitySensor","ReceiverPdu","Rectangle2D","ROUTE","ScalarInterpolator",
- "Scene","Script","Shape","SignalPdu","Sound","Sphere","SphereSensor","SpotLight","StaticGroup",
- "StringSensor","Switch","Text","TextureBackground","TextureCoordinate","TextureCoordinateGenerator",
- "TextureTransform","TimeSensor","TimeTrigger","TouchSensor","Transform","TransmitterPdu",
- "TriangleFanSet","TriangleSet","TriangleSet2D","TriangleStripSet","Viewpoint","VisibilitySensor",
- "WorldInfo","X3D","XvlShell","VertexShader","FragmentShader","MultiShaderAppearance","ShaderAppearance" ]
- self.namesStandard=[ "Empty","Empty.000","Empty.001","Empty.002","Empty.003","Empty.004","Empty.005",
- "Empty.006","Empty.007","Empty.008","Empty.009","Empty.010","Empty.011","Empty.012",
- "Scene.001","Scene.002","Scene.003","Scene.004","Scene.005","Scene.06","Scene.013",
- "Scene.006","Scene.007","Scene.008","Scene.009","Scene.010","Scene.011","Scene.012",
- "World","World.000","World.001","World.002","World.003","World.004","World.005" ]
- self.namesFog=[ "","LINEAR","EXPONENTIAL","" ]
-
-##########################################################
-# Writing nodes routines
-##########################################################
-
- def writeHeader(self):
- #bfile = sys.expandpath( Blender.Get('filepath') ).replace('<', '&lt').replace('>', '&gt')
- bfile = repr(os.path.basename(self.filepath).replace('<', '&lt').replace('>', '&gt'))[1:-1] # use outfile name
- self.file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
- self.file.write("<!DOCTYPE X3D PUBLIC \"ISO//Web3D//DTD X3D 3.0//EN\" \"http://www.web3d.org/specifications/x3d-3.0.dtd\">\n")
- self.file.write("<X3D version=\"3.0\" profile=\"Immersive\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema-instance\" xsd:noNamespaceSchemaLocation=\"http://www.web3d.org/specifications/x3d-3.0.xsd\">\n")
- self.file.write("<head>\n")
- self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % bfile)
- # self.file.write("\t<meta name=\"filename\" content=\"%s\" />\n" % sys.basename(bfile))
- self.file.write("\t<meta name=\"generator\" content=\"Blender %s\" />\n" % bpy.app.version_string)
- # self.file.write("\t<meta name=\"generator\" content=\"Blender %s\" />\n" % Blender.Get('version'))
- self.file.write("\t<meta name=\"translator\" content=\"X3D exporter v1.55 (2006/01/17)\" />\n")
- self.file.write("</head>\n")
- self.file.write("<Scene>\n")
-
- # This functionality is poorly defined, disabling for now - campbell
- '''
- def writeInline(self):
- inlines = Blender.Scene.Get()
- allinlines = len(inlines)
- if scene != inlines[0]:
- return
- else:
- for i in xrange(allinlines):
- nameinline=inlines[i].name
- if (nameinline not in self.namesStandard) and (i > 0):
- self.file.write("<Inline DEF=\"%s\" " % (self.cleanStr(nameinline)))
- nameinline = nameinline+".x3d"
- self.file.write("url=\"%s\" />" % nameinline)
- self.file.write("\n\n")
-
-
- def writeScript(self):
- textEditor = Blender.Text.Get()
- alltext = len(textEditor)
- for i in xrange(alltext):
- nametext = textEditor[i].name
- nlines = textEditor[i].getNLines()
- if (self.proto == 1):
- if (nametext == "proto" or nametext == "proto.js" or nametext == "proto.txt") and (nlines != None):
- nalllines = len(textEditor[i].asLines())
- alllines = textEditor[i].asLines()
- for j in xrange(nalllines):
- self.writeIndented(alllines[j] + "\n")
- elif (self.proto == 0):
- if (nametext == "route" or nametext == "route.js" or nametext == "route.txt") and (nlines != None):
- nalllines = len(textEditor[i].asLines())
- alllines = textEditor[i].asLines()
- for j in xrange(nalllines):
- self.writeIndented(alllines[j] + "\n")
- self.writeIndented("\n")
- '''
-
- def writeViewpoint(self, ob, mat, scene):
- context = scene.render
- # context = scene.render
- ratio = float(context.resolution_x)/float(context.resolution_y)
- # ratio = float(context.imageSizeY())/float(context.imageSizeX())
- lens = (360* (math.atan(ratio *16 / ob.data.lens) / math.pi))*(math.pi/180)
- # lens = (360* (math.atan(ratio *16 / ob.data.getLens()) / math.pi))*(math.pi/180)
- lens = min(lens, math.pi)
-
- # get the camera location, subtract 90 degress from X to orient like X3D does
- # mat = ob.matrix_world - mat is now passed!
-
- loc = self.rotatePointForVRML(mat.translation_part())
- rot = mat.to_euler()
- rot = (((rot[0]-90)), rot[1], rot[2])
- # rot = (((rot[0]-90)*DEG2RAD), rot[1]*DEG2RAD, rot[2]*DEG2RAD)
- nRot = self.rotatePointForVRML( rot )
- # convert to Quaternion and to Angle Axis
- Q = self.eulerToQuaternions(nRot[0], nRot[1], nRot[2])
- Q1 = self.multiplyQuaternions(Q[0], Q[1])
- Qf = self.multiplyQuaternions(Q1, Q[2])
- angleAxis = self.quaternionToAngleAxis(Qf)
- self.file.write("<Viewpoint DEF=\"%s\" " % (self.cleanStr(ob.name)))
- self.file.write("description=\"%s\" " % (ob.name))
- self.file.write("centerOfRotation=\"0 0 0\" ")
- self.file.write("position=\"%3.2f %3.2f %3.2f\" " % (loc[0], loc[1], loc[2]))
- self.file.write("orientation=\"%3.2f %3.2f %3.2f %3.2f\" " % (angleAxis[0], angleAxis[1], -angleAxis[2], angleAxis[3]))
- self.file.write("fieldOfView=\"%.3f\" />\n\n" % (lens))
-
- def writeFog(self, world):
- if world:
- mtype = world.mist_settings.falloff
- mparam = world.mist_settings
- grd = world.horizon_color
- grd0, grd1, grd2 = grd[0], grd[1], grd[2]
- else:
- return
- if (mtype == 'LINEAR' or mtype == 'INVERSE_QUADRATIC'):
- mtype = 1 if mtype == 'LINEAR' else 2
- # if (mtype == 1 or mtype == 2):
- self.file.write("<Fog fogType=\"%s\" " % self.namesFog[mtype])
- self.file.write("color=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
- self.file.write("visibilityRange=\"%s\" />\n\n" % round(mparam[2],self.cp))
- else:
- return
-
- def writeNavigationInfo(self, scene):
- self.file.write('<NavigationInfo headlight="false" visibilityLimit="0.0" type=\'"EXAMINE","ANY"\' avatarSize="0.25, 1.75, 0.75" />\n')
-
- def writeSpotLight(self, ob, mtx, lamp, world):
- safeName = self.cleanStr(ob.name)
- if world:
- ambi = world.ambient_color
- # ambi = world.amb
- ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
- else:
- ambi = 0
- ambientIntensity = 0
-
- # compute cutoff and beamwidth
- intensity=min(lamp.energy/1.75,1.0)
- beamWidth=lamp.spot_size * 0.37;
- # beamWidth=((lamp.spotSize*math.pi)/180.0)*.37;
- cutOffAngle=beamWidth*1.3
-
- dx,dy,dz=self.computeDirection(mtx)
- # note -dx seems to equal om[3][0]
- # note -dz seems to equal om[3][1]
- # note dy seems to equal om[3][2]
-
- #location=(ob.matrix_world*MATWORLD).translation_part() # now passed
- location=(mtx*MATWORLD).translation_part()
-
- radius = lamp.distance*math.cos(beamWidth)
- # radius = lamp.dist*math.cos(beamWidth)
- self.file.write("<SpotLight DEF=\"%s\" " % safeName)
- self.file.write("radius=\"%s\" " % (round(radius,self.cp)))
- self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp)))
- self.file.write("intensity=\"%s\" " % (round(intensity,self.cp)))
- self.file.write("color=\"%s %s %s\" " % (round(lamp.color[0],self.cp), round(lamp.color[1],self.cp), round(lamp.color[2],self.cp)))
- # self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp)))
- self.file.write("beamWidth=\"%s\" " % (round(beamWidth,self.cp)))
- self.file.write("cutOffAngle=\"%s\" " % (round(cutOffAngle,self.cp)))
- self.file.write("direction=\"%s %s %s\" " % (round(dx,3),round(dy,3),round(dz,3)))
- self.file.write("location=\"%s %s %s\" />\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3)))
-
-
- def writeDirectionalLight(self, ob, mtx, lamp, world):
- safeName = self.cleanStr(ob.name)
- if world:
- ambi = world.ambient_color
- # ambi = world.amb
- ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
- else:
- ambi = 0
- ambientIntensity = 0
-
- intensity=min(lamp.energy/1.75,1.0)
- (dx,dy,dz)=self.computeDirection(mtx)
- self.file.write("<DirectionalLight DEF=\"%s\" " % safeName)
- self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp)))
- self.file.write("color=\"%s %s %s\" " % (round(lamp.color[0],self.cp), round(lamp.color[1],self.cp), round(lamp.color[2],self.cp)))
- # self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp)))
- self.file.write("intensity=\"%s\" " % (round(intensity,self.cp)))
- self.file.write("direction=\"%s %s %s\" />\n\n" % (round(dx,4),round(dy,4),round(dz,4)))
-
- def writePointLight(self, ob, mtx, lamp, world):
- safeName = self.cleanStr(ob.name)
- if world:
- ambi = world.ambient_color
- # ambi = world.amb
- ambientIntensity = ((float(ambi[0] + ambi[1] + ambi[2]))/3)/2.5
- else:
- ambi = 0
- ambientIntensity = 0
-
- # location=(ob.matrix_world*MATWORLD).translation_part() # now passed
- location= (mtx*MATWORLD).translation_part()
-
- self.file.write("<PointLight DEF=\"%s\" " % safeName)
- self.file.write("ambientIntensity=\"%s\" " % (round(ambientIntensity,self.cp)))
- self.file.write("color=\"%s %s %s\" " % (round(lamp.color[0],self.cp), round(lamp.color[1],self.cp), round(lamp.color[2],self.cp)))
- # self.file.write("color=\"%s %s %s\" " % (round(lamp.col[0],self.cp), round(lamp.col[1],self.cp), round(lamp.col[2],self.cp)))
- self.file.write("intensity=\"%s\" " % (round( min(lamp.energy/1.75,1.0) ,self.cp)))
- self.file.write("radius=\"%s\" " % lamp.distance )
- # self.file.write("radius=\"%s\" " % lamp.dist )
- self.file.write("location=\"%s %s %s\" />\n\n" % (round(location[0],3), round(location[1],3), round(location[2],3)))
- '''
- def writeNode(self, ob, mtx):
- obname=str(ob.name)
- if obname in self.namesStandard:
- return
- else:
- dx,dy,dz = self.computeDirection(mtx)
- # 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)))
- self.writeIndented("location=\"%s %s %s\"\n" % (round(location[0],3), round(location[1],3), round(location[2],3)))
- self.writeIndented("/>\n",-1)
- self.writeIndented("\n")
- '''
- def secureName(self, name):
- name = name + str(self.nodeID)
- self.nodeID=self.nodeID+1
- if len(name) <= 3:
- newname = "_" + str(self.nodeID)
- return "%s" % (newname)
- else:
- for bad in ['"','#',"'",',','.','[','\\',']','{','}']:
- name=name.replace(bad,'_')
- if name in self.namesReserved:
- newname = name[0:3] + "_" + str(self.nodeID)
- return "%s" % (newname)
- elif name[0].isdigit():
- newname = "_" + name + str(self.nodeID)
- return "%s" % (newname)
- else:
- newname = name
- return "%s" % (newname)
-
- def writeIndexedFaceSet(self, ob, mesh, mtx, world, EXPORT_TRI = False):
- imageMap={} # set of used images
- sided={} # 'one':cnt , 'two':cnt
- vColors={} # 'multi':1
- meshName = self.cleanStr(ob.name)
-
- meshME = self.cleanStr(ob.data.name) # We dont care if its the mesh name or not
- # meshME = self.cleanStr(ob.getData(mesh=1).name) # We dont care if its the mesh name or not
- if len(mesh.faces) == 0: return
- mode = []
- # mode = 0
- if mesh.uv_textures.active:
- # if mesh.faceUV:
- for face in mesh.uv_textures.active.data:
- # for face in mesh.faces:
- if face.use_halo and 'HALO' not in mode:
- mode += ['HALO']
- if face.use_billboard and 'BILLBOARD' not in mode:
- mode += ['BILLBOARD']
- if face.use_object_color and 'OBJECT_COLOR' not in mode:
- mode += ['OBJECT_COLOR']
- if face.use_collision and 'COLLISION' not in mode:
- mode += ['COLLISION']
- # mode |= face.mode
-
- if 'HALO' in mode and self.halonode == 0:
- # if mode & Mesh.FaceModes.HALO and self.halonode == 0:
- self.writeIndented("<Billboard axisOfRotation=\"0 0 0\">\n",1)
- self.halonode = 1
- elif 'BILLBOARD' in mode and self.billnode == 0:
- # elif mode & Mesh.FaceModes.BILLBOARD and self.billnode == 0:
- self.writeIndented("<Billboard axisOfRotation=\"0 1 0\">\n",1)
- self.billnode = 1
- elif 'OBJECT_COLOR' in mode and self.matonly == 0:
- # elif mode & Mesh.FaceModes.OBCOL and self.matonly == 0:
- self.matonly = 1
- # TF_TILES is marked as deprecated in DNA_meshdata_types.h
- # elif mode & Mesh.FaceModes.TILES and self.tilenode == 0:
- # self.tilenode = 1
- elif 'COLLISION' not in mode and self.collnode == 0:
- # elif not mode & Mesh.FaceModes.DYNAMIC and self.collnode == 0:
- self.writeIndented("<Collision enabled=\"false\">\n",1)
- self.collnode = 1
-
- nIFSCnt=self.countIFSSetsNeeded(mesh, imageMap, sided, vColors)
-
- if nIFSCnt > 1:
- self.writeIndented("<Group DEF=\"%s%s\">\n" % ("G_", meshName),1)
-
- if 'two' in sided and sided['two'] > 0:
- bTwoSided=1
- else:
- bTwoSided=0
-
- # mtx = ob.matrix_world * MATWORLD # mtx is now passed
- mtx = mtx * MATWORLD
-
- loc= mtx.translation_part()
- sca= mtx.scale_part()
- quat = mtx.to_quat()
- rot= quat.axis
-
- self.writeIndented('<Transform DEF="%s" translation="%.6f %.6f %.6f" scale="%.6f %.6f %.6f" rotation="%.6f %.6f %.6f %.6f">\n' % \
- (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle) )
- # self.writeIndented('<Transform DEF="%s" translation="%.6f %.6f %.6f" scale="%.6f %.6f %.6f" rotation="%.6f %.6f %.6f %.6f">\n' % \
- # (meshName, loc[0], loc[1], loc[2], sca[0], sca[1], sca[2], rot[0], rot[1], rot[2], quat.angle*DEG2RAD) )
-
- self.writeIndented("<Shape>\n",1)
- maters=mesh.materials
- hasImageTexture = False
- is_smooth = False
-
- if len(maters) > 0 or mesh.uv_textures.active:
- # if len(maters) > 0 or mesh.faceUV:
- self.writeIndented("<Appearance>\n", 1)
- # right now this script can only handle a single material per mesh.
- if len(maters) >= 1 and maters[0].use_face_texture == False:
- mat = maters[0]
- self.writeMaterial(mat, self.cleanStr(mat.name,''), world)
- if len(maters) > 1:
- print("Warning: mesh named %s has multiple materials" % meshName)
- print("Warning: only one material per object handled")
-
- if not len(maters) or maters[0].use_face_texture:
- #-- textures
- image = None
- if mesh.uv_textures.active:
- for face in mesh.uv_textures.active.data:
- if face.use_image:
- image = face.image
- if image:
- self.writeImageTexture(image)
- break
-
- if image:
- hasImageTexture = True
-
- if self.tilenode == 1:
- self.writeIndented("<TextureTransform scale=\"%s %s\" />\n" % (image.xrep, image.yrep))
- self.tilenode = 0
-
- self.writeIndented("</Appearance>\n", -1)
-
- #-- IndexedFaceSet or IndexedLineSet
-
- # user selected BOUNDS=1, SOLID=3, SHARED=4, or TEXTURE=5
- ifStyle="IndexedFaceSet"
- # look up mesh name, use it if available
- if meshME in self.meshNames:
- self.writeIndented("<%s USE=\"ME_%s\">" % (ifStyle, meshME), 1)
- self.meshNames[meshME]+=1
- else:
- if int(mesh.users) > 1:
- self.writeIndented("<%s DEF=\"ME_%s\" " % (ifStyle, meshME), 1)
- self.meshNames[meshME]=1
- else:
- self.writeIndented("<%s " % ifStyle, 1)
-
- if bTwoSided == 1:
- self.file.write("solid=\"false\" ")
- else:
- self.file.write("solid=\"true\" ")
-
- for face in mesh.faces:
- if face.use_smooth:
- is_smooth = True
- break
- if is_smooth == True:
- creaseAngle=(mesh.auto_smooth_angle)*(math.pi/180.0)
- # creaseAngle=(mesh.degr)*(math.pi/180.0)
- self.file.write("creaseAngle=\"%s\" " % (round(creaseAngle,self.cp)))
-
- #--- output textureCoordinates if UV texture used
- if mesh.uv_textures.active:
- if self.matonly == 1 and self.share == 1:
- self.writeFaceColors(mesh)
- elif hasImageTexture == True:
- self.writeTextureCoordinates(mesh)
- #--- output coordinates
- self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI)
-
- self.writingcoords = 1
- self.writingtexture = 1
- self.writingcolor = 1
- self.writeCoordinates(ob, mesh, meshName, EXPORT_TRI)
-
- #--- output textureCoordinates if UV texture used
- if mesh.uv_textures.active:
- # if mesh.faceUV:
- if hasImageTexture == True:
- self.writeTextureCoordinates(mesh)
- elif self.matonly == 1 and self.share == 1:
- self.writeFaceColors(mesh)
- #--- output vertexColors
- self.matonly = 0
- self.share = 0
-
- self.writingcoords = 0
- self.writingtexture = 0
- self.writingcolor = 0
- #--- output closing braces
- self.writeIndented("</%s>\n" % ifStyle, -1)
- self.writeIndented("</Shape>\n", -1)
- self.writeIndented("</Transform>\n", -1)
-
- if self.halonode == 1:
- self.writeIndented("</Billboard>\n", -1)
- self.halonode = 0
-
- if self.billnode == 1:
- self.writeIndented("</Billboard>\n", -1)
- self.billnode = 0
-
- if self.collnode == 1:
- self.writeIndented("</Collision>\n", -1)
- self.collnode = 0
-
- if nIFSCnt > 1:
- self.writeIndented("</Group>\n", -1)
-
- self.file.write("\n")
-
- def writeCoordinates(self, ob, mesh, meshName, EXPORT_TRI = False):
- # create vertex list and pre rotate -90 degrees X for VRML
-
- if self.writingcoords == 0:
- self.file.write('coordIndex="')
- for face in mesh.faces:
- fv = face.vertices
- # fv = face.v
-
- if len(fv)==3:
- # if len(face)==3:
- self.file.write("%i %i %i -1, " % (fv[0], fv[1], fv[2]))
- # self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index))
- else:
- if EXPORT_TRI:
- self.file.write("%i %i %i -1, " % (fv[0], fv[1], fv[2]))
- # self.file.write("%i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index))
- self.file.write("%i %i %i -1, " % (fv[0], fv[2], fv[3]))
- # self.file.write("%i %i %i -1, " % (fv[0].index, fv[2].index, fv[3].index))
- else:
- self.file.write("%i %i %i %i -1, " % (fv[0], fv[1], fv[2], fv[3]))
- # self.file.write("%i %i %i %i -1, " % (fv[0].index, fv[1].index, fv[2].index, fv[3].index))
-
- self.file.write("\">\n")
- else:
- #-- vertices
- # 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.vertices:
- self.file.write("%.6f %.6f %.6f, " % tuple(v.co))
- self.file.write("\" />")
- self.writeIndented("\n", -1)
-
- def writeTextureCoordinates(self, mesh):
- texCoordList=[]
- texIndexList=[]
- j=0
-
- for face in mesh.uv_textures.active.data:
- # for face in mesh.faces:
- # workaround, since tface.uv iteration is wrong atm
- uvs = face.uv
- # uvs = [face.uv1, face.uv2, face.uv3, face.uv4] if face.vertices[3] else [face.uv1, face.uv2, face.uv3]
-
- for uv in uvs:
- # for uv in face.uv:
- texIndexList.append(j)
- texCoordList.append(uv)
- j=j+1
- texIndexList.append(-1)
-
- if self.writingtexture == 0:
- self.file.write("\n\t\t\ttexCoordIndex=\"")
- texIndxStr=""
- for i in range(len(texIndexList)):
- texIndxStr = texIndxStr + "%d, " % texIndexList[i]
- if texIndexList[i]==-1:
- self.file.write(texIndxStr)
- texIndxStr=""
- self.file.write("\"\n\t\t\t")
- else:
- self.writeIndented("<TextureCoordinate point=\"", 1)
- for i in range(len(texCoordList)):
- self.file.write("%s %s, " % (round(texCoordList[i][0],self.tp), round(texCoordList[i][1],self.tp)))
- self.file.write("\" />")
- self.writeIndented("\n", -1)
-
- def writeFaceColors(self, mesh):
- if self.writingcolor == 0:
- self.file.write("colorPerVertex=\"false\" ")
- elif mesh.vertex_colors.active:
- # else:
- self.writeIndented("<Color color=\"", 1)
- for face in mesh.vertex_colors.active.data:
- c = face.color1
- if self.verbose > 2:
- print("Debug: face.col r=%d g=%d b=%d" % (c[0], c[1], c[2]))
- # print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b))
- aColor = self.rgbToFS(c)
- self.file.write("%s, " % aColor)
-
- # for face in mesh.faces:
- # if face.col:
- # c=face.col[0]
- # if self.verbose > 2:
- # print("Debug: face.col r=%d g=%d b=%d" % (c.r, c.g, c.b))
- # aColor = self.rgbToFS(c)
- # self.file.write("%s, " % aColor)
- self.file.write("\" />")
- self.writeIndented("\n",-1)
-
- def writeMaterial(self, mat, matName, world):
- # look up material name, use it if available
- if matName in self.matNames:
- self.writeIndented("<Material USE=\"MA_%s\" />\n" % matName)
- self.matNames[matName]+=1
- return;
-
- self.matNames[matName]=1
-
- ambient = mat.ambient/3
- # ambient = mat.amb/3
- diffuseR, diffuseG, diffuseB = tuple(mat.diffuse_color)
- # diffuseR, diffuseG, diffuseB = mat.rgbCol[0], mat.rgbCol[1],mat.rgbCol[2]
- if world:
- ambi = world.ambient_color
- # ambi = world.getAmb()
- ambi0, ambi1, ambi2 = (ambi[0]*mat.ambient)*2, (ambi[1]*mat.ambient)*2, (ambi[2]*mat.ambient)*2
- # ambi0, ambi1, ambi2 = (ambi[0]*mat.amb)*2, (ambi[1]*mat.amb)*2, (ambi[2]*mat.amb)*2
- else:
- ambi0, ambi1, ambi2 = 0, 0, 0
- emisR, emisG, emisB = (diffuseR*mat.emit+ambi0)/2, (diffuseG*mat.emit+ambi1)/2, (diffuseB*mat.emit+ambi2)/2
-
- shininess = mat.specular_hardness/512.0
- # shininess = mat.hard/512.0
- specR = (mat.specular_color[0]+0.001)/(1.25/(mat.specular_intensity+0.001))
- # specR = (mat.specCol[0]+0.001)/(1.25/(mat.spec+0.001))
- specG = (mat.specular_color[1]+0.001)/(1.25/(mat.specular_intensity+0.001))
- # specG = (mat.specCol[1]+0.001)/(1.25/(mat.spec+0.001))
- specB = (mat.specular_color[2]+0.001)/(1.25/(mat.specular_intensity+0.001))
- # specB = (mat.specCol[2]+0.001)/(1.25/(mat.spec+0.001))
- transp = 1-mat.alpha
- # matFlags = mat.getMode()
- if mat.use_shadeless:
- # if matFlags & Blender.Material.Modes['SHADELESS']:
- ambient = 1
- shine = 1
- specR = emitR = diffuseR
- specG = emitG = diffuseG
- specB = emitB = diffuseB
- self.writeIndented("<Material DEF=\"MA_%s\" " % matName, 1)
- self.file.write("diffuseColor=\"%s %s %s\" " % (round(diffuseR,self.cp), round(diffuseG,self.cp), round(diffuseB,self.cp)))
- self.file.write("specularColor=\"%s %s %s\" " % (round(specR,self.cp), round(specG,self.cp), round(specB,self.cp)))
- self.file.write("emissiveColor=\"%s %s %s\" \n" % (round(emisR,self.cp), round(emisG,self.cp), round(emisB,self.cp)))
- self.writeIndented("ambientIntensity=\"%s\" " % (round(ambient,self.cp)))
- self.file.write("shininess=\"%s\" " % (round(shininess,self.cp)))
- self.file.write("transparency=\"%s\" />" % (round(transp,self.cp)))
- self.writeIndented("\n",-1)
-
- def writeImageTexture(self, image):
- name = image.name
- filepath = os.path.basename(image.filepath)
- if name in self.texNames:
- self.writeIndented("<ImageTexture USE=\"%s\" />\n" % self.cleanStr(name))
- self.texNames[name] += 1
- else:
- self.writeIndented("<ImageTexture DEF=\"%s\" " % self.cleanStr(name), 1)
- self.file.write("url=\"%s\" />" % filepath)
- self.writeIndented("\n",-1)
- self.texNames[name] = 1
-
- def writeBackground(self, world, alltextures):
- if world: worldname = world.name
- else: return
- blending = (world.use_sky_blend, world.use_sky_paper, world.use_sky_real)
- # blending = world.getSkytype()
- grd = world.horizon_color
- # grd = world.getHor()
- grd0, grd1, grd2 = grd[0], grd[1], grd[2]
- sky = world.zenith_color
- # sky = world.getZen()
- sky0, sky1, sky2 = sky[0], sky[1], sky[2]
- mix0, mix1, mix2 = grd[0]+sky[0], grd[1]+sky[1], grd[2]+sky[2]
- mix0, mix1, mix2 = mix0/2, mix1/2, mix2/2
- self.file.write("<Background ")
- if worldname not in self.namesStandard:
- self.file.write("DEF=\"%s\" " % self.secureName(worldname))
- # No Skytype - just Hor color
- if blending == (0, 0, 0):
- # if blending == 0:
- self.file.write("groundColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
- self.file.write("skyColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
- # Blend Gradient
- elif blending == (1, 0, 0):
- # elif blending == 1:
- self.file.write("groundColor=\"%s %s %s, " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
- self.file.write("%s %s %s\" groundAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp)))
- self.file.write("skyColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
- self.file.write("%s %s %s\" skyAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp)))
- # Blend+Real Gradient Inverse
- elif blending == (1, 0, 1):
- # elif blending == 3:
- self.file.write("groundColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
- self.file.write("%s %s %s\" groundAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp)))
- self.file.write("skyColor=\"%s %s %s, " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
- self.file.write("%s %s %s\" skyAngle=\"1.57, 1.57\" " %(round(mix0,self.cp), round(mix1,self.cp), round(mix2,self.cp)))
- # Paper - just Zen Color
- elif blending == (0, 0, 1):
- # elif blending == 4:
- self.file.write("groundColor=\"%s %s %s\" " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
- self.file.write("skyColor=\"%s %s %s\" " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
- # Blend+Real+Paper - komplex gradient
- elif blending == (1, 1, 1):
- # elif blending == 7:
- self.writeIndented("groundColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
- self.writeIndented("%s %s %s\" groundAngle=\"1.57, 1.57\" " %(round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
- self.writeIndented("skyColor=\"%s %s %s, " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
- self.writeIndented("%s %s %s\" skyAngle=\"1.57, 1.57\" " %(round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
- # Any Other two colors
- else:
- self.file.write("groundColor=\"%s %s %s\" " % (round(grd0,self.cp), round(grd1,self.cp), round(grd2,self.cp)))
- self.file.write("skyColor=\"%s %s %s\" " % (round(sky0,self.cp), round(sky1,self.cp), round(sky2,self.cp)))
-
- alltexture = len(alltextures)
-
- for i in range(alltexture):
- tex = alltextures[i]
-
- if tex.type != 'IMAGE' or tex.image is None:
- continue
-
- namemat = tex.name
- # namemat = alltextures[i].name
-
- pic = tex.image
-
- # using .expandpath just in case, os.path may not expect //
- basename = os.path.basename(bpy.path.abspath(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.filepath.split('/')[-1].split('\\')[-1])
- elif (namemat == "bottom") and (pic != None):
- self.writeIndented("bottomUrl=\"%s\" " % basename)
- # 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.filepath.split('/')[-1].split('\\')[-1])
- elif (namemat == "left") and (pic != None):
- self.writeIndented("leftUrl=\"%s\" " % basename)
- # 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.filepath.split('/')[-1].split('\\')[-1])
- elif (namemat == "top") and (pic != None):
- self.writeIndented("topUrl=\"%s\" " % basename)
- # self.writeIndented("topUrl=\"%s\" " % pic.filepath.split('/')[-1].split('\\')[-1])
- self.writeIndented("/>\n\n")
-
-##########################################################
-# export routine
-##########################################################
-
- def export(self, scene, world, alltextures,\
- EXPORT_APPLY_MODIFIERS = False,\
- EXPORT_TRI= False,\
- ):
-
- print("Info: starting X3D export to %r..." % self.filepath)
- self.writeHeader()
- # self.writeScript()
- self.writeNavigationInfo(scene)
- self.writeBackground(world, alltextures)
- self.writeFog(world)
- self.proto = 0
-
-
- # # COPIED FROM OBJ EXPORTER
- # if EXPORT_APPLY_MODIFIERS:
- # temp_mesh_name = '~tmp-mesh'
-
- # # Get the container mesh. - used for applying modifiers and non mesh objects.
- # containerMesh = meshName = tempMesh = None
- # for meshName in Blender.NMesh.GetNames():
- # if meshName.startswith(temp_mesh_name):
- # tempMesh = Mesh.Get(meshName)
- # if not tempMesh.users:
- # containerMesh = tempMesh
- # if not containerMesh:
- # containerMesh = Mesh.New(temp_mesh_name)
- # --------------------------
-
-
- 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(scene, ob_main)
-
- if derived is None: continue
-
- for ob, ob_mat in derived:
- # for ob, ob_mat in BPyObject.getDerivedObjects(ob_main):
- objType=ob.type
- objName=ob.name
- self.matonly = 0
- if objType == "CAMERA":
- # if objType == "Camera":
- self.writeViewpoint(ob, ob_mat, scene)
- elif objType in ("MESH", "CURVE", "SURF", "TEXT") :
- # 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(scene, EXPORT_APPLY_MODIFIERS, 'PREVIEW')
- # me= BPyMesh.getMeshFromObject(ob, containerMesh, EXPORT_APPLY_MODIFIERS, False, scene)
- else:
- me = ob.data
- # me = ob.getData(mesh=1)
-
- self.writeIndexedFaceSet(ob, me, ob_mat, world, EXPORT_TRI = EXPORT_TRI)
-
- # free mesh created with create_mesh()
- if me != ob.data:
- bpy.data.meshes.remove(me)
-
- elif objType == "LAMP":
- # elif objType == "Lamp":
- data= ob.data
- datatype=data.type
- if datatype == 'POINT':
- # if datatype == Lamp.Types.Lamp:
- self.writePointLight(ob, ob_mat, data, world)
- elif datatype == 'SPOT':
- # elif datatype == Lamp.Types.Spot:
- self.writeSpotLight(ob, ob_mat, data, world)
- elif datatype == 'SUN':
- # elif datatype == Lamp.Types.Sun:
- self.writeDirectionalLight(ob, ob_mat, data, world)
- else:
- self.writeDirectionalLight(ob, ob_mat, data, world)
- # do you think x3d could document what to do with dummy objects?
- #elif objType == "Empty" and objName != "Empty":
- # self.writeNode(ob, ob_mat)
- else:
- #print "Info: Ignoring [%s], object type [%s] not handle yet" % (object.name,object.getType)
- pass
-
- if free:
- free_derived_objects(ob_main)
-
- self.file.write("\n</Scene>\n</X3D>")
-
- # if EXPORT_APPLY_MODIFIERS:
- # if containerMesh:
- # containerMesh.vertices = None
-
- self.cleanup()
-
-##########################################################
-# Utility methods
-##########################################################
-
- def cleanup(self):
- self.file.close()
- self.texNames={}
- self.matNames={}
- self.indentLevel=0
- print("Info: finished X3D export to %r" % self.filepath)
-
- def cleanStr(self, name, prefix='rsvd_'):
- """cleanStr(name,prefix) - try to create a valid VRML DEF name from object name"""
-
- newName=name[:]
- if len(newName) == 0:
- self.nNodeID+=1
- return "%s%d" % (prefix, self.nNodeID)
-
- if newName in self.namesReserved:
- newName='%s%s' % (prefix,newName)
-
- if newName[0].isdigit():
- newName='%s%s' % ('_',newName)
-
- for bad in [' ','"','#',"'",',','.','[','\\',']','{','}']:
- newName=newName.replace(bad,'_')
- return newName
-
- def countIFSSetsNeeded(self, mesh, imageMap, sided, vColors):
- """
- countIFFSetsNeeded() - should look at a blender mesh to determine
- how many VRML IndexFaceSets or IndexLineSets are needed. A
- new mesh created under the following conditions:
-
- o - split by UV Textures / one per mesh
- o - split by face, one sided and two sided
- o - split by smooth and flat faces
- o - split when faces only have 2 vertices * needs to be an IndexLineSet
- """
-
- imageNameMap={}
- faceMap={}
- nFaceIndx=0
-
- if mesh.uv_textures.active:
- # if mesh.faceUV:
- for face in mesh.uv_textures.active.data:
- # for face in mesh.faces
- sidename = "two" if face.use_twoside else "one"
-
- if sidename in sided:
- sided[sidename]+=1
- else:
- sided[sidename]=1
-
- image = face.image
- if image:
- faceName="%s_%s" % (face.image.name, sidename);
- try:
- imageMap[faceName].append(face)
- except:
- imageMap[faceName]=[face.image.name,sidename,face]
-
- if self.verbose > 2:
- for faceName in imageMap.keys():
- ifs=imageMap[faceName]
- print("Debug: faceName=%s image=%s, solid=%s facecnt=%d" % \
- (faceName, ifs[0], ifs[1], len(ifs)-2))
-
- return len(imageMap)
-
- def faceToString(self,face):
-
- print("Debug: face.flag=0x%x (bitflags)" % face.flag)
- if face.sel:
- print("Debug: face.sel=true")
-
- print("Debug: face.mode=0x%x (bitflags)" % face.mode)
- if face.mode & Mesh.FaceModes.TWOSIDE:
- print("Debug: face.mode twosided")
-
- print("Debug: face.transp=0x%x (enum)" % face.blend_type)
- if face.blend_type == Mesh.FaceTranspModes.SOLID:
- print("Debug: face.transp.SOLID")
-
- if face.image:
- print("Debug: face.image=%s" % face.image.name)
- print("Debug: face.materialIndex=%d" % face.materialIndex)
-
- # XXX not used
- # def getVertexColorByIndx(self, mesh, indx):
- # c = None
- # for face in mesh.faces:
- # j=0
- # for vertex in face.v:
- # if vertex.index == indx:
- # c=face.col[j]
- # break
- # j=j+1
- # if c: break
- # return c
-
- def meshToString(self,mesh):
- # print("Debug: mesh.hasVertexUV=%d" % mesh.vertexColors)
- print("Debug: mesh.faceUV=%d" % (len(mesh.uv_textures) > 0))
- # print("Debug: mesh.faceUV=%d" % mesh.faceUV)
- print("Debug: mesh.hasVertexColours=%d" % (len(mesh.vertex_colors) > 0))
- # print("Debug: mesh.hasVertexColours=%d" % mesh.hasVertexColours())
- print("Debug: mesh.vertices=%d" % len(mesh.vertices))
- print("Debug: mesh.faces=%d" % len(mesh.faces))
- print("Debug: mesh.materials=%d" % len(mesh.materials))
-
- def rgbToFS(self, c):
- s="%s %s %s" % (round(c[0]/255.0,self.cp),
- round(c[1]/255.0,self.cp),
- round(c[2]/255.0,self.cp))
-
- # s="%s %s %s" % (
- # round(c.r/255.0,self.cp),
- # round(c.g/255.0,self.cp),
- # round(c.b/255.0,self.cp))
- return s
-
- def computeDirection(self, mtx):
- x,y,z=(0,-1.0,0) # point down
-
- ax,ay,az = (mtx*MATWORLD).to_euler()
-
- # ax *= DEG2RAD
- # ay *= DEG2RAD
- # az *= DEG2RAD
-
- # rot X
- x1=x
- y1=y*math.cos(ax)-z*math.sin(ax)
- z1=y*math.sin(ax)+z*math.cos(ax)
-
- # rot Y
- x2=x1*math.cos(ay)+z1*math.sin(ay)
- y2=y1
- z2=z1*math.cos(ay)-x1*math.sin(ay)
-
- # rot Z
- x3=x2*math.cos(az)-y2*math.sin(az)
- y3=x2*math.sin(az)+y2*math.cos(az)
- z3=z2
-
- return [x3,y3,z3]
-
-
- # swap Y and Z to handle axis difference between Blender and VRML
- #------------------------------------------------------------------------
- def rotatePointForVRML(self, v):
- x = v[0]
- y = v[2]
- z = -v[1]
-
- vrmlPoint=[x, y, z]
- return vrmlPoint
-
- # For writing well formed VRML code
- #------------------------------------------------------------------------
- def writeIndented(self, s, inc=0):
- if inc < 1:
- self.indentLevel = self.indentLevel + inc
-
- spaces=""
- for x in range(self.indentLevel):
- spaces = spaces + "\t"
- self.file.write(spaces + s)
-
- if inc > 0:
- self.indentLevel = self.indentLevel + inc
-
- # Converts a Euler to three new Quaternions
- # Angles of Euler are passed in as radians
- #------------------------------------------------------------------------
- def eulerToQuaternions(self, x, y, z):
- Qx = [math.cos(x/2), math.sin(x/2), 0, 0]
- Qy = [math.cos(y/2), 0, math.sin(y/2), 0]
- Qz = [math.cos(z/2), 0, 0, math.sin(z/2)]
-
- quaternionVec=[Qx,Qy,Qz]
- return quaternionVec
-
- # Multiply two Quaternions together to get a new Quaternion
- #------------------------------------------------------------------------
- def multiplyQuaternions(self, Q1, Q2):
- result = [((Q1[0] * Q2[0]) - (Q1[1] * Q2[1]) - (Q1[2] * Q2[2]) - (Q1[3] * Q2[3])),
- ((Q1[0] * Q2[1]) + (Q1[1] * Q2[0]) + (Q1[2] * Q2[3]) - (Q1[3] * Q2[2])),
- ((Q1[0] * Q2[2]) + (Q1[2] * Q2[0]) + (Q1[3] * Q2[1]) - (Q1[1] * Q2[3])),
- ((Q1[0] * Q2[3]) + (Q1[3] * Q2[0]) + (Q1[1] * Q2[2]) - (Q1[2] * Q2[1]))]
-
- return result
-
- # Convert a Quaternion to an Angle Axis (ax, ay, az, angle)
- # angle is in radians
- #------------------------------------------------------------------------
- def quaternionToAngleAxis(self, Qf):
- scale = math.pow(Qf[1],2) + math.pow(Qf[2],2) + math.pow(Qf[3],2)
- ax = Qf[1]
- ay = Qf[2]
- az = Qf[3]
-
- if scale > .0001:
- ax/=scale
- ay/=scale
- az/=scale
-
- angle = 2 * math.acos(Qf[0])
-
- result = [ax, ay, az, angle]
- return result
-
-##########################################################
-# Callbacks, needed before Main
-##########################################################
-
-def save(operator, context, filepath="",
- use_apply_modifiers=False,
- use_triangulate=False,
- use_compress=False):
-
- if use_compress:
- if not filepath.lower().endswith('.x3dz'):
- filepath = '.'.join(filepath.split('.')[:-1]) + '.x3dz'
- else:
- if not filepath.lower().endswith('.x3d'):
- filepath = '.'.join(filepath.split('.')[:-1]) + '.x3d'
-
- scene = context.scene
- world = scene.world
-
- if bpy.ops.object.mode_set.poll():
- bpy.ops.object.mode_set(mode='OBJECT')
-
- # XXX these are global textures while .Get() returned only scene's?
- alltextures = bpy.data.textures
- # alltextures = Blender.Texture.Get()
-
- wrlexport = x3d_class(filepath)
- wrlexport.export(scene,
- world,
- alltextures,
- EXPORT_APPLY_MODIFIERS=use_apply_modifiers,
- EXPORT_TRI=use_triangulate,
- )
-
- return {'FINISHED'}
-
diff --git a/release/scripts/op/io_shape_mdd/__init__.py b/release/scripts/op/io_shape_mdd/__init__.py
deleted file mode 100644
index 6453d70f569..00000000000
--- a/release/scripts/op/io_shape_mdd/__init__.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# ##### 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>
-
-# To support reload properly, try to access a package var, if it's there, reload everything
-if "bpy" in locals():
- # only reload if we alredy loaded, highly annoying
- import sys
- reload(sys.modules.get("io_shape_mdd.import_mdd", sys))
- reload(sys.modules.get("io_shape_mdd.export_mdd", sys))
-
-
-import bpy
-from bpy.props import *
-from io_utils import ExportHelper, ImportHelper
-
-
-class ImportMDD(bpy.types.Operator, ImportHelper):
- '''Import MDD vertex keyframe file to shape keys'''
- bl_idname = "import_shape.mdd"
- bl_label = "Import MDD"
-
- filename_ext = ".mdd"
- filter_glob = StringProperty(default="*.mdd", options={'HIDDEN'})
-
- frame_start = IntProperty(name="Start Frame", description="Start frame for inserting animation", min=-300000, max=300000, default=0)
- frame_step = IntProperty(name="Step", min=1, max=1000, default=1)
-
- @classmethod
- def poll(cls, context):
- ob = context.active_object
- return (ob and ob.type == 'MESH')
-
- def execute(self, context):
-
- # initialize from scene if unset
- scene = context.scene
- if not self.frame_start:
- self.frame_start = scene.frame_current
-
- import io_shape_mdd.import_mdd
- return io_shape_mdd.import_mdd.load(self, context, **self.properties)
-
-class ExportMDD(bpy.types.Operator, ExportHelper):
- '''Animated mesh to MDD vertex keyframe file'''
- bl_idname = "export_shape.mdd"
- bl_label = "Export MDD"
-
- filename_ext = ".mdd"
-
- # get first scene to get min and max properties for frames, fps
-
- minframe = 1
- maxframe = 300000
- minfps = 1
- maxfps = 120
-
- # List of operator properties, the attributes will be assigned
- # to the class instance from the operator settings before calling.
- fps = IntProperty(name="Frames Per Second", description="Number of frames/second", min=minfps, max=maxfps, default=25)
- 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)
-
- @classmethod
- def poll(cls, context):
- obj = context.active_object
- return (obj and obj.type == 'MESH')
-
- def execute(self, context):
- # initialize from scene if unset
- scene = context.scene
- if not self.frame_start:
- self.frame_start = scene.frame_start
- if not self.frame_end:
- self.frame_end = scene.frame_end
- if not self.fps:
- self.fps = scene.render.fps
-
- import io_shape_mdd.export_mdd
- return io_shape_mdd.export_mdd.save(self, context, **self.properties)
-
-
-def menu_func_import(self, context):
- self.layout.operator(ImportMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
-
-
-def menu_func_export(self, context):
- self.layout.operator(ExportMDD.bl_idname, text="Lightwave Point Cache (.mdd)")
-
-
-def register():
- bpy.types.INFO_MT_file_import.append(menu_func_import)
- bpy.types.INFO_MT_file_export.append(menu_func_export)
-
-
-def unregister():
- bpy.types.INFO_MT_file_import.remove(menu_func_import)
- bpy.types.INFO_MT_file_export.remove(menu_func_export)
-
-if __name__ == "__main__":
- register()
diff --git a/release/scripts/op/io_shape_mdd/export_mdd.py b/release/scripts/op/io_shape_mdd/export_mdd.py
deleted file mode 100644
index 3c57ae5afa0..00000000000
--- a/release/scripts/op/io_shape_mdd/export_mdd.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# ##### 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>
-
-# Contributors: Bill L.Nieuwendorp
-
-"""
-This script Exports Lightwaves MotionDesigner format.
-
-The .mdd format has become quite a popular Pipeline format<br>
-for moving animations from package to package.
-
-Be sure not to use modifiers that change the number or order of verts in the mesh
-"""
-
-import bpy
-import mathutils
-from struct import pack
-
-
-def zero_file(filepath):
- '''
- If a file fails, this replaces it with 1 char, better not remove it?
- '''
- file = open(filepath, 'w')
- file.write('\n') # apparently macosx needs some data in a blank file?
- file.close()
-
-
-def check_vertcount(mesh, vertcount):
- '''
- check and make sure the vertcount is consistent throughout the frame range
- '''
- if len(mesh.vertices) != vertcount:
- raise Exception('Error, number of verts has changed during animation, cannot export')
- f.close()
- zero_file(filepath)
- return
-
-
-def save(operator, context, filepath="", frame_start=1, frame_end=300, fps=25):
- """
- Blender.Window.WaitCursor(1)
-
- mesh_orig = Mesh.New()
- mesh_orig.getFromObject(obj.name)
- """
-
- scene = context.scene
- obj = context.object
-
- if bpy.ops.object.mode_set.poll():
- bpy.ops.object.mode_set(mode='OBJECT')
-
- orig_frame = scene.frame_current
- scene.frame_set(frame_start)
- me = obj.create_mesh(scene, True, 'PREVIEW')
-
- #Flip y and z
- 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],\
- [0.0, 0.0, 0.0, 1.0],\
- )
-
- numverts = len(me.vertices)
-
- numframes = frame_end - frame_start + 1
- fps = float(fps)
- f = open(filepath, 'wb') #no Errors yet:Safe to create file
-
- # Write the header
- f.write(pack(">2i", numframes, numverts))
-
- # Write the frame times (should we use the time IPO??)
- f.write(pack(">%df" % (numframes), *[frame / fps for frame in range(numframes)])) # seconds
-
- #rest frame needed to keep frames in sync
- """
- Blender.Set('curframe', frame_start)
- me_tmp.getFromObject(obj.name)
- """
-
- check_vertcount(me, numverts)
- me.transform(mat_flip * obj.matrix_world)
- f.write(pack(">%df" % (numverts * 3), *[axis for v in me.vertices for axis in v.co]))
-
- for frame in range(frame_start, frame_end + 1):#in order to start at desired frame
- """
- Blender.Set('curframe', frame)
- me_tmp.getFromObject(obj.name)
- """
-
- scene.frame_set(frame)
- me = obj.create_mesh(scene, True, 'PREVIEW')
- check_vertcount(me, numverts)
- me.transform(mat_flip * obj.matrix_world)
-
- # Write the vertex data
- f.write(pack(">%df" % (numverts * 3), *[axis for v in me.vertices for axis in v.co]))
-
- """
- me_tmp.vertices= None
- """
- f.close()
-
- print('MDD Exported: %r frames:%d\n' % (filepath, numframes - 1))
- """
- Blender.Window.WaitCursor(0)
- Blender.Set('curframe', orig_frame)
- """
- scene.frame_set(orig_frame)
-
- return {'FINISHED'}
diff --git a/release/scripts/op/io_shape_mdd/import_mdd.py b/release/scripts/op/io_shape_mdd/import_mdd.py
deleted file mode 100644
index d008ff931ff..00000000000
--- a/release/scripts/op/io_shape_mdd/import_mdd.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# ##### 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>
-
-# mdd importer by Bill L.Nieuwendorp
-# conversion to blender 2.5: Ivo Grigull (loolarge)
-#
-# Warning if the vertex order or vertex count differs from the
-# 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
-# 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
-# Bill Niewuendorp
-
-import bpy
-from struct import unpack
-
-
-def load(operator, context, filepath, frame_start=0, frame_step=1):
-
- scene = context.scene
- obj = context.object
-
- print('\n\nimporting mdd %r' % filepath)
-
- if bpy.ops.object.mode_set.poll():
- 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))
-
- # If target object doesn't have Basis shape key, create it.
- try:
- num_keys = len(obj.data.shape_keys.keys)
- except:
- basis = obj.add_shape_key()
- basis.name = "Basis"
- obj.data.update()
-
- scene.frame_current = frame_start
-
- def UpdateMesh(ob, fr):
-
- # Insert new shape key
- new_shapekey = obj.add_shape_key()
- new_shapekey.name = ("frame_%.4d" % fr)
- new_shapekey_name = new_shapekey.name
-
- obj.active_shape_key_index = len(obj.data.shape_keys.keys)-1
- index = len(obj.data.shape_keys.keys)-1
- obj.show_shape_key = True
-
- verts = obj.data.shape_keys.keys[len(obj.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()
- obj.show_shape_key = False
-
-
- # insert keyframes
- shape_keys = obj.data.shape_keys
-
- scene.frame_current -= 1
- obj.data.shape_keys.keys[index].value = 0.0
- shape_keys.keys[len(obj.data.shape_keys.keys)-1].keyframe_insert("value")
-
- scene.frame_current += 1
- obj.data.shape_keys.keys[index].value = 1.0
- shape_keys.keys[len(obj.data.shape_keys.keys)-1].keyframe_insert("value")
-
- scene.frame_current += 1
- obj.data.shape_keys.keys[index].value = 0.0
- shape_keys.keys[len(obj.data.shape_keys.keys)-1].keyframe_insert("value")
-
- obj.data.update()
-
-
- for i in range(frames):
- UpdateMesh(obj, i)
-
- return {'FINISHED'}
diff --git a/release/scripts/op/mesh.py b/release/scripts/op/mesh.py
index c2af9ba4da7..4906fd7fc6c 100644
--- a/release/scripts/op/mesh.py
+++ b/release/scripts/op/mesh.py
@@ -35,14 +35,14 @@ class MeshSelectInteriorFaces(bpy.types.Operator):
def execute(self, context):
ob = context.active_object
- bpy.ops.mesh.selection_type(type='FACE')
+ context.tool_settings.mesh_select_mode = False, False, True
is_editmode = (ob.mode == 'EDIT')
if is_editmode:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh = ob.data
- face_list = [face for face in mesh.faces]
+ face_list = mesh.faces[:]
face_edge_keys = [face.edge_keys for face in face_list]
edge_face_count = mesh.edge_face_count_dict
@@ -173,11 +173,11 @@ class MeshMirrorUV(bpy.types.Operator):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/nla.py b/release/scripts/op/nla.py
index a91c84999fa..5711fdf12e5 100644
--- a/release/scripts/op/nla.py
+++ b/release/scripts/op/nla.py
@@ -40,14 +40,14 @@ def pose_info():
binfo["pbone"] = pbone
binfo["matrix_local"] = bone.matrix_local.copy()
try:
- binfo["matrix_local_inv"] = binfo["matrix_local"].copy().invert()
+ binfo["matrix_local_inv"] = binfo["matrix_local"].inverted()
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()
+ binfo["matrix_pose_inv"] = binfo["matrix_pose"].inverted()
except:
binfo["matrix_pose_inv"] = Matrix()
@@ -67,7 +67,7 @@ def pose_info():
matrix = binfo_parent["matrix_pose_inv"] * matrix
rest_matrix = binfo_parent["matrix_local_inv"] * rest_matrix
- matrix = rest_matrix.copy().invert() * matrix
+ matrix = rest_matrix.inverted() * matrix
binfo["matrix_key"] = matrix.copy()
@@ -75,8 +75,6 @@ def pose_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
@@ -106,9 +104,9 @@ def bake(frame_start, frame_end, step=1, only_selected=False):
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.location = matrix.to_translation()
+ #pbone.rotation_quaternion = matrix.to_quaternion()
+ pbone.matrix_basis = matrix
pbone.keyframe_insert("location", -1, f, name)
@@ -149,7 +147,7 @@ class BakeAction(bpy.types.Operator):
def execute(self, context):
- action = bake(self.frame_start, self.frame_end, self.step, self.show_only_selected)
+ action = bake(self.frame_start, self.frame_end, self.step, self.only_selected)
# basic cleanup, could move elsewhere
for fcu in action.fcurves:
@@ -177,13 +175,11 @@ class BakeAction(bpy.types.Operator):
def register():
- pass
- # bpy.types.INFO_MT_mesh_add.append(menu_func)
+ bpy.utils.register_module(__name__)
def unregister():
- pass
- # bpy.types.INFO_MT_mesh_add.remove(menu_func)
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/object.py b/release/scripts/op/object.py
index 61a4478c5e4..92886689972 100644
--- a/release/scripts/op/object.py
+++ b/release/scripts/op/object.py
@@ -60,9 +60,7 @@ class SelectPattern(bpy.types.Operator):
def invoke(self, context, event):
wm = context.window_manager
- # return wm.invoke_props_popup(self, event)
- wm.invoke_props_popup(self, event)
- return {'RUNNING_MODAL'}
+ return wm.invoke_props_popup(self, event)
def draw(self, context):
layout = self.layout
@@ -209,9 +207,12 @@ class SubdivisionSet(bpy.types.Operator):
return
- # adda new modifier
- mod = obj.modifiers.new("Subsurf", 'SUBSURF')
- mod.levels = level
+ # add a new modifier
+ try:
+ mod = obj.modifiers.new("Subsurf", 'SUBSURF')
+ mod.levels = level
+ except:
+ self.report({'WARNING'}, "Modifiers cannot be added to object: " + obj.name)
for obj in context.selected_editable_objects:
set_object_subd(obj)
@@ -248,15 +249,15 @@ class ShapeTransfer(bpy.types.Operator):
def ob_add_shape(ob, name):
me = ob.data
- key = ob.add_shape_key(from_mix=False)
+ key = ob.shape_key_add(from_mix=False)
if len(me.shape_keys.keys) == 1:
key.name = "Basis"
- key = ob.add_shape_key(from_mix=False) # we need a rest
+ key = ob.shape_key_add(from_mix=False) # we need a rest
key.name = name
ob.active_shape_key_index = len(me.shape_keys.keys) - 1
- ob.show_shape_key = True
+ ob.show_only_shape_key = True
- from geometry import BarycentricTransform
+ from mathutils.geometry import barycentric_transform
from mathutils import Vector
if use_clamp and mode == 'OFFSET':
@@ -299,38 +300,38 @@ class ShapeTransfer(bpy.types.Operator):
for face in me.faces:
i1, i2, i3, i4 = face.vertices_raw
if i4 != 0:
- pt = BarycentricTransform(orig_shape_coords[i1],
+ pt = barycentric_transform(orig_shape_coords[i1],
orig_coords[i4], orig_coords[i1], orig_coords[i2],
target_coords[i4], target_coords[i1], target_coords[i2])
median_coords[i1].append(pt)
- pt = BarycentricTransform(orig_shape_coords[i2],
+ pt = barycentric_transform(orig_shape_coords[i2],
orig_coords[i1], orig_coords[i2], orig_coords[i3],
target_coords[i1], target_coords[i2], target_coords[i3])
median_coords[i2].append(pt)
- pt = BarycentricTransform(orig_shape_coords[i3],
+ pt = barycentric_transform(orig_shape_coords[i3],
orig_coords[i2], orig_coords[i3], orig_coords[i4],
target_coords[i2], target_coords[i3], target_coords[i4])
median_coords[i3].append(pt)
- pt = BarycentricTransform(orig_shape_coords[i4],
+ pt = barycentric_transform(orig_shape_coords[i4],
orig_coords[i3], orig_coords[i4], orig_coords[i1],
target_coords[i3], target_coords[i4], target_coords[i1])
median_coords[i4].append(pt)
else:
- pt = BarycentricTransform(orig_shape_coords[i1],
+ pt = barycentric_transform(orig_shape_coords[i1],
orig_coords[i3], orig_coords[i1], orig_coords[i2],
target_coords[i3], target_coords[i1], target_coords[i2])
median_coords[i1].append(pt)
- pt = BarycentricTransform(orig_shape_coords[i2],
+ pt = barycentric_transform(orig_shape_coords[i2],
orig_coords[i1], orig_coords[i2], orig_coords[i3],
target_coords[i1], target_coords[i2], target_coords[i3])
median_coords[i2].append(pt)
- pt = BarycentricTransform(orig_shape_coords[i3],
+ pt = barycentric_transform(orig_shape_coords[i3],
orig_coords[i2], orig_coords[i3], orig_coords[i1],
target_coords[i2], target_coords[i3], target_coords[i1])
median_coords[i3].append(pt)
@@ -349,12 +350,12 @@ class ShapeTransfer(bpy.types.Operator):
n1loc_to = v1_to + target_normals[i1] * edlen_to
n2loc_to = v2_to + target_normals[i2] * edlen_to
- pt = BarycentricTransform(orig_shape_coords[i1],
+ pt = barycentric_transform(orig_shape_coords[i1],
v2, v1, n1loc,
v2_to, v1_to, n1loc_to)
median_coords[i1].append(pt)
- pt = BarycentricTransform(orig_shape_coords[i2],
+ pt = barycentric_transform(orig_shape_coords[i2],
v1, v2, n2loc,
v1_to, v2_to, n2loc_to)
median_coords[i2].append(pt)
@@ -466,7 +467,7 @@ class JoinUVs(bpy.types.Operator):
class MakeDupliFace(bpy.types.Operator):
'''Make linked objects into dupli-faces'''
bl_idname = "object.make_dupli_face"
- bl_label = "Make DupliFace"
+ bl_label = "Make Dupli-Face"
@classmethod
def poll(cls, context):
@@ -483,10 +484,10 @@ class MakeDupliFace(bpy.types.Operator):
def matrix_to_quat(matrix):
# scale = matrix.median_scale
- trans = matrix.translation_part()
- rot = matrix.rotation_part() # also contains scale
+ trans = matrix.to_translation()
+ rot = matrix.to_3x3() # also contains scale
- return [(rot * b) + trans for b in base_tri]
+ return [(b * rot) + trans for b in base_tri]
scene = bpy.context.scene
linked = {}
for obj in bpy.context.selected_objects:
@@ -551,7 +552,6 @@ class IsolateTypeRender(bpy.types.Operator):
return {'FINISHED'}
-
class ClearAllRestrictRender(bpy.types.Operator):
'''Reveal all render objects by setting the hide render flag'''
bl_idname = "object.hide_render_clear_all"
@@ -565,11 +565,11 @@ class ClearAllRestrictRender(bpy.types.Operator):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/object_align.py b/release/scripts/op/object_align.py
index 359ffa9aabe..d98fe584c1a 100644
--- a/release/scripts/op/object_align.py
+++ b/release/scripts/op/object_align.py
@@ -26,206 +26,208 @@ 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 = [0.0, 0.0, 0.0]
+ Right_Down_Back_SEL = [0.0, 0.0, 0.0]
flag_first = True
+ objs = []
+
for obj in bpy.context.selected_objects:
- if obj.type == 'MESH':
+ matrix_world = obj.matrix_world
+ bb_world = [Vector(v[:]) * matrix_world for v in obj.bound_box]
+ objs.append((obj, bb_world))
+
+ if not objs:
+ return False
+
+ for obj, bb_world in objs:
+ Left_Up_Front = bb_world[1]
+ Right_Down_Back = bb_world[7]
- bb_world = [obj.matrix_world * Vector(v[:]) for v in obj.bound_box]
+ # Active Center
- Left_Up_Front = bb_world[1]
- Right_Down_Back = bb_world[7]
+ if obj == bpy.context.active_object:
- # Active Center
+ center_active_x = (Left_Up_Front[0] + Right_Down_Back[0]) / 2.0
+ center_active_y = (Left_Up_Front[1] + Right_Down_Back[1]) / 2.0
+ center_active_z = (Left_Up_Front[2] + Right_Down_Back[2]) / 2.0
- if obj == bpy.context.active_object:
+ size_active_x = (Right_Down_Back[0] - Left_Up_Front[0]) / 2.0
+ size_active_y = (Right_Down_Back[1] - Left_Up_Front[1]) / 2.0
+ size_active_z = (Left_Up_Front[2] - Right_Down_Back[2]) / 2.0
- 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
+ # Selection Center
- 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
+ if flag_first:
+ flag_first = False
- # Selection Center
+ Left_Up_Front_SEL[0] = Left_Up_Front[0]
+ Left_Up_Front_SEL[1] = Left_Up_Front[1]
+ Left_Up_Front_SEL[2] = Left_Up_Front[2]
- if flag_first:
- flag_first = False
+ Right_Down_Back_SEL[0] = Right_Down_Back[0]
+ Right_Down_Back_SEL[1] = Right_Down_Back[1]
+ Right_Down_Back_SEL[2] = Right_Down_Back[2]
+ else:
+ # X axis
+ if Left_Up_Front[0] < Left_Up_Front_SEL[0]:
Left_Up_Front_SEL[0] = Left_Up_Front[0]
+ # Y axis
+ if Left_Up_Front[1] < Left_Up_Front_SEL[1]:
Left_Up_Front_SEL[1] = Left_Up_Front[1]
+ # Z axis
+ if Left_Up_Front[2] > Left_Up_Front_SEL[2]:
Left_Up_Front_SEL[2] = Left_Up_Front[2]
+ # X axis
+ if Right_Down_Back[0] > Right_Down_Back_SEL[0]:
Right_Down_Back_SEL[0] = Right_Down_Back[0]
+ # Y axis
+ if Right_Down_Back[1] > Right_Down_Back_SEL[1]:
Right_Down_Back_SEL[1] = Right_Down_Back[1]
+ # Z axis
+ if Right_Down_Back[2] < Right_Down_Back_SEL[2]:
Right_Down_Back_SEL[2] = Right_Down_Back[2]
- else:
- # X axis
- if Left_Up_Front[0] < Left_Up_Front_SEL[0]:
- Left_Up_Front_SEL[0] = Left_Up_Front[0]
- # Y axis
- if Left_Up_Front[1] < Left_Up_Front_SEL[1]:
- Left_Up_Front_SEL[1] = Left_Up_Front[1]
- # Z axis
- if Left_Up_Front[2] > Left_Up_Front_SEL[2]:
- Left_Up_Front_SEL[2] = Left_Up_Front[2]
-
- # X axis
- if Right_Down_Back[0] > Right_Down_Back_SEL[0]:
- Right_Down_Back_SEL[0] = Right_Down_Back[0]
- # Y axis
- if Right_Down_Back[1] > Right_Down_Back_SEL[1]:
- Right_Down_Back_SEL[1] = Right_Down_Back[1]
- # Z axis
- 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.0
+ center_sel_y = (Left_Up_Front_SEL[1] + Right_Down_Back_SEL[1]) / 2.0
+ center_sel_z = (Left_Up_Front_SEL[2] + Right_Down_Back_SEL[2]) / 2.0
# Main Loop
- for obj in bpy.context.selected_objects:
- if obj.type == 'MESH':
-
- loc_world = obj.location
- 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]
+ for obj, bb_world in objs:
- 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
+ loc_world = obj.location
+ bb_world = [Vector(v[:]) * obj.matrix_world for v in obj.bound_box]
- positive_x = Right_Down_Back[0]
- positive_y = Right_Down_Back[1]
- positive_z = Left_Up_Front[2]
+ Left_Up_Front = bb_world[1]
+ Right_Down_Back = bb_world[7]
- negative_x = Left_Up_Front[0]
- negative_y = Left_Up_Front[1]
- negative_z = Right_Down_Back[2]
+ center_x = (Left_Up_Front[0] + Right_Down_Back[0]) / 2.0
+ center_y = (Left_Up_Front[1] + Right_Down_Back[1]) / 2.0
+ center_z = (Left_Up_Front[2] + Right_Down_Back[2]) / 2.0
- obj_loc = obj.location
+ positive_x = Right_Down_Back[0]
+ positive_y = Right_Down_Back[1]
+ positive_z = Left_Up_Front[2]
- if align_x:
+ negative_x = Left_Up_Front[0]
+ negative_y = Left_Up_Front[1]
+ negative_z = Right_Down_Back[2]
- # Align Mode
+ obj_loc = obj.location
- if relative_to == 'OPT_4': # Active relative
- if align_mode == 'OPT_1':
- obj_x = obj_loc[0] - negative_x - size_active_x
+ if align_x:
- elif align_mode == 'OPT_3':
- obj_x = obj_loc[0] - positive_x + size_active_x
+ # Align Mode
- else: # Everything else relative
- if align_mode == 'OPT_1':
- obj_x = obj_loc[0] - negative_x
+ if relative_to == 'OPT_4': # Active relative
+ if align_mode == 'OPT_1':
+ obj_x = obj_loc[0] - negative_x - size_active_x
- elif align_mode == 'OPT_3':
- obj_x = obj_loc[0] - positive_x
+ elif align_mode == 'OPT_3':
+ obj_x = obj_loc[0] - positive_x + size_active_x
- if align_mode == 'OPT_2': # All relative
- obj_x = obj_loc[0] - center_x
+ else: # Everything else relative
+ if align_mode == 'OPT_1':
+ obj_x = obj_loc[0] - negative_x
- # Relative To
+ elif align_mode == 'OPT_3':
+ obj_x = obj_loc[0] - positive_x
- if relative_to == 'OPT_1':
- loc_x = obj_x
+ if align_mode == 'OPT_2': # All relative
+ obj_x = obj_loc[0] - center_x
- elif relative_to == 'OPT_2':
- loc_x = obj_x + cursor[0]
+ # Relative To
- elif relative_to == 'OPT_3':
- loc_x = obj_x + center_sel_x
+ if relative_to == 'OPT_1':
+ loc_x = obj_x
- elif relative_to == 'OPT_4':
- loc_x = obj_x + center_active_x
+ elif relative_to == 'OPT_2':
+ loc_x = obj_x + cursor[0]
- obj.location[0] = loc_x
+ elif relative_to == 'OPT_3':
+ loc_x = obj_x + center_sel_x
+ elif relative_to == 'OPT_4':
+ loc_x = obj_x + center_active_x
- if align_y:
+ obj.location[0] = loc_x
- # Align Mode
+ if align_y:
+ # Align Mode
- if relative_to == 'OPT_4': # Active relative
- if align_mode == 'OPT_1':
- obj_y = obj_loc[1] - negative_y - size_active_y
+ if relative_to == 'OPT_4': # Active relative
+ if align_mode == 'OPT_1':
+ obj_y = obj_loc[1] - negative_y - size_active_y
- elif align_mode == 'OPT_3':
- obj_y = obj_loc[1] - positive_y + size_active_y
+ elif align_mode == 'OPT_3':
+ obj_y = obj_loc[1] - positive_y + size_active_y
- else: # Everything else relative
- if align_mode == 'OPT_1':
- obj_y = obj_loc[1] - negative_y
+ else: # Everything else relative
+ if align_mode == 'OPT_1':
+ obj_y = obj_loc[1] - negative_y
- elif align_mode == 'OPT_3':
- obj_y = obj_loc[1] - positive_y
+ elif align_mode == 'OPT_3':
+ obj_y = obj_loc[1] - positive_y
- if align_mode == 'OPT_2': # All relative
- obj_y = obj_loc[1] - center_y
+ if align_mode == 'OPT_2': # All relative
+ obj_y = obj_loc[1] - center_y
- # Relative To
+ # Relative To
- if relative_to == 'OPT_1':
- loc_y = obj_y
+ if relative_to == 'OPT_1':
+ loc_y = obj_y
- elif relative_to == 'OPT_2':
- loc_y = obj_y + cursor[1]
+ elif relative_to == 'OPT_2':
+ loc_y = obj_y + cursor[1]
- elif relative_to == 'OPT_3':
- loc_y = obj_y + center_sel_y
+ elif relative_to == 'OPT_3':
+ loc_y = obj_y + center_sel_y
- elif relative_to == 'OPT_4':
- loc_y = obj_y + center_active_y
+ elif relative_to == 'OPT_4':
+ loc_y = obj_y + center_active_y
- obj.location[1] = loc_y
+ obj.location[1] = loc_y
+ if align_z:
+ # Align Mode
+ if relative_to == 'OPT_4': # Active relative
+ if align_mode == 'OPT_1':
+ obj_z = obj_loc[2] - negative_z - size_active_z
- if align_z:
+ elif align_mode == 'OPT_3':
+ obj_z = obj_loc[2] - positive_z + size_active_z
- # Align Mode
+ else: # Everything else relative
+ if align_mode == 'OPT_1':
+ obj_z = obj_loc[2] - negative_z
- if relative_to == 'OPT_4': # Active relative
- if align_mode == 'OPT_1':
- obj_z = obj_loc[2] - negative_z - size_active_z
+ elif align_mode == 'OPT_3':
+ obj_z = obj_loc[2] - positive_z
- elif align_mode == 'OPT_3':
- obj_z = obj_loc[2] - positive_z + size_active_z
+ if align_mode == 'OPT_2': # All relative
+ obj_z = obj_loc[2] - center_z
- else: # Everything else relative
- if align_mode == 'OPT_1':
- obj_z = obj_loc[2] - negative_z
+ # Relative To
- elif align_mode == 'OPT_3':
- obj_z = obj_loc[2] - positive_z
+ if relative_to == 'OPT_1':
+ loc_z = obj_z
- if align_mode == 'OPT_2': # All relative
- obj_z = obj_loc[2] - center_z
+ elif relative_to == 'OPT_2':
+ loc_z = obj_z + cursor[2]
- # Relative To
+ elif relative_to == 'OPT_3':
+ loc_z = obj_z + center_sel_z
- if relative_to == 'OPT_1':
- loc_z = obj_z
+ elif relative_to == 'OPT_4':
+ loc_z = obj_z + center_active_z
- elif relative_to == 'OPT_2':
- loc_z = obj_z + cursor[2]
+ obj.location[2] = loc_z
- elif relative_to == 'OPT_3':
- loc_z = obj_z + center_sel_z
-
- elif relative_to == 'OPT_4':
- loc_z = obj_z + center_active_z
-
- obj.location[2] = loc_z
+ return True
from bpy.props import *
@@ -254,23 +256,28 @@ class AlignObjects(bpy.types.Operator):
description="",
default='OPT_4')
- align_x = BoolProperty(name="Align X",
- description="Align in the X axis", default=False)
-
- align_y = BoolProperty(name="Align Y",
- description="Align in the Y axis", default=False)
-
- align_z = BoolProperty(name="Align Z",
- description="Align in the Z axis", default=False)
+ align_axis = EnumProperty(items=(
+ ('X', "X", ""),
+ ('Y', "Y", ""),
+ ('Z', "Z", ""),
+ ),
+ name="Align",
+ description="Align to axis",
+ options={'ENUM_FLAG'})
@classmethod
def poll(cls, context):
return context.mode == 'OBJECT'
def execute(self, context):
- align_objects(self.align_x, self.align_y, self.align_z, self.align_mode, self.relative_to)
+ align_axis = self.align_axis
+ ret = align_objects('X' in align_axis, 'Y' in align_axis, 'Z' in align_axis, self.align_mode, self.relative_to)
- return {'FINISHED'}
+ if not ret:
+ self.report({'WARNING'}, "No objects with bound-box selected")
+ return {'CANCELLED'}
+ else:
+ return {'FINISHED'}
def menu_func(self, context):
@@ -280,11 +287,14 @@ def menu_func(self, context):
def register():
+ bpy.utils.register_module(__name__)
bpy.types.VIEW3D_MT_transform.append(menu_func)
def unregister():
+ bpy.utils.unregister_module(__name__)
bpy.types.VIEW3D_MT_transform.remove(menu_func)
+
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/object_randomize_transform.py b/release/scripts/op/object_randomize_transform.py
index f60f25242c7..ee7a5f98b91 100644
--- a/release/scripts/op/object_randomize_transform.py
+++ b/release/scripts/op/object_randomize_transform.py
@@ -21,7 +21,7 @@
import bpy
-def randomize_selected(seed, loc, rot, scale, scale_even, scale_min):
+def randomize_selected(seed, delta, loc, rot, scale, scale_even):
import random
from random import uniform
@@ -35,20 +35,31 @@ def randomize_selected(seed, loc, rot, scale, scale_even, scale_min):
for obj in bpy.context.selected_objects:
if loc:
- obj.location += rand_vec(loc)
+ if delta:
+ obj.delta_location += rand_vec(loc)
+ else:
+ obj.location += rand_vec(loc)
else: # otherwise the values change under us
uniform(0.0, 0.0), uniform(0.0, 0.0), uniform(0.0, 0.0)
if rot: # TODO, non euler's
vec = rand_vec(rot)
- obj.rotation_euler[0] += vec[0]
- obj.rotation_euler[1] += vec[1]
- obj.rotation_euler[2] += vec[2]
+ if delta:
+ obj.delta_rotation_euler[0] += vec[0]
+ obj.delta_rotation_euler[1] += vec[1]
+ obj.delta_rotation_euler[2] += vec[2]
+ else:
+ obj.rotation_euler[0] += vec[0]
+ obj.rotation_euler[1] += vec[1]
+ obj.rotation_euler[2] += vec[2]
else:
uniform(0.0, 0.0), uniform(0.0, 0.0), uniform(0.0, 0.0)
if scale:
- org_sca_x, org_sca_y, org_sca_z = obj.scale
+ if delta:
+ org_sca_x, org_sca_y, org_sca_z = obj.delta_scale
+ else:
+ org_sca_x, org_sca_y, org_sca_z = obj.scale
if scale_even:
sca_x = sca_y = sca_z = uniform(scale[0], - scale[0])
@@ -56,26 +67,23 @@ def randomize_selected(seed, loc, rot, scale, scale_even, scale_min):
else:
sca_x, sca_y, sca_z = rand_vec(scale)
- aX = sca_x + org_sca_x
- bX = org_sca_x * scale_min
-
- aY = sca_y + org_sca_y
- bY = org_sca_y * scale_min
-
- aZ = sca_z + org_sca_z
- bZ = org_sca_z * scale_min
-
- if aX < bX:
- aX = bX
- if aY < bY:
- aY = bY
- if aZ < bZ:
- aZ = bZ
+ if scale_even:
+ aX = -(sca_x * org_sca_x) + org_sca_x
+ aY = -(sca_x * org_sca_y) + org_sca_y
+ aZ = -(sca_x * org_sca_z) + org_sca_z
+ else:
+ aX = sca_x + org_sca_x
+ aY = sca_y + org_sca_y
+ aZ = sca_z + org_sca_z
- obj.scale = aX, aY, aZ
+ if delta:
+ obj.delta_scale = aX, aY, aZ
+ else:
+ obj.scale = aX, aY, aZ
else:
uniform(0.0, 0.0), uniform(0.0, 0.0), uniform(0.0, 0.0)
+
from bpy.props import *
@@ -89,8 +97,11 @@ class RandomizeLocRotSize(bpy.types.Operator):
description="Seed value for the random generator",
default=0, min=0, max=1000)
+ use_delta = BoolProperty(name="Transform Delta",
+ description="Randomize delta transform values instead of regular transform", default=False)
+
use_loc = BoolProperty(name="Randomize Location",
- description="Randomize the scale values", default=True)
+ description="Randomize the location values", default=True)
loc = FloatVectorProperty(name="Location",
description="Maximun distance the objects can spread over each axis",
@@ -109,9 +120,9 @@ class RandomizeLocRotSize(bpy.types.Operator):
scale_even = BoolProperty(name="Scale Even",
description="Use the same scale value for all axis", default=False)
- scale_min = FloatProperty(name="Minimun Scale Factor",
+ '''scale_min = FloatProperty(name="Minimun Scale Factor",
description="Lowest scale percentage possible",
- default=0.15, min=-1.0, max=1.0, precision=3)
+ default=0.15, min=-1.0, max=1.0, precision=3)'''
scale = FloatVectorProperty(name="Scale",
description="Maximum scale randomization over each axis",
@@ -119,16 +130,19 @@ class RandomizeLocRotSize(bpy.types.Operator):
def execute(self, context):
from math import radians
+
seed = self.random_seed
+ delta = self.use_delta
+
loc = None if not self.use_loc else self.loc
rot = None if not self.use_rot else self.rot * radians(1.0)
scale = None if not self.use_scale else self.scale
scale_even = self.scale_even
- scale_min = self.scale_min
+ #scale_min = self.scale_min
- randomize_selected(seed, loc, rot, scale, scale_even, scale_min)
+ randomize_selected(seed, delta, loc, rot, scale, scale_even)
return {'FINISHED'}
@@ -140,11 +154,14 @@ def menu_func(self, context):
def register():
+ bpy.utils.register_module(__name__)
bpy.types.VIEW3D_MT_transform.append(menu_func)
def unregister():
+ bpy.utils.unregister_module(__name__)
bpy.types.VIEW3D_MT_transform.remove(menu_func)
+
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/presets.py b/release/scripts/op/presets.py
index 07852550ab7..65653aeee3e 100644
--- a/release/scripts/op/presets.py
+++ b/release/scripts/op/presets.py
@@ -29,6 +29,7 @@ class AddPresetBase():
- preset_subdir '''
# bl_idname = "script.preset_base_add"
# bl_label = "Add a Python Preset"
+ bl_options = {'REGISTER'} # only because invoke_props_popup requires.
name = bpy.props.StringProperty(name="Name", description="Name of the preset, used to make the path name", maxlen=64, default="")
remove_active = bpy.props.BoolProperty(default=False, options={'HIDDEN'})
@@ -41,36 +42,52 @@ class AddPresetBase():
def execute(self, context):
import os
-
+
if hasattr(self, "pre_cb"):
self.pre_cb(context)
-
+
preset_menu_class = getattr(bpy.types, self.preset_menu)
- if not self.remove_active:
-
+ if not self.remove_active:
+
if not self.name:
return {'FINISHED'}
filename = self.as_filename(self.name)
-
- target_path = bpy.utils.preset_paths(self.preset_subdir)[0] # we need some way to tell the user and system preset path
+
+ target_path = bpy.utils.user_resource('SCRIPTS', os.path.join("presets", self.preset_subdir), create=True)
+
+ if not target_path:
+ self.report({'WARNING'}, "Failed to create presets path")
+ return {'CANCELLED'}
filepath = os.path.join(target_path, filename) + ".py"
-
+
if hasattr(self, "add"):
self.add(context, filepath)
else:
file_preset = open(filepath, 'w')
file_preset.write("import bpy\n")
+ if hasattr(self, "preset_defines"):
+ for rna_path in self.preset_defines:
+ exec(rna_path)
+ file_preset.write("%s\n" % rna_path)
+ file_preset.write("\n")
+
for rna_path in self.preset_values:
value = eval(rna_path)
- file_preset.write("%s = %s\n" % (rna_path, repr(value)))
+ # convert thin wrapped sequences to simple lists to repr()
+ try:
+ value = value[:]
+ except:
+ pass
+
+ file_preset.write("%s = %r\n" % (rna_path, value))
file_preset.close()
-
- preset_menu_class.bl_label = bpy.path.display_name(self.name)
+
+ preset_menu_class.bl_label = bpy.path.display_name(filename)
else:
preset_active = preset_menu_class.bl_label
@@ -101,14 +118,13 @@ class AddPresetBase():
return {'FINISHED'}
+ def check(self, context):
+ self.name = self.as_filename(self.name)
+
def invoke(self, context, event):
if not self.remove_active:
wm = context.window_manager
- #crashes, TODO - fix
- #return wm.invoke_props_popup(self, event)
-
- wm.invoke_props_popup(self, event)
- return {'RUNNING_MODAL'}
+ return wm.invoke_props_dialog(self)
else:
return self.execute(context)
@@ -140,17 +156,21 @@ class AddPresetRender(AddPresetBase, bpy.types.Operator):
bl_label = "Add Render Preset"
preset_menu = "RENDER_MT_presets"
+ preset_defines = [
+ "scene = bpy.context.scene"
+ ]
+
preset_values = [
- "bpy.context.scene.render.field_order",
- "bpy.context.scene.render.fps",
- "bpy.context.scene.render.fps_base",
- "bpy.context.scene.render.pixel_aspect_x",
- "bpy.context.scene.render.pixel_aspect_y",
- "bpy.context.scene.render.resolution_percentage",
- "bpy.context.scene.render.resolution_x",
- "bpy.context.scene.render.resolution_y",
- "bpy.context.scene.render.use_fields",
- "bpy.context.scene.render.use_fields_still",
+ "scene.render.field_order",
+ "scene.render.fps",
+ "scene.render.fps_base",
+ "scene.render.pixel_aspect_x",
+ "scene.render.pixel_aspect_y",
+ "scene.render.resolution_percentage",
+ "scene.render.resolution_x",
+ "scene.render.resolution_y",
+ "scene.render.use_fields",
+ "scene.render.use_fields_still",
]
preset_subdir = "render"
@@ -162,20 +182,20 @@ class AddPresetSSS(AddPresetBase, bpy.types.Operator):
bl_label = "Add SSS Preset"
preset_menu = "MATERIAL_MT_sss_presets"
+ preset_defines = [
+ "material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)"
+ ]
+
preset_values = [
- "bpy.context.material.subsurface_scattering.back",
- "bpy.context.material.subsurface_scattering.color[0]",
- "bpy.context.material.subsurface_scattering.color[1]",
- "bpy.context.material.subsurface_scattering.color[2]",
- "bpy.context.material.subsurface_scattering.color_factor",
- "bpy.context.material.subsurface_scattering.error_threshold",
- "bpy.context.material.subsurface_scattering.front",
- "bpy.context.material.subsurface_scattering.ior",
- "bpy.context.material.subsurface_scattering.radius[0]",
- "bpy.context.material.subsurface_scattering.radius[1]",
- "bpy.context.material.subsurface_scattering.radius[2]",
- "bpy.context.material.subsurface_scattering.scale",
- "bpy.context.material.subsurface_scattering.texture_factor",
+ "material.subsurface_scattering.back",
+ "material.subsurface_scattering.color",
+ "material.subsurface_scattering.color_factor",
+ "material.subsurface_scattering.error_threshold",
+ "material.subsurface_scattering.front",
+ "material.subsurface_scattering.ior",
+ "material.subsurface_scattering.radius",
+ "material.subsurface_scattering.scale",
+ "material.subsurface_scattering.texture_factor",
]
preset_subdir = "sss"
@@ -187,13 +207,17 @@ class AddPresetCloth(AddPresetBase, bpy.types.Operator):
bl_label = "Add Cloth Preset"
preset_menu = "CLOTH_MT_presets"
+ preset_defines = [
+ "cloth = bpy.context.cloth"
+ ]
+
preset_values = [
- "bpy.context.cloth.settings.air_damping",
- "bpy.context.cloth.settings.bending_stiffness",
- "bpy.context.cloth.settings.mass",
- "bpy.context.cloth.settings.quality",
- "bpy.context.cloth.settings.spring_damping",
- "bpy.context.cloth.settings.structural_stiffness",
+ "cloth.settings.air_damping",
+ "cloth.settings.bending_stiffness",
+ "cloth.settings.mass",
+ "cloth.settings.quality",
+ "cloth.settings.spring_damping",
+ "cloth.settings.structural_stiffness",
]
preset_subdir = "cloth"
@@ -205,20 +229,24 @@ class AddPresetSunSky(AddPresetBase, bpy.types.Operator):
bl_label = "Add Sunsky Preset"
preset_menu = "LAMP_MT_sunsky_presets"
+ preset_defines = [
+ "sky = bpy.context.object.data.sky"
+ ]
+
preset_values = [
- "bpy.context.object.data.sky.atmosphere_extinction",
- "bpy.context.object.data.sky.atmosphere_inscattering",
- "bpy.context.object.data.sky.atmosphere_turbidity",
- "bpy.context.object.data.sky.backscattered_light",
- "bpy.context.object.data.sky.horizon_brightness",
- "bpy.context.object.data.sky.spread",
- "bpy.context.object.data.sky.sun_brightness",
- "bpy.context.object.data.sky.sun_intensity",
- "bpy.context.object.data.sky.sun_size",
- "bpy.context.object.data.sky.use_sky_blend",
- "bpy.context.object.data.sky.use_sky_blend_type",
- "bpy.context.object.data.sky.use_sky_color_space",
- "bpy.context.object.data.sky.use_sky_exposure",
+ "sky.atmosphere_extinction",
+ "sky.atmosphere_inscattering",
+ "sky.atmosphere_turbidity",
+ "sky.backscattered_light",
+ "sky.horizon_brightness",
+ "sky.spread",
+ "sky.sun_brightness",
+ "sky.sun_intensity",
+ "sky.sun_size",
+ "sky.use_sky_blend",
+ "sky.use_sky_blend_type",
+ "sky.use_sky_color_space",
+ "sky.use_sky_exposure",
]
preset_subdir = "sunsky"
@@ -230,17 +258,21 @@ class AddPresetInteraction(AddPresetBase, bpy.types.Operator):
bl_label = "Add Interaction Preset"
preset_menu = "USERPREF_MT_interaction_presets"
+ preset_defines = [
+ "user_preferences = bpy.context.user_preferences"
+ ]
+
preset_values = [
- "bpy.context.user_preferences.edit.use_drag_immediately",
- "bpy.context.user_preferences.edit.use_insertkey_xyz_to_rgb",
- "bpy.context.user_preferences.inputs.invert_mouse_wheel_zoom",
- "bpy.context.user_preferences.inputs.select_mouse",
- "bpy.context.user_preferences.inputs.use_emulate_numpad",
- "bpy.context.user_preferences.inputs.use_mouse_continuous",
- "bpy.context.user_preferences.inputs.use_mouse_emulate_3_button",
- "bpy.context.user_preferences.inputs.view_rotate_method",
- "bpy.context.user_preferences.inputs.view_zoom_axis",
- "bpy.context.user_preferences.inputs.view_zoom_method",
+ "user_preferences.edit.use_drag_immediately",
+ "user_preferences.edit.use_insertkey_xyz_to_rgb",
+ "user_preferences.inputs.invert_mouse_wheel_zoom",
+ "user_preferences.inputs.select_mouse",
+ "user_preferences.inputs.use_emulate_numpad",
+ "user_preferences.inputs.use_mouse_continuous",
+ "user_preferences.inputs.use_mouse_emulate_3_button",
+ "user_preferences.inputs.view_rotate_method",
+ "user_preferences.inputs.view_zoom_axis",
+ "user_preferences.inputs.view_zoom_method",
]
preset_subdir = "interaction"
@@ -250,7 +282,7 @@ class AddPresetKeyconfig(AddPresetBase, bpy.types.Operator):
'''Add a Keyconfig Preset'''
bl_idname = "wm.keyconfig_preset_add"
bl_label = "Add Keyconfig Preset"
- preset_menu = "PREFS_MT_keyconfigs"
+ preset_menu = "USERPREF_MT_keyconfigs"
preset_subdir = "keyconfig"
def add(self, context, filepath):
@@ -269,12 +301,64 @@ class AddPresetKeyconfig(AddPresetBase, bpy.types.Operator):
keyconfigs.remove(keyconfigs.active)
+class AddPresetOperator(AddPresetBase, bpy.types.Operator):
+ '''Add an Application Interaction Preset'''
+ bl_idname = "wm.operator_preset_add"
+ bl_label = "Operator Preset"
+ preset_menu = "WM_MT_operator_presets"
+
+ operator = bpy.props.StringProperty(name="Operator", maxlen=64, options={'HIDDEN'})
+
+ # XXX, not ideal
+ preset_defines = [
+ "op = bpy.context.space_data.operator",
+ ]
+
+ @property
+ def preset_subdir(self):
+ return __class__.operator_path(self.operator)
+
+ @property
+ def preset_values(self):
+ properties_blacklist = bpy.types.Operator.bl_rna.properties.keys()
+
+ prefix, suffix = self.operator.split("_OT_", 1)
+ operator_rna = getattr(getattr(bpy.ops, prefix.lower()), suffix).get_rna().bl_rna
+
+ ret = []
+ for prop_id, prop in operator_rna.properties.items():
+ if (not prop.is_hidden) and prop_id not in properties_blacklist:
+ ret.append("op.%s" % prop_id)
+
+ return ret
+
+ @staticmethod
+ def operator_path(operator):
+ import os
+ prefix, suffix = operator.split("_OT_", 1)
+ return os.path.join("operator", "%s.%s" % (prefix.lower(), suffix))
+
+
+class WM_MT_operator_presets(bpy.types.Menu):
+ bl_label = "Operator Presets"
+
+ def draw(self, context):
+ self.operator = context.space_data.operator.bl_idname
+ bpy.types.Menu.draw_preset(self, context)
+
+ @property
+ def preset_subdir(self):
+ return AddPresetOperator.operator_path(self.operator)
+
+ preset_operator = "script.execute_preset"
+
+
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/screen_play_rendered_anim.py b/release/scripts/op/screen_play_rendered_anim.py
index 53421642129..579af9b34b3 100644
--- a/release/scripts/op/screen_play_rendered_anim.py
+++ b/release/scripts/op/screen_play_rendered_anim.py
@@ -30,14 +30,18 @@ import os
def guess_player_path(preset):
import platform
- system = platform.system()
+ try:
+ system = platform.system()
+ except UnicodeDecodeError:
+ import sys
+ system = sys.platform
if preset == 'BLENDER24':
player_path = "blender"
if system == 'Darwin':
test_path = "/Applications/blender 2.49.app/Contents/MacOS/blender"
- elif system == 'Windows':
+ elif system in ('Windows', 'win32'):
test_path = "/Program Files/Blender Foundation/Blender/blender.exe"
if os.path.exists(test_path):
@@ -143,11 +147,11 @@ class PlayRenderedAnim(bpy.types.Operator):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/sequencer.py b/release/scripts/op/sequencer.py
index e34489b335d..de341bef269 100644
--- a/release/scripts/op/sequencer.py
+++ b/release/scripts/op/sequencer.py
@@ -135,11 +135,11 @@ class SequencerDeinterlaceSelectedMovies(bpy.types.Operator):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
diff --git a/release/scripts/op/uv.py b/release/scripts/op/uv.py
index d01ef070d87..83282924b5b 100644
--- a/release/scripts/op/uv.py
+++ b/release/scripts/op/uv.py
@@ -21,11 +21,12 @@
import bpy
from bpy.props import *
+
def write_svg(fw, mesh, image_width, image_height, face_iter):
# for making an XML compatible string
from xml.sax.saxutils import escape
from os.path import basename
-
+
fw('<?xml version="1.0" standalone="no"?>\n')
fw('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" \n')
fw(' "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n')
@@ -113,7 +114,7 @@ def write_png(fw, mesh_source, image_width, image_height, face_iter):
filepath = fw.__self__.name
fw.__self__.close()
- material_solids = [bpy.data.materials.new("uv_temp_solid") for i in range(len(mesh_source.materials))]
+ material_solids = [bpy.data.materials.new("uv_temp_solid") for i in range(max(1, len(mesh_source.materials)))]
material_wire = bpy.data.materials.new("uv_temp_wire")
scene = bpy.data.scenes.new("uv_temp")
@@ -126,27 +127,37 @@ def write_png(fw, mesh_source, image_width, image_height, face_iter):
for f in mesh_source.faces:
tot_verts += len(f.vertices)
+ faces_source = mesh_source.faces
+
+ # get unique UV's incase there are many overlapping which slow down filling.
+ face_hash_3 = set()
+ face_hash_4 = set()
+ for i, uv in face_iter:
+ material_index = faces_source[i].material_index
+ if len(uv) == 3:
+ face_hash_3.add((uv[0][0], uv[0][1], uv[1][0], uv[1][1], uv[2][0], uv[2][1], material_index))
+ else:
+ face_hash_4.add((uv[0][0], uv[0][1], uv[1][0], uv[1][1], uv[2][0], uv[2][1], uv[3][0], uv[3][1], material_index))
+
# now set the faces coords and locations
# build mesh data
mesh_new_vertices = []
mesh_new_materials = []
mesh_new_face_vertices = []
-
-
+
current_vert = 0
- faces_source = mesh_source.faces
- for i, uv in face_iter:
- if len(uv) == 3:
- mesh_new_vertices.extend([uv[0][0], uv[0][1], 0.0, uv[1][0], uv[1][1], 0.0, uv[2][0], uv[2][1], 0.0])
- mesh_new_face_vertices.extend([current_vert, current_vert + 1, current_vert + 2, 0])
- current_vert += 3
- else:
- mesh_new_vertices.extend([uv[0][0], uv[0][1], 0.0, uv[1][0], uv[1][1], 0.0, uv[2][0], uv[2][1], 0.0, uv[3][0], uv[3][1], 0.0])
- mesh_new_face_vertices.extend([current_vert, current_vert + 1, current_vert + 2, current_vert + 3])
- current_vert += 4
- mesh_new_materials.append(faces_source[i].material_index)
-
+ for face_data in face_hash_3:
+ mesh_new_vertices.extend([face_data[0], face_data[1], 0.0, face_data[2], face_data[3], 0.0, face_data[4], face_data[5], 0.0])
+ mesh_new_face_vertices.extend([current_vert, current_vert + 1, current_vert + 2, 0])
+ mesh_new_materials.append(face_data[6])
+ current_vert += 3
+ for face_data in face_hash_4:
+ mesh_new_vertices.extend([face_data[0], face_data[1], 0.0, face_data[2], face_data[3], 0.0, face_data[4], face_data[5], 0.0, face_data[6], face_data[7], 0.0])
+ mesh_new_face_vertices.extend([current_vert, current_vert + 1, current_vert + 2, current_vert + 3])
+ mesh_new_materials.append(face_data[8])
+ current_vert += 4
+
mesh.vertices.add(len(mesh_new_vertices) // 3)
mesh.faces.add(len(mesh_new_face_vertices) // 4)
@@ -155,7 +166,7 @@ def write_png(fw, mesh_source, image_width, image_height, face_iter):
mesh.faces.foreach_set("material_index", mesh_new_materials)
mesh.update(calc_edges=True)
-
+
obj_solid = bpy.data.objects.new("uv_temp_solid", mesh)
obj_wire = bpy.data.objects.new("uv_temp_wire", mesh)
base_solid = scene.objects.link(obj_solid)
@@ -165,11 +176,10 @@ def write_png(fw, mesh_source, image_width, image_height, face_iter):
# place behind the wire
obj_solid.location = 0, 0, -1
-
+
obj_wire.material_slots[0].link = 'OBJECT'
obj_wire.material_slots[0].material = material_wire
-
-
+
# setup the camera
cam = bpy.data.cameras.new("uv_temp")
cam.type = 'ORTHO'
@@ -181,7 +191,9 @@ def write_png(fw, mesh_source, image_width, image_height, face_iter):
# setup materials
for i, mat_solid in enumerate(material_solids):
- mat_solid.diffuse_color = mesh_source.materials[i].diffuse_color
+ if mesh_source.materials and mesh_source.materials[i]:
+ mat_solid.diffuse_color = mesh_source.materials[i].diffuse_color
+
mat_solid.use_shadeless = True
mat_solid.use_transparency = True
mat_solid.alpha = 0.25
@@ -190,7 +202,6 @@ def write_png(fw, mesh_source, image_width, image_height, face_iter):
material_wire.use_shadeless = True
material_wire.diffuse_color = 0, 0, 0
-
# scene render settings
scene.render.use_raytrace = False
scene.render.alpha_mode = 'STRAIGHT'
@@ -203,22 +214,17 @@ def write_png(fw, mesh_source, image_width, image_height, face_iter):
if image_width > image_height:
scene.render.pixel_aspect_y = image_width / image_height
elif image_width < image_height:
- scene.render.pixel_aspect_x = image_height /image_width
-
+ scene.render.pixel_aspect_x = image_height / image_width
+
scene.frame_start = 1
scene.frame_end = 1
-
+
scene.render.file_format = 'PNG'
scene.render.filepath = filepath
data_context = {"blend_data": bpy.context.blend_data, "scene": scene}
- bpy.ops.render.render(data_context, animation=True)
-
- # stupid
- import os
- animpath = scene.render.frame_path(1)
- os.rename(animpath, os.path.abspath(filepath))
-
+ bpy.ops.render.render(data_context, write_still=True)
+
# cleanup
bpy.data.scenes.remove(scene)
bpy.data.objects.remove(obj_cam)
@@ -227,15 +233,14 @@ def write_png(fw, mesh_source, image_width, image_height, face_iter):
bpy.data.cameras.remove(cam)
bpy.data.meshes.remove(mesh)
-
+
bpy.data.materials.remove(material_wire)
for mat_solid in material_solids:
bpy.data.materials.remove(mat_solid)
-
class ExportUVLayout(bpy.types.Operator):
- '''Export the Mesh as SVG'''
+ """Export UV layout to file"""
bl_idname = "uv.export_layout"
bl_label = "Export UV Layout"
@@ -251,16 +256,16 @@ class ExportUVLayout(bpy.types.Operator):
name="Format",
description="File format to export the UV layout to",
default='PNG')
- size = IntVectorProperty(size=2, default=(1024, 1024), min=8, max=32768)
+ size = IntVectorProperty(size=2, default=(1024, 1024), min=8, max=32768, description="Dimensions of the exported file")
@classmethod
def poll(cls, context):
obj = context.active_object
- return (obj and obj.type == 'MESH')
+ return (obj and obj.type == 'MESH' and obj.data.uv_textures)
def _space_image(self, context):
space_data = context.space_data
- if type(space_data) == bpy.types.SpaceImageEditor:
+ if isinstance(space_data, bpy.types.SpaceImageEditor):
return space_data
else:
return None
@@ -319,7 +324,6 @@ class ExportUVLayout(bpy.types.Operator):
if is_editmode:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
-
mesh = obj.data
mode = self.mode
@@ -351,11 +355,12 @@ class ExportUVLayout(bpy.types.Operator):
else:
return False
-
def invoke(self, context, event):
+ import os
self.size = self._image_size(context)
+ self.filepath = os.path.splitext(bpy.data.filepath)[0]
wm = context.window_manager
- wm.add_fileselect(self)
+ wm.fileselect_add(self)
return {'RUNNING_MODAL'}
@@ -364,10 +369,12 @@ def menu_func(self, context):
def register():
+ bpy.utils.register_module(__name__)
bpy.types.IMAGE_MT_uvs.append(menu_func)
def unregister():
+ bpy.utils.unregister_module(__name__)
bpy.types.IMAGE_MT_uvs.remove(menu_func)
if __name__ == "__main__":
diff --git a/release/scripts/op/uvcalc_follow_active.py b/release/scripts/op/uvcalc_follow_active.py
index 9f809dd39f8..12895fae1c5 100644
--- a/release/scripts/op/uvcalc_follow_active.py
+++ b/release/scripts/op/uvcalc_follow_active.py
@@ -31,7 +31,6 @@ def extend(obj, operator, EXTEND_MODE):
if not me.uv_textures:
me.uv_textures.new()
-
# Toggle Edit mode
is_editmode = (obj.mode == 'EDIT')
if is_editmode:
@@ -41,7 +40,7 @@ def extend(obj, operator, EXTEND_MODE):
edge_average_lengths = {}
OTHER_INDEX = 2, 3, 0, 1
- FAST_INDICIES = 0, 2, 1, 3 # order is faster
+ FAST_INDICIES = 0, 2, 1, 3 # order is faster
def extend_uvs(face_source, face_target, edge_key):
'''
@@ -86,30 +85,27 @@ def extend(obj, operator, EXTEND_MODE):
except:
target_matching_edge = edge_idxs_target.index(edge_key_swap)
-
edgepair_inner_source = edge_idxs_source[source_matching_edge]
edgepair_inner_target = edge_idxs_target[target_matching_edge]
edgepair_outer_source = edge_idxs_source[OTHER_INDEX[source_matching_edge]]
edgepair_outer_target = edge_idxs_target[OTHER_INDEX[target_matching_edge]]
if edge_idxs_source[source_matching_edge] == edge_idxs_target[target_matching_edge]:
- iA = 0 # Flipped, most common
+ iA = 0 # Flipped, most common
iB = 1
- else: # The normals of these faces must be different
+ else: # The normals of these faces must be different
iA = 1
iB = 0
-
# Set the target UV's touching source face, no tricky calc needed,
uvs_vhash_target[edgepair_inner_target[0]][:] = uvs_vhash_source[edgepair_inner_source[iA]]
uvs_vhash_target[edgepair_inner_target[1]][:] = uvs_vhash_source[edgepair_inner_source[iB]]
-
# Set the 2 UV's on the target face that are not touching
# for this we need to do basic expaning on the source faces UV's
if EXTEND_MODE == 'LENGTH':
- try: # divide by zero is possible
+ try: # divide by zero is possible
'''
measure the length of each face from the middle of each edge to the opposite
allong the axis we are copying, use this
@@ -137,7 +133,6 @@ def extend(obj, operator, EXTEND_MODE):
uvs_vhash_target[edgepair_outer_target[iB]][:] = uvs_vhash_source[edgepair_inner_source[0]] + (uvs_vhash_source[edgepair_inner_source[0]] - uvs_vhash_source[edgepair_outer_source[1]])
uvs_vhash_target[edgepair_outer_target[iA]][:] = uvs_vhash_source[edgepair_inner_source[1]] + (uvs_vhash_source[edgepair_inner_source[1]] - uvs_vhash_source[edgepair_outer_source[0]])
-
if not me.uv_textures:
me.uv_textures.new()
@@ -158,15 +153,12 @@ def extend(obj, operator, EXTEND_MODE):
operator.report({'ERROR'}, "Active face not selected.")
return
-
-
# Modes
# 0 unsearched
# 1:mapped, use search from this face. - removed!!
# 2:all siblings have been searched. dont search again.
face_modes = [0] * len(face_sel)
- face_modes[face_act_local_index] = 1 # extend UV's from this face.
-
+ face_modes[face_act_local_index] = 1 # extend UV's from this face.
# Edge connectivty
edge_faces = {}
@@ -187,7 +179,6 @@ def extend(obj, operator, EXTEND_MODE):
looplen[0] += (me_verts[ed[0]].co - me_verts[ed[1]].co).length
looplen[0] = looplen[0] / len(loop)
-
# remove seams, so we dont map accross seams.
for ed in me.edges:
if ed.use_seam:
@@ -198,36 +189,34 @@ def extend(obj, operator, EXTEND_MODE):
pass
# Done finding seams
-
# face connectivity - faces around each face
- # only store a list of indicies for each face.
+ # only store a list of indices for each face.
face_faces = [[] for i in range(len(face_sel))]
for edge_key, faces in edge_faces.items():
- if len(faces) == 2: # Only do edges with 2 face users for now
+ if len(faces) == 2: # Only do edges with 2 face users for now
face_faces[faces[0]].append((faces[1], edge_key))
face_faces[faces[1]].append((faces[0], edge_key))
-
# Now we know what face is connected to what other face, map them by connectivity
ok = True
while ok:
ok = False
for i in range(len(face_sel)):
- if face_modes[i] == 1: # searchable
+ if face_modes[i] == 1: # searchable
for f_sibling, edge_key in face_faces[i]:
if face_modes[f_sibling] == 0:
- face_modes[f_sibling] = 1 # mapped and search from.
+ face_modes[f_sibling] = 1 # mapped and search from.
extend_uvs(face_sel[i], face_sel[f_sibling], edge_key)
- face_modes[i] = 1 # we can map from this one now.
- ok = True # keep searching
+ face_modes[i] = 1 # we can map from this one now.
+ ok = True # keep searching
- face_modes[i] = 2 # dont search again
+ face_modes[i] = 2 # dont search again
if is_editmode:
bpy.ops.object.mode_set(mode='EDIT')
else:
- me.update()
+ me.update_tag()
def main(context, operator):
@@ -262,11 +251,14 @@ menu_func = (lambda self, context: self.layout.operator(FollowActiveQuads.bl_idn
def register():
+ bpy.utils.register_module(__name__)
bpy.types.VIEW3D_MT_uv_map.append(menu_func)
def unregister():
+ bpy.utils.unregister_module(__name__)
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 83303f8f7f1..8cdf593f98d 100644
--- a/release/scripts/op/uvcalc_smart_project.py
+++ b/release/scripts/op/uvcalc_smart_project.py
@@ -22,9 +22,8 @@
# <pep8 compliant>
-from mathutils import Matrix, Vector
+from mathutils import Matrix, Vector, geometry
import time
-import geometry
import bpy
from math import cos, radians
@@ -79,11 +78,7 @@ def pointInTri2D(v, v1, v2, v3):
nor = side1.cross(side2)
- l1 = [side1[0], side1[1], side1[2]]
- l2 = [side2[0], side2[1], side2[2]]
- l3 = [nor[0], nor[1], nor[2]]
-
- mtx = Matrix(l1, l2, l3)
+ mtx = Matrix((side1, side2, nor))
# Zero area 2d tri, even tho we throw away zerop area faces
# the projection UV can result in a zero area UV.
@@ -173,7 +168,7 @@ def island2Edge(island):
# e.pop(2)
# return edges and unique points
- return length_sorted_edges, [v.__copy__().resize3D() for v in unique_points.values()]
+ return length_sorted_edges, [v.to_3d() for v in unique_points.values()]
# ========================= NOT WORKING????
# Find if a points inside an edge loop, un-orderd.
@@ -226,13 +221,13 @@ def islandIntersectUvIsland(source, target, SourceOffset):
# Edge intersect test
for ed in edgeLoopsSource:
for seg in edgeLoopsTarget:
- i = geometry.LineIntersect2D(\
+ i = geometry.intersect_line_line_2d(\
seg[0], seg[1], SourceOffset+ed[0], SourceOffset+ed[1])
if i:
return 1 # LINE INTERSECTION
# 1 test for source being totally inside target
- SourceOffset.resize3D()
+ SourceOffset.resize_3d()
for pv in source[7]:
if pointInIsland(pv+SourceOffset, target[0]):
return 2 # SOURCE INSIDE TARGET
@@ -740,7 +735,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.box_pack_2d(packBoxes)
# print 'Box Packing Time:', time.time() - time1
@@ -777,16 +772,12 @@ def packIslands(islandList):
-def VectoMat(vec):
- a3 = vec.__copy__().normalize()
-
- up = Vector((0.0, 0.0, 1.0))
- if abs(a3.dot(up)) == 1.0:
- up = Vector((0.0, 1.0, 0.0))
-
- a1 = a3.cross(up).normalize()
- a2 = a3.cross(a1)
- return Matrix([a1[0], a1[1], a1[2]], [a2[0], a2[1], a2[2]], [a3[0], a3[1], a3[2]])
+def VectoQuat(vec):
+ vec = vec.normalized()
+ if abs(vec.x) > 0.5:
+ return vec.to_track_quat('Z', 'X')
+ else:
+ return vec.to_track_quat('Z', 'Y')
class thickface(object):
@@ -935,7 +926,7 @@ def main(context, island_margin, projection_limit):
# Initialize projectVecs
if USER_VIEW_INIT:
# Generate Projection
- projectVecs = [Vector(Window.GetViewVector()) * ob.matrix_world.copy().invert().rotation_part()] # We add to this allong the way
+ projectVecs = [Vector(Window.GetViewVector()) * ob.matrix_world.inverted().to_3x3()] # We add to this allong the way
else:
projectVecs = []
@@ -972,7 +963,7 @@ def main(context, island_margin, projection_limit):
averageVec += fprop.no
if averageVec.x != 0 or averageVec.y != 0 or averageVec.z != 0: # Avoid NAN
- projectVecs.append(averageVec.normalize())
+ projectVecs.append(averageVec.normalized())
# Get the next vec!
@@ -1049,14 +1040,14 @@ def main(context, island_margin, projection_limit):
continue
# Make a projection matrix from a unit length vector.
- MatProj = VectoMat(projectVecs[i])
+ MatQuat = VectoQuat(projectVecs[i])
# Get the faces UV's from the projected vertex.
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.
- f_uv[j][:] = (v.co * MatProj)[:2]
+ f_uv[j][:] = (v.co * MatQuat)[:2]
if USER_SHARE_SPACE:
@@ -1139,10 +1130,12 @@ menu_func = (lambda self, context: self.layout.operator(SmartProject.bl_idname,
def register():
+ bpy.utils.register_module(__name__)
bpy.types.VIEW3D_MT_uv_map.append(menu_func)
def unregister():
+ bpy.utils.unregister_module(__name__)
bpy.types.VIEW3D_MT_uv_map.remove(menu_func)
if __name__ == "__main__":
diff --git a/release/scripts/op/vertexpaint_dirt.py b/release/scripts/op/vertexpaint_dirt.py
index c5bb4450497..d5060e913ae 100644
--- a/release/scripts/op/vertexpaint_dirt.py
+++ b/release/scripts/op/vertexpaint_dirt.py
@@ -65,7 +65,7 @@ def applyVertexDirt(me, blur_iterations, blur_strength, clamp_dirt, clamp_clean,
# get the direction of the vectors between the vertex and it's connected vertices
for c in con[i]:
- vec += (me.vertices[c].co - co).normalize()
+ vec += (me.vertices[c].co - co).normalized()
# normalize the vector by dividing by the number of connected verts
tot_con = len(con[i])
@@ -180,11 +180,11 @@ class VertexPaintDirt(bpy.types.Operator):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/op/wm.py b/release/scripts/op/wm.py
index 958fdeb3df6..cbc9e3cd55f 100644
--- a/release/scripts/op/wm.py
+++ b/release/scripts/op/wm.py
@@ -30,11 +30,12 @@ class MESH_OT_delete_edgeloop(bpy.types.Operator):
bl_label = "Delete Edge Loop"
def execute(self, context):
- bpy.ops.transform.edge_slide(value=1.0)
- bpy.ops.mesh.select_more()
- bpy.ops.mesh.remove_doubles()
+ if 'FINISHED' in bpy.ops.transform.edge_slide(value=1.0):
+ bpy.ops.mesh.select_more()
+ bpy.ops.mesh.remove_doubles()
+ return {'FINISHED'}
- return {'FINISHED'}
+ return {'CANCELLED'}
rna_path_prop = StringProperty(name="Context Attributes",
description="rna context string", maxlen=1024, default="")
@@ -74,6 +75,34 @@ def execute_context_assign(self, context):
return {'FINISHED'}
+class BRUSH_OT_set_active_number(bpy.types.Operator):
+ '''Set active sculpt/paint brush from it's number'''
+ bl_idname = "brush.set_active_number"
+ bl_label = "Set Brush Number"
+
+ mode = StringProperty(name="mode",
+ description="Paint mode to set brush for", maxlen=1024)
+ number = IntProperty(name="number",
+ description="Brush number")
+
+ _attr_dict = {"sculpt": "use_paint_sculpt",
+ "vertex_paint": "use_paint_vertex",
+ "weight_paint": "use_paint_weight",
+ "image_paint": "use_paint_texture"}
+
+ def execute(self, context):
+ attr = self._attr_dict.get(self.mode)
+ if attr is None:
+ return {'CANCELLED'}
+
+ for i, brush in enumerate((cur for cur in bpy.data.brushes if getattr(cur, attr))):
+ if i == self.number:
+ getattr(context.tool_settings, self.mode).brush = brush
+ return {'FINISHED'}
+
+ return {'CANCELLED'}
+
+
class WM_OT_context_set_boolean(bpy.types.Operator):
'''Set a context value.'''
bl_idname = "wm.context_set_boolean"
@@ -241,8 +270,8 @@ class WM_OT_context_toggle_enum(bpy.types.Operator):
class WM_OT_context_cycle_int(bpy.types.Operator):
- '''Set a context value. Useful for cycling active material,
- vertex keys, groups' etc.'''
+ '''Set a context value. Useful for cycling active material, '''
+ '''vertex keys, groups' etc.'''
bl_idname = "wm.context_cycle_int"
bl_label = "Context Int Cycle"
bl_options = {'UNDO'}
@@ -266,9 +295,9 @@ class WM_OT_context_cycle_int(bpy.types.Operator):
if value != eval("context.%s" % data_path):
# relies on rna clamping int's out of the range
if self.reverse:
- value = (1 << 32)
+ value = (1 << 31) - 1
else:
- value = - (1 << 32)
+ value = -1 << 31
exec("context.%s=value" % data_path)
@@ -478,7 +507,7 @@ class WM_OT_context_modal_mouse(bpy.types.Operator):
else:
self.initial_x = event.mouse_x
- context.window_manager.add_modal_handler(self)
+ context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
@@ -500,7 +529,7 @@ class WM_OT_path_open(bpy.types.Operator):
bl_idname = "wm.path_open"
bl_label = ""
- filepath = StringProperty(name="File Path", maxlen=1024)
+ filepath = StringProperty(name="File Path", maxlen=1024, subtype='FILE_PATH')
def execute(self, context):
import sys
@@ -632,16 +661,14 @@ class WM_OT_doc_edit(bpy.types.Operator):
def draw(self, context):
layout = self.layout
- props = self.properties # XXX, this should not be needed, api problem!
- layout.label(text="Descriptor ID: '%s'" % props.doc_id)
- layout.prop(props, "doc_new", text="")
+ layout.label(text="Descriptor ID: '%s'" % self.doc_id)
+ layout.prop(self, "doc_new", text="")
def invoke(self, context, event):
wm = context.window_manager
return wm.invoke_props_dialog(self, width=600)
-
from bpy.props import *
@@ -662,6 +689,7 @@ class WM_OT_properties_edit(bpy.types.Operator):
'''Internal use (edit a property data_path)'''
bl_idname = "wm.properties_edit"
bl_label = "Edit Property"
+ bl_options = {'REGISTER'} # only because invoke_props_popup requires.
data_path = rna_path
property = rna_property
@@ -722,11 +750,7 @@ class WM_OT_properties_edit(bpy.types.Operator):
self.description = prop_ui.get("description", "")
wm = context.window_manager
- # This crashes, TODO - fix
- #return wm.invoke_props_popup(self, event)
-
- wm.invoke_props_popup(self, event)
- return {'RUNNING_MODAL'}
+ return wm.invoke_props_dialog(self)
class WM_OT_properties_add(bpy.types.Operator):
@@ -780,12 +804,23 @@ class WM_OT_keyconfig_activate(bpy.types.Operator):
return {'FINISHED'}
+class WM_OT_sysinfo(bpy.types.Operator):
+ '''Generate System Info'''
+ bl_idname = "wm.sysinfo"
+ bl_label = "System Info"
+
+ def execute(self, context):
+ import sys_info
+ sys_info.write_sysinfo(self)
+ return {'FINISHED'}
+
+
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/presets/ffmpeg/DV.py b/release/scripts/presets/ffmpeg/DV.py
index 4cdb2f271b9..46d2a0a4a2f 100644
--- a/release/scripts/presets/ffmpeg/DV.py
+++ b/release/scripts/presets/ffmpeg/DV.py
@@ -8,3 +8,6 @@ if is_ntsc:
bpy.context.scene.render.resolution_y = 480
else:
bpy.context.scene.render.resolution_y = 576
+
+bpy.context.scene.render.ffmpeg_audio_mixrate = 48000
+bpy.context.scene.render.ffmpeg_audio_codec = "PCM"
diff --git a/release/scripts/presets/ffmpeg/DVD.py b/release/scripts/presets/ffmpeg/DVD.py
index 233bdab4f20..e18ec9f817b 100644
--- a/release/scripts/presets/ffmpeg/DVD.py
+++ b/release/scripts/presets/ffmpeg/DVD.py
@@ -14,6 +14,10 @@ else:
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_buffersize = 224 * 8
bpy.context.scene.render.ffmpeg_packetsize = 2048
bpy.context.scene.render.ffmpeg_muxrate = 10080000
+
+bpy.context.scene.render.ffmpeg_audio_codec = "AC3"
+bpy.context.scene.render.ffmpeg_audio_bitrate = 448
+bpy.context.scene.render.ffmpeg_audio_mixrate = 48000
diff --git a/release/scripts/presets/ffmpeg/SVCD.py b/release/scripts/presets/ffmpeg/SVCD.py
index 52f938623b8..c71a3851af0 100644
--- a/release/scripts/presets/ffmpeg/SVCD.py
+++ b/release/scripts/presets/ffmpeg/SVCD.py
@@ -14,6 +14,10 @@ else:
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_buffersize = 224 * 8
bpy.context.scene.render.ffmpeg_packetsize = 2324
bpy.context.scene.render.ffmpeg_muxrate = 0
+
+bpy.context.scene.render.ffmpeg_audio_bitrate = 224
+bpy.context.scene.render.ffmpeg_audio_mixrate = 44100
+bpy.context.scene.render.ffmpeg_audio_codec = "MP2"
diff --git a/release/scripts/presets/ffmpeg/VCD.py b/release/scripts/presets/ffmpeg/VCD.py
index 876fa2d8ba6..faf27efe9e6 100644
--- a/release/scripts/presets/ffmpeg/VCD.py
+++ b/release/scripts/presets/ffmpeg/VCD.py
@@ -14,6 +14,10 @@ else:
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_buffersize = 40 * 8
bpy.context.scene.render.ffmpeg_packetsize = 2324
bpy.context.scene.render.ffmpeg_muxrate = 2352 * 75 * 8
+
+bpy.context.scene.render.ffmpeg_audio_bitrate = 224
+bpy.context.scene.render.ffmpeg_audio_mixrate = 44100
+bpy.context.scene.render.ffmpeg_audio_codec = "MP2"
diff --git a/release/scripts/presets/ffmpeg/h264.py b/release/scripts/presets/ffmpeg/h264.py
index 74e6890a5d4..1cd5d61a926 100644
--- a/release/scripts/presets/ffmpeg/h264.py
+++ b/release/scripts/presets/ffmpeg/h264.py
@@ -12,6 +12,6 @@ else:
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_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
index 6ce9d4ea7ed..9a35227ad57 100644
--- a/release/scripts/presets/ffmpeg/theora.py
+++ b/release/scripts/presets/ffmpeg/theora.py
@@ -12,6 +12,6 @@ else:
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_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
index 0c8e3989451..fa64562e566 100644
--- a/release/scripts/presets/ffmpeg/xvid.py
+++ b/release/scripts/presets/ffmpeg/xvid.py
@@ -12,6 +12,6 @@ else:
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_buffersize = 224 * 8
bpy.context.scene.render.ffmpeg_packetsize = 2048
bpy.context.scene.render.ffmpeg_muxrate = 10080000
diff --git a/release/scripts/presets/interaction/maya.py b/release/scripts/presets/keyconfig/maya.py
index 4a40326325e..120597cdd2a 100644
--- a/release/scripts/presets/interaction/maya.py
+++ b/release/scripts/presets/keyconfig/maya.py
@@ -2,7 +2,7 @@
import bpy
wm = bpy.context.window_manager
-kc = wm.keyconfigs.new('Maya')
+kc = wm.keyconfigs.new('maya')
# Map 3D View
km = kc.keymaps.new('3D View', space_type='VIEW_3D', region_type='WINDOW', modal=False)
@@ -173,7 +173,7 @@ kmi = km.items.new('wm.context_set_enum', 'COMMA', 'PRESS', ctrl=True)
kmi.properties.data_path = 'space_data.pivot_point'
kmi.properties.value = 'MEDIAN_POINT'
kmi = km.items.new('wm.context_toggle', 'COMMA', 'PRESS', alt=True)
-kmi.properties.data_path = 'space_data.use_pivot_point_align'
+kmi.properties.data_path = 'space_data.use_pivot_point'
kmi = km.items.new('wm.context_toggle', 'Q', 'PRESS')
kmi.properties.data_path = 'space_data.show_manipulator'
kmi = km.items.new('wm.context_set_enum', 'PERIOD', 'PRESS')
@@ -314,7 +314,7 @@ kmi = km.items.new('mesh.faces_select_linked_flat', 'F', 'PRESS', shift=True, ct
kmi.properties.sharpness = 135.0
kmi = km.items.new('mesh.select_similar', 'G', 'PRESS', shift=True)
kmi = km.items.new('wm.call_menu', 'TAB', 'PRESS', ctrl=True)
-kmi.properties.name = 'VIEW3D_MT_edit_mesh_selection_mode'
+kmi.properties.name = 'VIEW3D_MT_edit_mesh_select_mode'
kmi = km.items.new('mesh.hide', 'H', 'PRESS')
kmi = km.items.new('mesh.hide', 'H', 'PRESS', shift=True)
kmi.properties.unselected = True
diff --git a/release/scripts/presets/render/HDV_1080p.py b/release/scripts/presets/render/HDV_1080p.py
index 7637648e53a..3ba32135c1d 100644
--- a/release/scripts/presets/render/HDV_1080p.py
+++ b/release/scripts/presets/render/HDV_1080p.py
@@ -5,4 +5,4 @@ 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
+bpy.context.scene.render.fps_base = 1.001
diff --git a/release/scripts/presets/render/HDV_NTSC_1080p.py b/release/scripts/presets/render/HDV_NTSC_1080p.py
new file mode 100644
index 00000000000..2dfa1e0fd1e
--- /dev/null
+++ b/release/scripts/presets/render/HDV_NTSC_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 = 30
+bpy.context.scene.render.fps_base = 1.001
diff --git a/release/scripts/presets/render/HDV_PAL_1080p.py b/release/scripts/presets/render/HDV_PAL_1080p.py
new file mode 100644
index 00000000000..d8b1c707607
--- /dev/null
+++ b/release/scripts/presets/render/HDV_PAL_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 = 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 d505be2b435..b2ee19ca125 100644
--- a/release/scripts/presets/sss/apple.py
+++ b/release/scripts/presets/sss/apple.py
@@ -1,3 +1,5 @@
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
+material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)
+
+material.subsurface_scattering.radius = 11.605, 3.884, 1.754
+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 53e199455c1..9acc2f3e25f 100644
--- a/release/scripts/presets/sss/chicken.py
+++ b/release/scripts/presets/sss/chicken.py
@@ -1,3 +1,5 @@
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
+material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)
+
+material.subsurface_scattering.radius = 9.436, 3.348, 1.790
+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 221739a30ab..c03cc0243d9 100644
--- a/release/scripts/presets/sss/cream.py
+++ b/release/scripts/presets/sss/cream.py
@@ -1,3 +1,5 @@
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
+material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)
+
+material.subsurface_scattering.radius = 15.028, 4.664, 2.541
+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 96d136dc271..b94c7cced27 100644
--- a/release/scripts/presets/sss/ketchup.py
+++ b/release/scripts/presets/sss/ketchup.py
@@ -1,3 +1,5 @@
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
+material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)
+
+material.subsurface_scattering.radius = 4.762, 0.575, 0.394
+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 cd68fd7d26f..c85719900e2 100644
--- a/release/scripts/presets/sss/marble.py
+++ b/release/scripts/presets/sss/marble.py
@@ -1,3 +1,5 @@
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
+material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)
+
+material.subsurface_scattering.radius = 8.509, 5.566, 3.951
+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 7a6c25db833..74807014bd3 100644
--- a/release/scripts/presets/sss/potato.py
+++ b/release/scripts/presets/sss/potato.py
@@ -1,3 +1,5 @@
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
+material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)
+
+material.subsurface_scattering.radius = 14.266, 7.228, 2.036
+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 5be37b820da..163659faf34 100644
--- a/release/scripts/presets/sss/skim_milk.py
+++ b/release/scripts/presets/sss/skim_milk.py
@@ -1,3 +1,5 @@
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
+material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)
+
+material.subsurface_scattering.radius = 18.424, 10.443, 3.502
+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 76dc64f61f9..ef284019637 100644
--- a/release/scripts/presets/sss/skin1.py
+++ b/release/scripts/presets/sss/skin1.py
@@ -1,3 +1,5 @@
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
+material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)
+
+material.subsurface_scattering.radius = 3.673, 1.367, 0.683
+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 6a72a782638..16a7d154309 100644
--- a/release/scripts/presets/sss/skin2.py
+++ b/release/scripts/presets/sss/skin2.py
@@ -1,3 +1,5 @@
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
+material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)
+
+material.subsurface_scattering.radius = 4.821, 1.694, 1.090
+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 59aaa135933..c11b18557e3 100644
--- a/release/scripts/presets/sss/whole_milk.py
+++ b/release/scripts/presets/sss/whole_milk.py
@@ -1,3 +1,5 @@
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
+material = (bpy.context.material.active_node_material if bpy.context.material.active_node_material else bpy.context.material)
+
+material.subsurface_scattering.radius = 10.899, 6.575, 2.508
+material.subsurface_scattering.color = 0.947, 0.931, 0.852
diff --git a/release/scripts/templates/addon_add_object.py b/release/scripts/templates/addon_add_object.py
new file mode 100644
index 00000000000..f4f1185e282
--- /dev/null
+++ b/release/scripts/templates/addon_add_object.py
@@ -0,0 +1,78 @@
+bl_info = {
+ "name": "New Object",
+ "author": "YourNameHere",
+ "version": (1, 0),
+ "blender": (2, 5, 5),
+ "api": 33333,
+ "location": "View3D > Add > Mesh > New Object",
+ "description": "Adds a new Mesh Object",
+ "warning": "",
+ "wiki_url": "",
+ "tracker_url": "",
+ "category": "Add Mesh"}
+
+
+import bpy
+from bpy.props import FloatVectorProperty
+from add_utils import AddObjectHelper, add_object_data
+from mathutils import Vector
+
+
+def add_object(self, context):
+ scale_x = self.scale.x
+ scale_y = self.scale.y
+
+ verts = [Vector((-1 * scale_x, 1 * scale_y, 0)),
+ Vector((1 * scale_x, 1 * scale_y, 0)),
+ Vector((1 * scale_x, -1 * scale_y, 0)),
+ Vector((-1 * scale_x, -1 * scale_y, 0)),
+ ]
+
+ edges = []
+ faces = [[0, 1, 2, 3]]
+
+ mesh_data = bpy.data.meshes.new(name='New Object Mesh')
+ mesh_data.from_pydata(verts, edges, faces)
+ add_object_data(context, mesh_data, operator=self)
+
+
+class OBJECT_OT_add_object(bpy.types.Operator, AddObjectHelper):
+ """Add a Mesh Object"""
+ bl_idname = "mesh.add_object"
+ bl_label = "Add Mesh Object"
+ bl_description = "Create a new Mesh Object"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ scale = FloatVectorProperty(name='scale',
+ default=(1.0, 1.0, 1.0),
+ subtype='TRANSLATION',
+ description='scaling')
+
+ def execute(self, context):
+
+ add_object(self, context)
+
+ return {'FINISHED'}
+
+
+#### REGISTER ####
+
+def add_object_button(self, context):
+ self.layout.operator(
+ OBJECT_OT_add_object.bl_idname,
+ text="Add Object",
+ icon="PLUGIN")
+
+
+def register():
+ bpy.utils.register_class(OBJECT_OT_add_object)
+ bpy.types.INFO_MT_mesh_add.append(add_object_button)
+
+
+def unregister():
+ bpy.utils.unregister_class(OBJECT_OT_add_object)
+ bpy.types.INFO_MT_mesh_add.remove(add_object_button)
+
+
+if __name__ == '__main__':
+ register()
diff --git a/release/scripts/templates/background_job.py b/release/scripts/templates/background_job.py
new file mode 100644
index 00000000000..0337f8f4922
--- /dev/null
+++ b/release/scripts/templates/background_job.py
@@ -0,0 +1,114 @@
+# This script is an example of how you can run blender from the command line (in background mode with no interface)
+# to automate tasks, in this example it creates a text object, camera and light, then renders and/or saves it.
+# This example also shows how you can parse command line options to python scripts.
+#
+# Example usage for this test.
+# blender --background --factory-startup --python $HOME/background_job.py -- --text="Hello World" --render="/tmp/hello" --save="/tmp/hello.blend"
+#
+# Notice:
+# '--factory-startup' is used to avoid the user default settings from interfearing with automated scene generation.
+# '--' causes blender to ignore all following arguments so python can use them.
+#
+# See blender --help for details.
+
+import bpy
+
+
+def example_function(body_text, save_path, render_path):
+
+ scene = bpy.context.scene
+
+ # Clear existing objects.
+ scene.camera = None
+ for obj in scene.objects:
+ scene.objects.unlink(obj)
+
+ txt_data = bpy.data.curves.new(name="MyText", type='FONT')
+
+ # Text Object
+ txt_ob = bpy.data.objects.new(name="MyText", object_data=txt_data)
+ scene.objects.link(txt_ob) # add the data to the scene as an object
+ txt_data.body = body_text # set the body text to the command line arg given
+ txt_data.align = 'CENTER' # center text
+
+ # Camera
+ cam_data = bpy.data.cameras.new("MyCam") # create new camera data
+ cam_ob = bpy.data.objects.new(name="MyCam", object_data=cam_data)
+ scene.objects.link(cam_ob) # add the camera data to the scene (creating a new object)
+ scene.camera = cam_ob # set the active camera
+ cam_ob.location = 0.0, 0.0, 10.0
+
+ # Lamp
+ lamp_data = bpy.data.lamps.new("MyLamp", 'POINT')
+ lamp_ob = bpy.data.objects.new(name="MyCam", object_data=lamp_data)
+ scene.objects.link(lamp_ob)
+ lamp_ob.location = 2.0, 2.0, 5.0
+
+ if save_path:
+ try:
+ f = open(save_path, 'w')
+ f.close()
+ ok = True
+ except:
+ print("Cannot save to path %r" % save_path)
+
+ import traceback
+ traceback.print_exc()
+
+ if ok:
+ bpy.ops.wm.save_as_mainfile(filepath=save_path)
+
+ if render_path:
+ render = scene.render
+ render.use_file_extension = True
+ render.filepath = render_path
+ bpy.ops.render.render(write_still=True)
+
+
+import sys # to get command line args
+import optparse # to parse options for us and print a nice help message
+
+
+def main():
+
+ # get the args passed to blender after "--", all of which are ignored by blender specifically
+ # so python may receive its own arguments
+ argv = sys.argv
+
+ if "--" not in argv:
+ argv = [] # as if no args are passed
+ else:
+ argv = argv[argv.index("--") + 1:] # get all args after "--"
+
+ # When --help or no args are given, print this help
+ usage_text = "Run blender in background mode with this script:"
+ usage_text += " blender --background --python " + __file__ + " -- [options]"
+
+ parser = optparse.OptionParser(usage=usage_text)
+
+ # Example background utility, add some text and renders or saves it (with options)
+ # Possible types are: string, int, long, choice, float and complex.
+ parser.add_option("-t", "--text", dest="body_text", help="This text will be used to render an image", type="string")
+
+ parser.add_option("-s", "--save", dest="save_path", help="Save the generated file to the specified path", metavar='FILE')
+ parser.add_option("-r", "--render", dest="render_path", help="Render an image to the specified path", metavar='FILE')
+
+ options, args = parser.parse_args(argv) # In this example we wont use the args
+
+ if not argv:
+ parser.print_help()
+ return
+
+ if not options.body_text:
+ print("Error: --text=\"some string\" argument not given, aborting.")
+ parser.print_help()
+ return
+
+ # Run the example function
+ example_function(options.body_text, options.save_path, options.render_path)
+
+ print("batch job finished, exiting")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/release/scripts/templates/builtin_keyingset.py b/release/scripts/templates/builtin_keyingset.py
new file mode 100644
index 00000000000..0b808e9cd26
--- /dev/null
+++ b/release/scripts/templates/builtin_keyingset.py
@@ -0,0 +1,38 @@
+import bpy
+from keyingsets_utils import *
+
+
+class BUILTIN_KSI_hello(bpy.types.KeyingSetInfo):
+ bl_label = "Hello World KeyingSet"
+
+ # poll - test for whether Keying Set can be used at all
+ def poll(ksi, context):
+ return (context.active_object) or (context.selected_objects)
+
+ # iterator - go over all relevant data, calling generate()
+ def iterator(ksi, context, ks):
+ for ob in context.selected_objects:
+ ksi.generate(context, ks, ob)
+
+ # generator - populate Keying Set with property paths to use
+ def generate(ksi, context, ks, data):
+ id_block = data.id_data
+
+ ks.paths.add(id_block, "location")
+
+ for i in range(5):
+ ks.paths.add(id_block, "layers", i, group_method='NAMED', group_name="5x Hello Layers")
+
+ ks.paths.add(id_block, "show_x_ray", group_method='NONE')
+
+
+def register():
+ bpy.utils.register_class(BUILTIN_KSI_hello)
+
+
+def unregister():
+ bpy.utils.unregister_class(BUILTIN_KSI_hello)
+
+
+if __name__ == '__main__':
+ register()
diff --git a/release/scripts/templates/gamelogic.py b/release/scripts/templates/gamelogic.py
index 21a901c091b..c6d15850a4e 100644
--- a/release/scripts/templates/gamelogic.py
+++ b/release/scripts/templates/gamelogic.py
@@ -1,10 +1,7 @@
# This script must be assigned to a python controller
# where it can access the object that owns it and the sensors/actuators that it connects to.
-# GameLogic has been added to the global namespace no need to import
-
-# for keyboard event comparison
-# import GameKeys
+import bge
# support for Vector(), Matrix() types and advanced functions like Matrix.Scale(...) and Matrix.Rotation(...)
# import mathutils
@@ -12,8 +9,9 @@
# for functions like getWindowWidth(), getWindowHeight()
# import Rasterizer
+
def main():
- cont = GameLogic.getCurrentController()
+ cont = bge.logic.getCurrentController()
# The KX_GameObject that owns this controller.
own = cont.owner
@@ -21,7 +19,6 @@ def main():
# for scripts that deal with spacial logic
own_pos = own.worldPosition
-
# Some example functions, remove to write your own script.
# check for a positive sensor, will run on any object without errors.
print('Logic info for KX_GameObject', own.name)
@@ -55,14 +52,12 @@ def main():
# sens_key = cont.sensors['key_sensor']
# actu_motion = cont.actuators['motion']
-
# Loop through all other objects in the scene
- sce = GameLogic.getCurrentScene()
+ sce = bge.logic.getCurrentScene()
print('Scene Objects:', sce.name)
for ob in sce.objects:
print(' ', ob.name, ob.worldPosition)
-
# Example where collision objects are checked for their properties
# adding to our objects "life" property
"""
diff --git a/release/scripts/templates/gamelogic_basic.py b/release/scripts/templates/gamelogic_basic.py
index 5e7d19672fe..dbfcf948b18 100644
--- a/release/scripts/templates/gamelogic_basic.py
+++ b/release/scripts/templates/gamelogic_basic.py
@@ -1,7 +1,9 @@
+import bge
+
def main():
- cont = GameLogic.getCurrentController()
+ cont = bge.logic.getCurrentController()
own = cont.owner
sens = cont.sensors['mySensor']
diff --git a/release/scripts/templates/gamelogic_module.py b/release/scripts/templates/gamelogic_module.py
index 5a61a3592dc..fcc8a8839c9 100644
--- a/release/scripts/templates/gamelogic_module.py
+++ b/release/scripts/templates/gamelogic_module.py
@@ -5,13 +5,14 @@
# * External text modules are supported as long as they are at
# the same location as the blendfile or one of its libraries.
-import GameLogic
+import bge
# variables defined here will only be set once when the
# module is first imported. Set object spesific vars
# inside the function if you intend to use the module
# with multiple objects.
+
def main(cont):
own = cont.owner
@@ -23,4 +24,4 @@ def main(cont):
else:
cont.deactivate(actu)
-# dont call main(GameLogic.getCurrentController()), the py controller will
+# dont call main(bge.logic.getCurrentController()), the py controller will
diff --git a/release/scripts/templates/operator.py b/release/scripts/templates/operator.py
deleted file mode 100644
index 822d888a96c..00000000000
--- a/release/scripts/templates/operator.py
+++ /dev/null
@@ -1,63 +0,0 @@
-import bpy
-
-def write_some_data(context, filepath, use_some_setting):
- print("running write_some_data...")
- pass
-
-from bpy.props import *
-
-class ExportSomeData(bpy.types.Operator):
- '''This appiers in the tooltip of the operator and in the generated docs.'''
- bl_idname = "export.some_data" # this is important since its how bpy.ops.export.some_data is constructed
- bl_label = "Export Some Data"
-
- # List of operator properties, the attributes will be assigned
- # to the class instance from the operator settings before calling.
-
- # TODO, add better example props
- 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.")),
- name="Example Enum",
- description="Choose between two items",
- default='OPT_A')
-
- @classmethod
- def poll(cls, context):
- return context.active_object != None
-
- def execute(self, context):
-
- # # Bug, currently isnt working
- #if not self.is_property_set("filepath"):
- # raise Exception("filename not set")
-
- write_some_data(self.filepath, context, self.use_setting)
-
- return {'FINISHED'}
-
- def invoke(self, context, event):
- wm = context.window_manager
-
- if True:
- # File selector
- wm.add_fileselect(self) # will run self.execute()
- return {'RUNNING_MODAL'}
- elif True:
- # search the enum
- wm.invoke_search_popup(self)
- return {'RUNNING_MODAL'}
- elif False:
- # Redo popup
- return wm.invoke_props_popup(self, event) #
- elif False:
- return self.execute(context)
-
-
-# Only needed if you want to add into a dynamic menu
-menu_func = lambda self, context: self.layout.operator("export.some_data", text="Example Exporter...")
-bpy.types.INFO_MT_file_export.append(menu_func)
-
-if __name__ == "__main__":
- bpy.ops.export.some_data('INVOKE_DEFAULT', filepath="/tmp/test.ply")
diff --git a/release/scripts/templates/operator_export.py b/release/scripts/templates/operator_export.py
new file mode 100644
index 00000000000..5390d32aeff
--- /dev/null
+++ b/release/scripts/templates/operator_export.py
@@ -0,0 +1,66 @@
+import bpy
+
+
+def write_some_data(context, filepath, use_some_setting):
+ print("running write_some_data...")
+ f = open(filepath, 'w')
+ f.write("Hello World %s" % use_some_setting)
+ f.close()
+
+ return {'FINISHED'}
+
+
+# ExportHelper is a helper class, defines filename and
+# invoke() function which calls the file selector.
+from io_utils import ExportHelper
+
+from bpy.props import *
+
+
+class ExportSomeData(bpy.types.Operator, ExportHelper):
+ '''This appiers in the tooltip of the operator and in the generated docs.'''
+ bl_idname = "export.some_data" # this is important since its how bpy.ops.export.some_data is constructed
+ bl_label = "Export Some Data"
+
+ # ExportHelper mixin class uses this
+ filename_ext = ".txt"
+
+ filter_glob = StringProperty(default="*.txt", options={'HIDDEN'})
+
+ # List of operator properties, the attributes will be assigned
+ # to the class instance from the operator settings before calling.
+ 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.")),
+ name="Example Enum",
+ description="Choose between two items",
+ default='OPT_A')
+
+ @classmethod
+ def poll(cls, context):
+ return context.active_object != None
+
+ def execute(self, context):
+ return write_some_data(context, self.filepath, self.use_setting)
+
+
+# Only needed if you want to add into a dynamic menu
+def menu_func_export(self, context):
+ self.layout.operator(ExportSomeData.bl_idname, text="Text Export Operator")
+
+
+def register():
+ bpy.utils.register_class(ExportSomeData)
+ bpy.types.INFO_MT_file_export.append(menu_func_export)
+
+
+def unregister():
+ bpy.utils.unregister_class(ExportSomeData)
+ bpy.types.INFO_MT_file_export.remove(menu_func_export)
+
+
+if __name__ == "__main__":
+ register()
+
+ # test call
+ bpy.ops.export.some_data('INVOKE_DEFAULT')
diff --git a/release/scripts/templates/operator_mesh_add.py b/release/scripts/templates/operator_mesh_add.py
new file mode 100644
index 00000000000..77d172b3068
--- /dev/null
+++ b/release/scripts/templates/operator_mesh_add.py
@@ -0,0 +1,106 @@
+import bpy
+
+
+def add_box(width, height, depth):
+ """
+ This function takes inputs and returns vertex and face arrays.
+ no actual mesh data creation is done here.
+ """
+
+ vertices = [1.0, 1.0, -1.0,
+ 1.0, -1.0, -1.0,
+ -1.0, -1.0, -1.0,
+ -1.0, 1.0, -1.0,
+ 1.0, 1.0, 1.0,
+ 1.0, -1.0, 1.0,
+ -1.0, -1.0, 1.0,
+ -1.0, 1.0, 1.0,
+ ]
+
+ faces = [0, 1, 2, 3,
+ 4, 7, 6, 5,
+ 0, 4, 5, 1,
+ 1, 5, 6, 2,
+ 2, 6, 7, 3,
+ 4, 0, 3, 7,
+ ]
+
+ # apply size
+ for i in range(0, len(vertices), 3):
+ vertices[i] *= width
+ vertices[i + 1] *= depth
+ vertices[i + 2] *= height
+
+ return vertices, faces
+
+
+from bpy.props import *
+
+
+class AddBox(bpy.types.Operator):
+ '''Add a simple box mesh'''
+ bl_idname = "mesh.primitive_box_add"
+ bl_label = "Add Box"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ width = FloatProperty(name="Width",
+ description="Box Width",
+ default=1.0, min=0.01, max=100.0)
+
+ height = FloatProperty(name="Height",
+ description="Box Height",
+ default=1.0, min=0.01, max=100.0)
+
+ depth = FloatProperty(name="Depth",
+ description="Box Depth",
+ default=1.0, min=0.01, max=100.0)
+
+ # generic transform props
+ view_align = BoolProperty(name="Align to View",
+ default=False)
+ location = FloatVectorProperty(name="Location",
+ subtype='TRANSLATION')
+ rotation = FloatVectorProperty(name="Rotation",
+ subtype='EULER')
+
+ def execute(self, context):
+
+ verts_loc, faces = add_box(self.width,
+ self.height,
+ self.depth,
+ )
+
+ mesh = bpy.data.meshes.new("Box")
+
+ mesh.vertices.add(len(verts_loc) // 3)
+ mesh.faces.add(len(faces) // 4)
+
+ mesh.vertices.foreach_set("co", verts_loc)
+ mesh.faces.foreach_set("vertices_raw", faces)
+ mesh.update()
+
+ # add the mesh as an object into the scene with this utility module
+ import add_object_utils
+ add_object_utils.object_data_add(context, mesh, operator=self)
+
+ return {'FINISHED'}
+
+
+def menu_func(self, context):
+ self.layout.operator(AddBox.bl_idname, icon='MESH_CUBE')
+
+
+def register():
+ bpy.utils.register_class(AddBox)
+ bpy.types.INFO_MT_mesh_add.append(menu_func)
+
+
+def unregister():
+ bpy.utils.unregister_class(AddBox)
+ bpy.types.INFO_MT_mesh_add.remove(menu_func)
+
+if __name__ == "__main__":
+ register()
+
+ # test call
+ bpy.ops.mesh.primitive_box_add()
diff --git a/release/scripts/templates/operator_modal.py b/release/scripts/templates/operator_modal.py
index 522f9fea050..6eb3843d6a6 100644
--- a/release/scripts/templates/operator_modal.py
+++ b/release/scripts/templates/operator_modal.py
@@ -1,6 +1,7 @@
import bpy
from bpy.props import *
+
class ModalOperator(bpy.types.Operator):
'''Move an object with the mouse, example.'''
bl_idname = "object.modal_operator"
@@ -25,7 +26,7 @@ class ModalOperator(bpy.types.Operator):
def invoke(self, context, event):
if context.object:
- context.window_manager.add_modal_handler(self)
+ context.window_manager.modal_handler_add(self)
self.first_mouse_x = event.mouse_x
self.first_value = context.object.location.x
return {'RUNNING_MODAL'}
@@ -34,5 +35,16 @@ class ModalOperator(bpy.types.Operator):
return {'CANCELLED'}
+def register():
+ bpy.utils.register_class(ModalOperator)
+
+
+def unregister():
+ bpy.utils.unregister_class(ModalOperator)
+
+
if __name__ == "__main__":
+ register()
+
+ # test call
bpy.ops.object.modal_operator()
diff --git a/release/scripts/templates/operator_modal_draw.py b/release/scripts/templates/operator_modal_draw.py
index 2a3db3e3018..e7a1f6e4ffe 100644
--- a/release/scripts/templates/operator_modal_draw.py
+++ b/release/scripts/templates/operator_modal_draw.py
@@ -2,10 +2,11 @@ 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.
+ font_id = 0 # XXX, need to find out how best to get this.
# draw some text
blf.position(font_id, 15, 30, 0)
@@ -52,7 +53,7 @@ class ModalDrawOperator(bpy.types.Operator):
def invoke(self, context, event):
if context.area.type == 'VIEW_3D':
- context.window_manager.add_modal_handler(self)
+ context.window_manager.modal_handler_add(self)
# Add the region OpenGL drawing callback
# draw in view space with 'POST_VIEW' and 'PRE_VIEW'
@@ -64,3 +65,14 @@ class ModalDrawOperator(bpy.types.Operator):
else:
self.report({'WARNING'}, "View3D not found, cannot run operator")
return {'CANCELLED'}
+
+
+def register():
+ bpy.utils.register_class(ModalDrawOperator)
+
+
+def unregister():
+ bpy.utils.unregister_class(ModalDrawOperator)
+
+if __name__ == "__main__":
+ register()
diff --git a/release/scripts/templates/operator_modal_view3d.py b/release/scripts/templates/operator_modal_view3d.py
index c116dd28b9e..c494f121017 100644
--- a/release/scripts/templates/operator_modal_view3d.py
+++ b/release/scripts/templates/operator_modal_view3d.py
@@ -2,6 +2,7 @@ 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"
@@ -9,7 +10,6 @@ class ViewOperator(bpy.types.Operator):
offset = FloatVectorProperty(name="Offset", size=3)
-
def execute(self, context):
v3d = context.space_data
rv3d = v3d.region_3d
@@ -23,12 +23,15 @@ class ViewOperator(bpy.types.Operator):
if event.type == 'MOUSEMOVE':
self.offset = (self._initial_mouse - Vector((event.mouse_x, event.mouse_y, 0.0))) * 0.02
self.execute(context)
+ context.area.header_text_set("Offset %.4f %.4f %.4f" % tuple(self.offset))
elif event.type == 'LEFTMOUSE':
+ context.area.header_text_set()
return {'FINISHED'}
elif event.type in ('RIGHTMOUSE', 'ESC'):
rv3d.view_location = self._initial_location
+ context.area.header_text_set()
return {'CANCELLED'}
return {'RUNNING_MODAL'}
@@ -39,7 +42,7 @@ class ViewOperator(bpy.types.Operator):
v3d = context.space_data
rv3d = v3d.region_3d
- context.window_manager.add_modal_handler(self)
+ context.window_manager.modal_handler_add(self)
if rv3d.view_perspective == 'CAMERA':
rv3d.view_perspective = 'PERSP'
@@ -51,3 +54,15 @@ class ViewOperator(bpy.types.Operator):
else:
self.report({'WARNING'}, "Active space must be a View3d")
return {'CANCELLED'}
+
+
+def register():
+ bpy.utils.register_class(ViewOperator)
+
+
+def unregister():
+ bpy.utils.unregister_class(ViewOperator)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/release/scripts/templates/operator_simple.py b/release/scripts/templates/operator_simple.py
index 853bfa666eb..8348c7a95b1 100644
--- a/release/scripts/templates/operator_simple.py
+++ b/release/scripts/templates/operator_simple.py
@@ -1,11 +1,13 @@
import bpy
+
def main(context):
for ob in context.scene.objects:
print(ob)
+
class SimpleOperator(bpy.types.Operator):
- ''''''
+ '''Tooltip'''
bl_idname = "object.simple_operator"
bl_label = "Simple Object Operator"
@@ -18,5 +20,16 @@ class SimpleOperator(bpy.types.Operator):
return {'FINISHED'}
+def register():
+ bpy.utils.register_class(SimpleOperator)
+
+
+def unregister():
+ bpy.utils.unregister_class(SimpleOperator)
+
+
if __name__ == "__main__":
+ register()
+
+ # test call
bpy.ops.object.simple_operator()
diff --git a/release/scripts/templates/operator_uv.py b/release/scripts/templates/operator_uv.py
index 305496e31ce..93fec117fa1 100644
--- a/release/scripts/templates/operator_uv.py
+++ b/release/scripts/templates/operator_uv.py
@@ -1,5 +1,6 @@
import bpy
+
def main(context):
obj = context.active_object
mesh = obj.data
@@ -8,9 +9,10 @@ def main(context):
if is_editmode:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
-
if not mesh.uv_textures:
uvtex = bpy.ops.mesh.uv_texture_add()
+ else:
+ uvtex = mesh.uv_textures.active
# adjust UVs
for i, uv in enumerate(uvtex.data):
@@ -20,7 +22,6 @@ def main(context):
# apply the location of the vertex as a UV
uvs[j][:] = mesh.vertices[v_idx].co.xy
-
if is_editmode:
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
@@ -40,5 +41,16 @@ class UvOperator(bpy.types.Operator):
return {'FINISHED'}
+def register():
+ bpy.utils.register_class(UvOperator)
+
+
+def unregister():
+ bpy.utils.unregister_class(UvOperator)
+
+
if __name__ == "__main__":
+ register()
+
+ # test call
bpy.ops.uv.simple_operator()
diff --git a/release/scripts/templates/panel_simple.py b/release/scripts/templates/panel_simple.py
index 7c73e58a3e5..ddbd4eb7aa4 100644
--- a/release/scripts/templates/panel_simple.py
+++ b/release/scripts/templates/panel_simple.py
@@ -1,5 +1,6 @@
import bpy
+
class OBJECT_PT_hello(bpy.types.Panel):
bl_label = "Hello World Panel"
bl_space_type = "PROPERTIES"
@@ -18,3 +19,15 @@ class OBJECT_PT_hello(bpy.types.Panel):
row.label(text="Active object is: " + obj.name)
row = layout.row()
row.prop(obj, "name")
+
+
+def register():
+ bpy.utils.register_class(OBJECT_PT_hello)
+
+
+def unregister():
+ bpy.utils.unregister_class(OBJECT_PT_hello)
+
+
+if __name__ == "__main__":
+ register()
diff --git a/release/scripts/ui/properties_animviz.py b/release/scripts/ui/properties_animviz.py
index 87925a9d6f4..5f5684f5c89 100644
--- a/release/scripts/ui/properties_animviz.py
+++ b/release/scripts/ui/properties_animviz.py
@@ -94,12 +94,13 @@ class OnionSkinButtonsPanel():
# NOTE:
# The specialised panel types are derived in their respective UI modules
+# dont register these classes since they are only helpers.
def register():
- pass
+ pass # bpy.utils.register_module(__name__)
def unregister():
- pass
+ pass # bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_data_armature.py b/release/scripts/ui/properties_data_armature.py
index 5cb7016a908..6550e1bb1ed 100644
--- a/release/scripts/ui/properties_data_armature.py
+++ b/release/scripts/ui/properties_data_armature.py
@@ -42,13 +42,10 @@ class DATA_PT_context_arm(ArmatureButtonsPanel, bpy.types.Panel):
arm = context.armature
space = context.space_data
- split = layout.split(percentage=0.65)
if ob:
- split.template_ID(ob, "data")
- split.separator()
+ layout.template_ID(ob, "data")
elif arm:
- split.template_ID(space, "pin_id")
- split.separator()
+ layout.template_ID(space, "pin_id")
class DATA_PT_skeleton(ArmatureButtonsPanel, bpy.types.Panel):
@@ -101,7 +98,8 @@ class DATA_PT_display(ArmatureButtonsPanel, bpy.types.Panel):
col = split.column()
col.prop(arm, "show_group_colors", text="Colors")
- col.prop(ob, "show_x_ray", text="X-Ray")
+ if ob:
+ col.prop(ob, "show_x_ray", text="X-Ray")
col.prop(arm, "use_deform_delay", text="Delay Refresh")
@@ -287,14 +285,15 @@ class DATA_PT_onion_skinning(OnionSkinButtonsPanel): # , bpy.types.Panel): # in
class DATA_PT_custom_props_arm(ArmatureButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "object.data"
+ _property_type = bpy.types.Armature
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_data_armature_rigify.py b/release/scripts/ui/properties_data_armature_rigify.py
deleted file mode 100644
index f7961821277..00000000000
--- a/release/scripts/ui/properties_data_armature_rigify.py
+++ /dev/null
@@ -1,325 +0,0 @@
-# ##### 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 bpy.props import *
-
-
-class PoseTemplate(bpy.types.IDPropertyGroup):
- name = StringProperty(name="Name of the slave", description="", maxlen=64, default="")
-
-
-class PoseTemplateSettings(bpy.types.IDPropertyGroup):
- templates = CollectionProperty(type=PoseTemplate, name="Templates", description="")
- active_template_index = IntProperty(name="Index of the active slave", description="", default=-1, min=-1, max=65535)
- use_generate_deform_rig = BoolProperty(name="Create Deform Rig", description="Create a copy of the metarig, constrainted by the generated rig", default=False)
-
-
-def metarig_templates():
- import rigify
- return rigify.get_submodule_types()
-
-
-class DATA_PT_template(bpy.types.Panel):
- bl_label = "Meta-Rig Templates"
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "data"
- bl_options = {'DEFAULT_CLOSED'}
-
- templates = []
-
- @classmethod
- def poll(cls, context):
- if not context.armature:
- return False
- obj = context.object
- if obj:
- return (obj.mode in ('POSE', 'OBJECT'))
- return False
-
- def draw(self, context):
- layout = self.layout
- try:
- active_type = context.active_pose_bone["type"]
- except:
- active_type = None
-
- scene = context.scene
- pose_templates = scene.pose_templates
-
- if pose_templates.active_template_index == -1:
- pose_templates.active_template_index = 0
-
- if not self.templates:
- self.templates[:] = metarig_templates()
-
- while(len(pose_templates.templates) < len(self.templates)):
- pose_templates.templates.add()
- while(len(pose_templates.templates) > len(self.templates)):
- pose_templates.templates.remove(0)
-
- for i, template_name in enumerate(self.templates):
- template = pose_templates.templates[i]
- if active_type == template_name:
- template.name = "<%s>" % template_name.replace("_", " ")
- else:
- template.name = " %s " % template_name.replace("_", " ")
-
- row = layout.row()
- row.operator("pose.metarig_generate", text="Generate")
- row.operator("pose.metarig_validate", text="Check")
- row.operator("pose.metarig_graph", text="Graph")
- row = layout.row()
- row.prop(pose_templates, "use_generate_deform_rig")
-
- row = layout.row()
- col = row.column()
- col.template_list(pose_templates, "templates", pose_templates, "active_template_index", rows=1)
-
- subrow = col.split(percentage=0.5, align=True)
- subsubrow = subrow.row(align=True)
- subsubrow.operator("pose.metarig_assign", text="Assign")
- subsubrow.operator("pose.metarig_clear", text="Clear")
-
- if self.templates:
- subsubrow = subrow.split(percentage=0.8)
- subsubrow.operator("pose.metarig_sample_add", text="Sample").metarig_type = self.templates[pose_templates.active_template_index]
- subsubrow.operator("pose.metarig_sample_add", text="All").metarig_type = "" # self.templates[pose_templates.active_template_index]
-
- sub = row.column(align=True)
- sub.operator("pose.metarig_reload", icon="FILE_REFRESH", text="")
-
-
-class Reload(bpy.types.Operator):
- '''Re-Scan the metarig package directory for scripts'''
-
- bl_idname = "pose.metarig_reload"
- bl_label = "Re-Scan the list of metarig types"
-
- def execute(self, context):
- DATA_PT_template.templates[:] = metarig_templates()
- return {'FINISHED'}
-
-
-def rigify_report_exception(operator, exception):
- import traceback
- import sys
- import os
- # find the module name where the error happened
- # hint, this is the metarig type!
- exceptionType, exceptionValue, exceptionTraceback = sys.exc_info()
- fn = traceback.extract_tb(exceptionTraceback)[-1][0]
- fn = os.path.basename(fn)
- fn = os.path.splitext(fn)[0]
- message = []
- if fn.startswith("__"):
- message.append("Incorrect armature...")
- else:
- message.append("Incorrect armature for type '%s'" % fn)
- message.append(exception.message)
-
- message.reverse() # XXX - stupid! menu's are upside down!
-
- operator.report(set(['INFO']), '\n'.join(message))
-
-
-class Generate(bpy.types.Operator):
- '''Generates a metarig from the active armature'''
-
- bl_idname = "pose.metarig_generate"
- bl_label = "Generate Metarig"
-
- def execute(self, context):
- import rigify
- reload(rigify)
-
- meta_def = context.scene.pose_templates.use_generate_deform_rig
-
- try:
- rigify.generate_rig(context, context.object, META_DEF=meta_def)
- except rigify.RigifyError as rig_exception:
- rigify_report_exception(self, rig_exception)
-
- return {'FINISHED'}
-
-
-class Validate(bpy.types.Operator):
- '''Validate a metarig from the active armature'''
-
- bl_idname = "pose.metarig_validate"
- bl_label = "Validate Metarig"
-
- def execute(self, context):
- import rigify
- reload(rigify)
- try:
- rigify.validate_rig(context, context.object)
- except rigify.RigifyError as rig_exception:
- rigify_report_exception(self, rig_exception)
- return {'FINISHED'}
-
-
-class Sample(bpy.types.Operator):
- '''Create a sample metarig to be modified before generating the final rig.'''
-
- bl_idname = "pose.metarig_sample_add"
- bl_label = "Re-Scan Metarig Scripts"
-
- metarig_type = StringProperty(name="Type", description="Name of the rig type to generate a sample of, a blank string for all", maxlen=128, default="")
-
- def execute(self, context):
- import rigify
- reload(rigify)
- final = (self.metarig_type == "")
- objects = rigify.generate_test(context, metarig_type=self.metarig_type, GENERATE_FINAL=final)
-
- if len(objects) > 1:
- for i, (obj_meta, obj_gen) in enumerate(objects):
- obj_meta.location.x = i * 1.0
- if obj_gen:
- obj_gen.location.x = i * 1.0
-
- return {'FINISHED'}
-
-
-class Graph(bpy.types.Operator):
- '''Create a graph from the active armature through graphviz'''
-
- bl_idname = "pose.metarig_graph"
- bl_label = "Pose Graph"
-
- def execute(self, context):
- import os
- import graphviz_export
- import bpy
- reload(graphviz_export)
- obj = bpy.context.object
- path = os.path.splitext(bpy.data.filepath)[0] + "-" + bpy.path.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)
-
- if saved:
- # if we seriously want this working everywhere we'll need some new approach
- os.system("dot -Tpng %s > %s; gnome-open %s &" % (path_dot, path_png, path_png))
- #os.system("python /b/xdot.py '%s' &" % path_dot)
-
- return {'FINISHED'}
-
-
-class AsScript(bpy.types.Operator):
- '''Write the edit armature out as a python script'''
-
- bl_idname = "pose.metarig_to_script"
- bl_label = "Write Metarig to Script"
- bl_options = {'REGISTER', 'UNDO'}
-
- 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.filepath
- file = open(path, "w")
- file.write(code)
- file.close()
-
- return {'FINISHED'}
-
- def invoke(self, context, event):
- import os
- obj = context.object
- self.filepath = os.path.splitext(bpy.data.filepath)[0] + "-" + bpy.path.clean_name(obj.name) + ".py"
- wm = context.window_manager
- wm.add_fileselect(self)
- return {'RUNNING_MODAL'}
-
-
-# operators that use the GUI
-class ActiveAssign(bpy.types.Operator):
- '''Assign to the active posebone'''
-
- bl_idname = "pose.metarig_assign"
- bl_label = "Assign to the active posebone"
-
- @classmethod
- def poll(cls, context):
- bone = context.active_pose_bone
- return bool(bone and bone.id_data.mode == 'POSE')
-
- def execute(self, context):
- scene = context.scene
- pose_templates = scene.pose_templates
- template_name = DATA_PT_template.templates[pose_templates.active_template_index]
- context.active_pose_bone["type"] = template_name
- return {'FINISHED'}
-
-
-class ActiveClear(bpy.types.Operator):
- '''Clear type from the active posebone'''
-
- bl_idname = "pose.metarig_clear"
- bl_label = "Metarig Clear Type"
-
- @classmethod
- def poll(cls, context):
- bone = context.active_pose_bone
- return bool(bone and bone.id_data.mode == 'POSE')
-
- def execute(self, context):
- scene = context.scene
- try:
- del context.active_pose_bone["type"]
- except:
- return {'CANCELLED'}
- return {'FINISHED'}
-
-
-class INFO_MT_armature_metarig_add(bpy.types.Menu):
- bl_idname = "INFO_MT_armature_metarig_add"
- bl_label = "Meta-Rig"
-
- def draw(self, context):
- import rigify
-
- layout = self.layout
- layout.operator_context = 'INVOKE_REGION_WIN'
-
- for submodule_type in rigify.get_submodule_types():
- text = bpy.path.display_name(submodule_type)
- layout.operator("pose.metarig_sample_add", text=text, icon='OUTLINER_OB_ARMATURE').metarig_type = submodule_type
-
-menu_func = (lambda self, context: self.layout.menu("INFO_MT_armature_metarig_add", icon='OUTLINER_OB_ARMATURE'))
-import space_info # ensure the menu is loaded first
-
-
-def register():
- bpy.types.Scene.pose_templates = PointerProperty(type=PoseTemplateSettings, name="Pose Templates", description="Pose Template Settings")
- space_info.INFO_MT_armature_add.append(menu_func)
-
-
-def unregister():
- del bpy.types.Scene.pose_templates
- space_info.INFO_MT_armature_add.remove(menu_func)
-
-if __name__ == "__main__":
- register()
diff --git a/release/scripts/ui/properties_data_bone.py b/release/scripts/ui/properties_data_bone.py
index 3ed05d914ed..feca4fc2502 100644
--- a/release/scripts/ui/properties_data_bone.py
+++ b/release/scripts/ui/properties_data_bone.py
@@ -50,27 +50,22 @@ class BONE_PT_context_bone(BoneButtonsPanel, bpy.types.Panel):
class BONE_PT_transform(BoneButtonsPanel, bpy.types.Panel):
bl_label = "Transform"
+ @classmethod
+ def poll(cls, context):
+ if context.edit_bone:
+ return True
+
+ ob = context.object
+ return ob and ob.mode == 'POSE' and context.bone
+
def draw(self, context):
layout = self.layout
ob = context.object
bone = context.bone
- if not bone:
- bone = context.edit_bone
- row = layout.row()
- row.column().prop(bone, "head")
- row.column().prop(bone, "tail")
-
- col = row.column()
- sub = col.column(align=True)
- sub.label(text="Roll:")
- sub.prop(bone, "roll", text="")
- sub.label()
- sub.prop(bone, "lock")
-
- else:
- pchan = ob.pose.bones[context.bone.name]
+ if bone and ob:
+ pchan = ob.pose.bones[bone.name]
row = layout.row()
col = row.column()
@@ -92,6 +87,19 @@ class BONE_PT_transform(BoneButtonsPanel, bpy.types.Panel):
layout.prop(pchan, "rotation_mode")
+ elif context.edit_bone:
+ bone = context.edit_bone
+ row = layout.row()
+ row.column().prop(bone, "head")
+ row.column().prop(bone, "tail")
+
+ col = row.column()
+ sub = col.column(align=True)
+ sub.label(text="Roll:")
+ sub.prop(bone, "roll", text="")
+ sub.label()
+ sub.prop(bone, "lock")
+
class BONE_PT_transform_locks(BoneButtonsPanel, bpy.types.Panel):
bl_label = "Transform Locks"
@@ -99,14 +107,15 @@ class BONE_PT_transform_locks(BoneButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
- return context.bone
+ ob = context.object
+ return ob and ob.mode == 'POSE' and context.bone
def draw(self, context):
layout = self.layout
ob = context.object
bone = context.bone
- pchan = ob.pose.bones[context.bone.name]
+ pchan = ob.pose.bones[bone.name]
row = layout.row()
col = row.column()
@@ -134,12 +143,12 @@ class BONE_PT_relations(BoneButtonsPanel, bpy.types.Panel):
ob = context.object
bone = context.bone
arm = context.armature
+ pchan = None
- if not bone:
+ if ob and bone:
+ pchan = ob.pose.bones[bone.name]
+ elif bone is None:
bone = context.edit_bone
- pchan = None
- else:
- pchan = ob.pose.bones[context.bone.name]
split = layout.split()
@@ -163,7 +172,7 @@ class BONE_PT_relations(BoneButtonsPanel, bpy.types.Panel):
sub = col.column()
sub.active = (bone.parent is not None)
sub.prop(bone, "use_connect")
- sub.prop(bone, "use_hinge", text="Inherit Rotation")
+ sub.prop(bone, "use_inherit_rotation", text="Inherit Rotation")
sub.prop(bone, "use_inherit_scale", text="Inherit Scale")
sub = col.column()
sub.active = (not bone.parent or not bone.use_connect)
@@ -178,31 +187,33 @@ class BONE_PT_display(BoneButtonsPanel, bpy.types.Panel):
return context.bone
def draw(self, context):
+ # note. this works ok in editmode but isnt
+ # all that useful so disabling for now.
layout = self.layout
ob = context.object
bone = context.bone
+ pchan = None
- if not bone:
+ if ob and bone:
+ pchan = ob.pose.bones[bone.name]
+ elif bone is None:
bone = context.edit_bone
- pchan = None
- else:
- pchan = ob.pose.bones[context.bone.name]
-
- if ob and pchan:
+ if bone:
split = layout.split()
col = split.column()
col.prop(bone, "show_wire", text="Wireframe")
col.prop(bone, "hide", text="Hide")
- col = split.column()
+ if pchan:
+ col = split.column()
- col.label(text="Custom Shape:")
- col.prop(pchan, "custom_shape", text="")
- if pchan.custom_shape:
- col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones", text="At")
+ col.label(text="Custom Shape:")
+ col.prop(pchan, "custom_shape", text="")
+ if pchan.custom_shape:
+ col.prop_search(pchan, "custom_shape_transform", ob.pose, "bones", text="At")
class BONE_PT_inverse_kinematics(BoneButtonsPanel, bpy.types.Panel):
@@ -211,7 +222,8 @@ class BONE_PT_inverse_kinematics(BoneButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
- return context.active_pose_bone
+ ob = context.object
+ return ob and ob.mode == 'POSE' and context.bone
def draw(self, context):
layout = self.layout
@@ -346,6 +358,7 @@ class BONE_PT_deform(BoneButtonsPanel, bpy.types.Panel):
class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+ _property_type = bpy.types.Bone, bpy.types.EditBone, bpy.types.PoseBone
@property
def _context_path(self):
@@ -357,11 +370,11 @@ class BONE_PT_custom_props(BoneButtonsPanel, PropertyPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_data_camera.py b/release/scripts/ui/properties_data_camera.py
index f7a7ec6b7a9..0f5d4a59bf5 100644
--- a/release/scripts/ui/properties_data_camera.py
+++ b/release/scripts/ui/properties_data_camera.py
@@ -69,7 +69,7 @@ class DATA_PT_camera(CameraButtonsPanel, bpy.types.Panel):
col = split.column()
if cam.type == 'PERSP':
if cam.lens_unit == 'MILLIMETERS':
- col.prop(cam, "lens", text="Angle")
+ col.prop(cam, "lens")
elif cam.lens_unit == 'DEGREES':
col.prop(cam, "angle")
col = split.column()
@@ -135,14 +135,15 @@ class DATA_PT_camera_display(CameraButtonsPanel, bpy.types.Panel):
class DATA_PT_custom_props_camera(CameraButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "object.data"
+ _property_type = bpy.types.Camera
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_data_curve.py b/release/scripts/ui/properties_data_curve.py
index 1d8034c6add..b26b7140fd2 100644
--- a/release/scripts/ui/properties_data_curve.py
+++ b/release/scripts/ui/properties_data_curve.py
@@ -28,7 +28,7 @@ class CurveButtonsPanel():
@classmethod
def poll(cls, context):
- return (context.object and context.object.type in ('CURVE', 'SURFACE', 'TEXT') and context.curve)
+ return (context.object and context.object.type in ('CURVE', 'SURFACE', 'FONT') and context.curve)
class CurveButtonsPanelCurve(CurveButtonsPanel):
@@ -59,14 +59,10 @@ class DATA_PT_context_curve(CurveButtonsPanel, bpy.types.Panel):
curve = context.curve
space = context.space_data
- split = layout.split(percentage=0.65)
-
if ob:
- split.template_ID(ob, "data")
- split.separator()
+ layout.template_ID(ob, "data")
elif curve:
- split.template_ID(space, "pin_id")
- split.separator()
+ layout.template_ID(space, "pin_id") # XXX: broken
class DATA_PT_shape_curve(CurveButtonsPanel, bpy.types.Panel):
@@ -79,7 +75,7 @@ class DATA_PT_shape_curve(CurveButtonsPanel, bpy.types.Panel):
curve = context.curve
is_surf = (ob.type == 'SURFACE')
is_curve = (ob.type == 'CURVE')
- is_text = (ob.type == 'TEXT')
+ is_text = (ob.type == 'FONT')
if is_curve:
row = layout.row()
@@ -103,8 +99,9 @@ class DATA_PT_shape_curve(CurveButtonsPanel, bpy.types.Panel):
col = split.column()
if is_surf:
- sub = col.column(align=True)
+ sub = col.column()
sub.label(text="")
+ sub = col.column(align=True)
sub.prop(curve, "resolution_v", text="Preview V")
sub.prop(curve, "render_resolution_v", text="Render V")
@@ -114,10 +111,10 @@ class DATA_PT_shape_curve(CurveButtonsPanel, bpy.types.Panel):
sub.label(text="Fill:")
sub.prop(curve, "use_fill_front")
sub.prop(curve, "use_fill_back")
- sub.prop(curve, "use_fill_deform", text="Use Deformed")
+ sub.prop(curve, "use_fill_deform", text="Fill Deformed")
col.label(text="Textures:")
- col.prop(curve, "use_map_on_length")
+ col.prop(curve, "use_uv_as_generated")
col.prop(curve, "use_auto_texspace")
@@ -261,7 +258,7 @@ class DATA_PT_font(CurveButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
- return (context.object and context.object.type == 'TEXT' and context.curve)
+ return (context.object and context.object.type == 'FONT' and context.curve)
def draw(self, context):
layout = self.layout
@@ -269,7 +266,18 @@ class DATA_PT_font(CurveButtonsPanel, bpy.types.Panel):
text = context.curve
char = context.curve.edit_format
- layout.template_ID(text, "font", open="font.open", unlink="font.unlink")
+ row = layout.split(percentage=0.25)
+ row.label(text="Regular")
+ row.template_ID(text, "font", open="font.open", unlink="font.unlink")
+ row = layout.split(percentage=0.25)
+ row.label(text="Bold")
+ row.template_ID(text, "font_bold", open="font.open", unlink="font.unlink")
+ row = layout.split(percentage=0.25)
+ row.label(text="Italic")
+ row.template_ID(text, "font_italic", open="font.open", unlink="font.unlink")
+ row = layout.split(percentage=0.25)
+ row.label(text="Bold & Italic")
+ row.template_ID(text, "font_bold_italic", open="font.open", unlink="font.unlink")
#layout.prop(text, "font")
@@ -317,7 +325,7 @@ class DATA_PT_paragraph(CurveButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
- return (context.object and context.object.type == 'TEXT' and context.curve)
+ return (context.object and context.object.type == 'FONT' and context.curve)
def draw(self, context):
layout = self.layout
@@ -346,7 +354,7 @@ class DATA_PT_textboxes(CurveButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
- return (context.object and context.object.type == 'TEXT' and context.curve)
+ return (context.object and context.object.type == 'FONT' and context.curve)
def draw(self, context):
layout = self.layout
@@ -384,14 +392,15 @@ class DATA_PT_textboxes(CurveButtonsPanel, bpy.types.Panel):
class DATA_PT_custom_props_curve(CurveButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "object.data"
+ _property_type = bpy.types.Curve
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_data_empty.py b/release/scripts/ui/properties_data_empty.py
index 9a297eba4af..bb0028efec5 100644
--- a/release/scripts/ui/properties_data_empty.py
+++ b/release/scripts/ui/properties_data_empty.py
@@ -44,11 +44,11 @@ class DATA_PT_empty(DataButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_data_lamp.py b/release/scripts/ui/properties_data_lamp.py
index 72e95989b06..55781434763 100644
--- a/release/scripts/ui/properties_data_lamp.py
+++ b/release/scripts/ui/properties_data_lamp.py
@@ -390,14 +390,15 @@ class DATA_PT_falloff_curve(DataButtonsPanel, bpy.types.Panel):
class DATA_PT_custom_props_lamp(DataButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "object.data"
+ _property_type = bpy.types.Lamp
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_data_lattice.py b/release/scripts/ui/properties_data_lattice.py
index 469bd07b691..6bdb36d3520 100644
--- a/release/scripts/ui/properties_data_lattice.py
+++ b/release/scripts/ui/properties_data_lattice.py
@@ -85,14 +85,15 @@ class DATA_PT_lattice(DataButtonsPanel, bpy.types.Panel):
class DATA_PT_custom_props_lattice(DataButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "object.data"
+ _property_type = bpy.types.Lattice
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_data_mesh.py b/release/scripts/ui/properties_data_mesh.py
index 38364139147..342204d0e78 100644
--- a/release/scripts/ui/properties_data_mesh.py
+++ b/release/scripts/ui/properties_data_mesh.py
@@ -33,6 +33,7 @@ class MESH_MT_vertex_group_specials(bpy.types.Menu):
layout.operator("object.vertex_group_copy_to_linked", icon='LINK_AREA')
layout.operator("object.vertex_group_copy_to_selected", icon='LINK_AREA')
layout.operator("object.vertex_group_mirror", icon='ARROW_LEFTRIGHT')
+ layout.operator("object.vertex_group_remove", icon='X', text="Delete All").all = True
class MESH_MT_shape_key_specials(bpy.types.Menu):
@@ -70,13 +71,10 @@ class DATA_PT_context_mesh(MeshButtonsPanel, bpy.types.Panel):
mesh = context.mesh
space = context.space_data
- split = layout.split(percentage=0.65)
if ob:
- split.template_ID(ob, "data")
- split.separator()
+ layout.template_ID(ob, "data")
elif mesh:
- split.template_ID(space, "pin_id")
- split.separator()
+ layout.template_ID(space, "pin_id")
class DATA_PT_normals(MeshButtonsPanel, bpy.types.Panel):
@@ -111,6 +109,7 @@ class DATA_PT_settings(MeshButtonsPanel, bpy.types.Panel):
mesh = context.mesh
layout.prop(mesh, "texture_mesh")
+ layout.prop(mesh, "use_auto_texspace")
class DATA_PT_vertex_groups(MeshButtonsPanel, bpy.types.Panel):
@@ -182,7 +181,7 @@ class DATA_PT_shape_keys(MeshButtonsPanel, bpy.types.Panel):
enable_edit = ob.mode != 'EDIT'
enable_edit_value = False
- if ob.show_shape_key is False:
+ if ob.show_only_shape_key is False:
if enable_edit or (ob.type == 'MESH' and ob.use_shape_key_edit_mode):
enable_edit_value = True
@@ -218,7 +217,7 @@ class DATA_PT_shape_keys(MeshButtonsPanel, bpy.types.Panel):
sub = row.row(align=True)
subsub = sub.row(align=True)
subsub.active = enable_edit_value
- subsub.prop(ob, "show_shape_key", text="")
+ subsub.prop(ob, "show_only_shape_key", text="")
subsub.prop(kb, "mute", text="")
sub.prop(ob, "use_shape_key_edit_mode", text="")
@@ -286,7 +285,7 @@ class DATA_PT_texface(MeshButtonsPanel, bpy.types.Panel):
ob = context.active_object
rd = context.scene.render
- return (context.mode == 'EDIT_MESH') and (rd.engine == 'BLENDER_GAME') and ob and ob.type == 'MESH'
+ return (context.mode == 'EDIT_MESH') and ob and ob.type == 'MESH'
def draw(self, context):
layout = self.layout
@@ -297,6 +296,9 @@ class DATA_PT_texface(MeshButtonsPanel, bpy.types.Panel):
tf = me.faces.active_tface
if tf:
+ if context.scene.render.engine != 'BLENDER_GAME':
+ col.label(text="Options only supported in Game Engine")
+
split = layout.split()
col = split.column()
@@ -349,14 +351,15 @@ class DATA_PT_vertex_colors(MeshButtonsPanel, bpy.types.Panel):
class DATA_PT_custom_props_mesh(MeshButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "object.data"
+ _property_type = bpy.types.Mesh
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_data_metaball.py b/release/scripts/ui/properties_data_metaball.py
index b4bf8dc5d70..cf7aa8c08fd 100644
--- a/release/scripts/ui/properties_data_metaball.py
+++ b/release/scripts/ui/properties_data_metaball.py
@@ -42,13 +42,10 @@ class DATA_PT_context_metaball(DataButtonsPanel, bpy.types.Panel):
mball = context.meta_ball
space = context.space_data
- split = layout.split(percentage=0.65)
if ob:
- split.template_ID(ob, "data")
- split.separator()
+ layout.template_ID(ob, "data")
elif mball:
- split.template_ID(space, "pin_id")
- split.separator()
+ layout.template_ID(space, "pin_id")
class DATA_PT_metaball(DataButtonsPanel, bpy.types.Panel):
@@ -118,14 +115,15 @@ class DATA_PT_metaball_element(DataButtonsPanel, bpy.types.Panel):
class DATA_PT_custom_props_metaball(DataButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "object.data"
+ _property_type = bpy.types.MetaBall
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_data_modifier.py b/release/scripts/ui/properties_data_modifier.py
index f659b254fd8..f17cd8a4b98 100644
--- a/release/scripts/ui/properties_data_modifier.py
+++ b/release/scripts/ui/properties_data_modifier.py
@@ -52,24 +52,22 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel):
col = split.column()
col.label(text="Object:")
col.prop(md, "object", text="")
+ col.prop(md, "use_deform_preserve_volume")
col = split.column()
- col.label(text="Vertex Group::")
+ col.label(text="Bind To:")
+ col.prop(md, "use_vertex_groups", text="Vertex Groups")
+ col.prop(md, "use_bone_envelopes", text="Bone Envelopes")
+
+ split = layout.split()
+
+ col = split.split()
col.prop_search(md, "vertex_group", ob, "vertex_groups", text="")
sub = col.column()
sub.active = bool(md.vertex_group)
sub.prop(md, "invert_vertex_group")
- split = layout.split()
-
- col = split.column()
- col.label(text="Bind To:")
- col.prop(md, "use_vertex_groups", text="Vertex Groups")
- col.prop(md, "use_bone_envelopes", text="Bone Envelopes")
-
- col = split.column()
- col.label(text="Deformation:")
- col.prop(md, "use_deform_preserve_volume")
+ col = layout.column()
col.prop(md, "use_multi_modifier")
def ARRAY(self, layout, ob, md):
@@ -365,7 +363,6 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel):
col.prop(md, "use_dynamic_bind")
def MIRROR(self, layout, ob, md):
- layout.prop(md, "merge_threshold")
split = layout.split(percentage=0.25)
col = split.column()
@@ -376,6 +373,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel):
col = split.column()
col.label(text="Options:")
+ col.prop(md, "use_mirror_merge", text="Merge")
col.prop(md, "use_clip", text="Clipping")
col.prop(md, "use_mirror_vertex_groups", text="Vertex Groups")
@@ -385,6 +383,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel):
col.prop(md, "use_mirror_v", text="V")
col = layout.column()
+
+ if md.use_mirror_merge == True:
+ col.prop(md, "merge_threshold")
col.label(text="Mirror Object:")
col.prop(md, "mirror_object", text="")
@@ -411,6 +412,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel):
col.operator("object.multires_subdivide", text="Subdivide")
col.operator("object.multires_higher_levels_delete", text="Delete Higher")
col.operator("object.multires_reshape", text="Reshape")
+ col.operator("object.multires_base_apply", text="Apply Base")
col.prop(md, "show_only_control_edges")
layout.separator()
@@ -707,11 +709,11 @@ class DATA_PT_modifiers(ModifierButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_game.py b/release/scripts/ui/properties_game.py
index f8f88586bdd..60934891b7f 100644
--- a/release/scripts/ui/properties_game.py
+++ b/release/scripts/ui/properties_game.py
@@ -72,7 +72,6 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, bpy.types.Panel):
col = split.column()
sub = col.column()
- sub.active = (game.physics_type == 'RIGID_BODY')
sub.prop(game, "use_anisotropic_friction")
subsub = sub.column()
subsub.active = game.use_anisotropic_friction
@@ -149,6 +148,21 @@ class PHYSICS_PT_game_physics(PhysicsButtonsPanel, bpy.types.Panel):
col.prop(game, "use_ghost")
col.prop(ob, "hide_render", text="Invisible")
+ layout.separator()
+
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Attributes:")
+ col.prop(game, "radius")
+
+ col = split.column()
+ sub = col.column()
+ sub.prop(game, "use_anisotropic_friction")
+ subsub = sub.column()
+ subsub.active = game.use_anisotropic_friction
+ subsub.prop(game, "friction_coefficients", text="", slider=True)
+
elif game.physics_type in ('SENSOR', 'INVISIBLE', 'NO_COLLISION', 'OCCLUDE'):
layout.prop(ob, "hide_render", text="Invisible")
@@ -353,21 +367,25 @@ class RENDER_PT_game_performance(RenderButtonsPanel, bpy.types.Panel):
layout = self.layout
gs = context.scene.game_settings
+ row = layout.row()
+ row.prop(gs, "use_frame_rate")
+ row.prop(gs, "use_display_lists")
- split = layout.split()
- col = split.column()
- col.label(text="Show:")
- col.prop(gs, "show_debug_properties", text="Debug Properties")
- col.prop(gs, "show_framerate_profile", text="Framerate and Profile")
- col.prop(gs, "show_physics_visualization", text="Physics Visualization")
- col.prop(gs, "use_deprecation_warnings")
+class RENDER_PT_game_display(RenderButtonsPanel, bpy.types.Panel):
+ bl_label = "Display"
+ COMPAT_ENGINES = {'BLENDER_GAME'}
- col = split.column()
+ def draw(self, context):
+ layout = self.layout
- col.label(text="Render:")
- col.prop(gs, "use_frame_rate")
- col.prop(gs, "use_display_lists")
+ gs = context.scene.game_settings
+ flow = layout.column_flow()
+ flow.prop(gs, "show_debug_properties", text="Debug Properties")
+ flow.prop(gs, "show_framerate_profile", text="Framerate and Profile")
+ flow.prop(gs, "show_physics_visualization", text="Physics Visualization")
+ flow.prop(gs, "use_deprecation_warnings")
+ flow.prop(gs, "show_mouse")
class RENDER_PT_game_sound(RenderButtonsPanel, bpy.types.Panel):
@@ -530,11 +548,11 @@ class WORLD_PT_game_physics_obstacles(WorldButtonsPanel, bpy.types.Panel):
layout.prop(gs, "show_obstacle_simulation")
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_material.py b/release/scripts/ui/properties_material.py
index 82a52214b69..82c3e840420 100644
--- a/release/scripts/ui/properties_material.py
+++ b/release/scripts/ui/properties_material.py
@@ -269,7 +269,7 @@ class MATERIAL_PT_shading(MaterialButtonsPanel, bpy.types.Panel):
def poll(cls, context):
mat = active_node_mat(context.material)
engine = context.scene.render.engine
- return mat and (mat.type in ('SURFACE', 'WIRE', 'HALO')) and (engine in cls.COMPAT_ENGINES)
+ return mat and (mat.type in ('SURFACE', 'WIRE')) and (engine in cls.COMPAT_ENGINES)
def draw(self, context):
layout = self.layout
@@ -294,9 +294,6 @@ class MATERIAL_PT_shading(MaterialButtonsPanel, bpy.types.Panel):
sub.prop(mat, "use_tangent_shading")
sub.prop(mat, "use_cubic")
- elif mat.type == 'HALO':
- layout.prop(mat, "alpha")
-
class MATERIAL_PT_transp(MaterialButtonsPanel, bpy.types.Panel):
bl_label = "Transparency"
@@ -486,14 +483,30 @@ class MATERIAL_PT_halo(MaterialButtonsPanel, bpy.types.Panel):
mat = context.material # dont use node material
halo = mat.halo
+ def number_but(layout, toggle, number, name, color):
+ row = layout.row(align=True)
+ row.prop(halo, toggle, text="")
+ sub = row.column()
+ sub.active = getattr(halo, toggle)
+ sub.prop(halo, number, text=name)
+ if not color == "":
+ sub.prop(mat, color, text="")
+
split = layout.split()
col = split.column()
+ col.prop(mat, "alpha")
col.prop(mat, "diffuse_color", text="")
+
+ col = split.column()
col.prop(halo, "size")
col.prop(halo, "hardness")
col.prop(halo, "add")
- col.label(text="Options:")
+
+ layout.label(text="Options:")
+
+ split = layout.split()
+ col = split.column()
col.prop(halo, "use_texture")
col.prop(halo, "use_vertex_normal")
col.prop(halo, "use_extreme_alpha")
@@ -501,22 +514,9 @@ class MATERIAL_PT_halo(MaterialButtonsPanel, bpy.types.Panel):
col.prop(halo, "use_soft")
col = split.column()
- col.prop(halo, "use_ring")
- sub = col.column()
- sub.active = halo.use_ring
- sub.prop(halo, "ring_count")
- sub.prop(mat, "mirror_color", text="")
- col.separator()
- col.prop(halo, "use_lines")
- sub = col.column()
- sub.active = halo.use_lines
- sub.prop(halo, "line_count", text="Lines")
- sub.prop(mat, "specular_color", text="")
- col.separator()
- col.prop(halo, "use_star")
- sub = col.column()
- sub.active = halo.use_star
- sub.prop(halo, "star_tip_count")
+ number_but(col, "use_ring", "ring_count", "Rings", "mirror_color")
+ number_but(col, "use_lines", "line_count", "Lines", "specular_color")
+ number_but(col, "use_star", "star_tip_count", "Star tips", "")
class MATERIAL_PT_flare(MaterialButtonsPanel, bpy.types.Panel):
@@ -622,9 +622,8 @@ class MATERIAL_PT_strand(MaterialButtonsPanel, bpy.types.Panel):
col.separator()
sub = col.column()
sub.active = (not mat.use_shadeless)
- sub.prop(tan, "use_surface_diffuse")
+ sub.label("Surface diffuse:")
sub = col.column()
- sub.active = tan.use_surface_diffuse
sub.prop(tan, "blend_distance", text="Distance")
@@ -893,14 +892,15 @@ class MATERIAL_PT_volume_options(VolumeButtonsPanel, bpy.types.Panel):
class MATERIAL_PT_custom_props(MaterialButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "material"
+ _property_type = bpy.types.Material
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_object.py b/release/scripts/ui/properties_object.py
index dd242723cac..30380e2d338 100644
--- a/release/scripts/ui/properties_object.py
+++ b/release/scripts/ui/properties_object.py
@@ -36,11 +36,11 @@ class OBJECT_PT_context_object(ObjectButtonsPanel, bpy.types.Panel):
space = context.space_data
ob = context.object
- row = layout.row()
- row.label(text="", icon='OBJECT_DATA')
if space.use_pin_id:
- row.template_ID(space, "pin_id")
+ layout.template_ID(space, "pin_id")
else:
+ row = layout.row()
+ row.label(text="", icon='OBJECT_DATA')
row.prop(ob, "name", text="")
@@ -70,6 +70,32 @@ class OBJECT_PT_transform(ObjectButtonsPanel, bpy.types.Panel):
layout.prop(ob, "rotation_mode")
+class OBJECT_PT_delta_transform(ObjectButtonsPanel, bpy.types.Panel):
+ bl_label = "Delta Transform"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+
+ ob = context.object
+
+ row = layout.row()
+
+ row.column().prop(ob, "delta_location")
+ if ob.rotation_mode == 'QUATERNION':
+ row.column().prop(ob, "delta_rotation_quaternion", text="Rotation")
+ elif ob.rotation_mode == 'AXIS_ANGLE':
+ #row.column().label(text="Rotation")
+ #row.column().prop(pchan, "delta_rotation_angle", text="Angle")
+ #row.column().prop(pchan, "delta_rotation_axis", text="Axis")
+ #row.column().prop(ob, "delta_rotation_axis_angle", text="Rotation")
+ row.column().label(text="Not for Axis-Angle")
+ else:
+ row.column().prop(ob, "delta_rotation_euler", text="Rotation")
+
+ row.column().prop(ob, "delta_scale")
+
+
class OBJECT_PT_transform_locks(ObjectButtonsPanel, bpy.types.Panel):
bl_label = "Transform Locks"
bl_options = {'DEFAULT_CLOSED'}
@@ -192,7 +218,8 @@ class OBJECT_PT_display(ObjectButtonsPanel, bpy.types.Panel):
col = split.column()
col.prop(ob, "show_texture_space", text="Texture Space")
col.prop(ob, "show_x_ray", text="X-Ray")
- col.prop(ob, "show_transparent", text="Transparency")
+ if ob.type == 'MESH':
+ col.prop(ob, "show_transparent", text="Transparency")
class OBJECT_PT_duplication(ObjectButtonsPanel, bpy.types.Panel):
@@ -251,9 +278,6 @@ class OBJECT_PT_animation(ObjectButtonsPanel, bpy.types.Panel):
col.label(text="Time Offset:")
col.prop(ob, "use_time_offset_edit", text="Edit")
row = col.row()
- row.prop(ob, "use_time_offset_particle", text="Particle")
- row.active = bool(ob.particle_systems)
- row = col.row()
row.prop(ob, "use_time_offset_parent", text="Parent")
row.active = (ob.parent is not None)
row = col.row()
@@ -312,17 +336,18 @@ class OBJECT_PT_onion_skinning(OnionSkinButtonsPanel): # , bpy.types.Panel): #
self.draw_settings(context, ob.animation_visualisation)
-class OBJECT_PT_custom_props(bpy.types.Panel, PropertyPanel, ObjectButtonsPanel):
+class OBJECT_PT_custom_props(ObjectButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "object"
+ _property_type = bpy.types.Object
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_object_constraint.py b/release/scripts/ui/properties_object_constraint.py
index 3908b00cde6..4b9c2885277 100644
--- a/release/scripts/ui/properties_object_constraint.py
+++ b/release/scripts/ui/properties_object_constraint.py
@@ -61,7 +61,7 @@ class ConstraintButtonsPanel():
if con.target.type == 'ARMATURE':
layout.prop_search(con, "subtarget", con.target.data, "bones", text="Bone")
- if con.type in ('COPY_LOCATION', 'STRETCH_TO', 'TRACK_TO', 'PIVOT'):
+ if hasattr(con, "head_tail"):
row = layout.row()
row.label(text="Head/Tail:")
row.prop(con, "head_tail", text="")
@@ -551,7 +551,36 @@ class ConstraintButtonsPanel():
col.prop(con, "axis_y", text="Y")
col.prop(con, "axis_z", text="Z")
- #Missing: Limit arrays (not wrapped in RNA yet)
+ if con.pivot_type == 'CONE_TWIST':
+ layout.label(text="Limits:")
+ split = layout.split()
+
+ col = split.column(align=True)
+ col.prop(con, "use_angular_limit_x", text="Angular X")
+ col.prop(con, "use_angular_limit_y", text="Angular Y")
+ col.prop(con, "use_angular_limit_z", text="Angular Z")
+
+ col = split.column()
+ col.prop(con, "limit_cone_min", text="")
+ col = split.column()
+ col.prop(con, "limit_cone_max", text="")
+
+ elif con.pivot_type == 'GENERIC_6_DOF':
+ layout.label(text="Limits:")
+ split = layout.split()
+
+ col = split.column(align=True)
+ col.prop(con, "use_limit_x", text="X")
+ col.prop(con, "use_limit_y", text="Y")
+ col.prop(con, "use_limit_z", text="Z")
+ col.prop(con, "use_angular_limit_x", text="Angular X")
+ col.prop(con, "use_angular_limit_y", text="Angular Y")
+ col.prop(con, "use_angular_limit_z", text="Angular Z")
+
+ col = split.column()
+ col.prop(con, "limit_generic_min", text="")
+ col = split.column()
+ col.prop(con, "limit_generic_max", text="")
def CLAMP_TO(self, context, layout, con):
self.target_template(layout, con)
@@ -624,7 +653,7 @@ class ConstraintButtonsPanel():
self.space_template(layout, con)
def SHRINKWRAP(self, context, layout, con):
- self.target_template(layout, con)
+ self.target_template(layout, con, False)
layout.prop(con, "distance")
layout.prop(con, "shrinkwrap_type")
@@ -675,7 +704,7 @@ class ConstraintButtonsPanel():
col.prop(con, "rotation_range", text="Pivot When")
def SCRIPT(self, context, layout, con):
- layout.label("blender 2.5 has no py-constraints")
+ layout.label("Blender 2.5 has no py-constraints")
class OBJECT_PT_constraints(ConstraintButtonsPanel, bpy.types.Panel):
@@ -691,7 +720,12 @@ class OBJECT_PT_constraints(ConstraintButtonsPanel, bpy.types.Panel):
ob = context.object
- layout.operator_menu_enum("object.constraint_add", "type")
+ if ob.mode == 'POSE':
+ box = layout.box()
+ box.alert = True
+ box.label(icon='INFO', text="See Bone Constraints tab to Add Constraints to active bone")
+ else:
+ layout.operator_menu_enum("object.constraint_add", "type")
for con in ob.constraints:
self.draw_constraint(context, con)
@@ -715,11 +749,11 @@ class BONE_PT_constraints(ConstraintButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_particle.py b/release/scripts/ui/properties_particle.py
index bd6d2e13c88..4bed2e81629 100644
--- a/release/scripts/ui/properties_particle.py
+++ b/release/scripts/ui/properties_particle.py
@@ -27,7 +27,11 @@ from properties_physics_common import basic_force_field_falloff_ui
def particle_panel_enabled(context, psys):
- return (psys.point_cache.is_baked is False) and (not psys.is_edited) and (not context.particle_system_editable)
+ phystype = psys.settings.physics_type
+ if psys.settings.type in ('EMITTER', 'REACTOR') and phystype in ('NO', 'KEYED'):
+ return True
+ else:
+ return (psys.point_cache.is_baked is False) and (not psys.is_edited) and (not context.particle_system_editable)
def particle_panel_poll(cls, context):
@@ -37,7 +41,7 @@ def particle_panel_poll(cls, context):
return False
if psys.settings is None:
return False
- return psys.settings.type in ('EMITTER', 'REACTOR', 'HAIR') and (engine in cls.COMPAT_ENGINES)
+ return psys.settings.is_fluid == False and (engine in cls.COMPAT_ENGINES)
class ParticleButtonsPanel():
@@ -91,22 +95,24 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, bpy.types.Panel):
split = layout.split(percentage=0.32)
col = split.column()
col.label(text="Name:")
- if part.type in ('EMITTER', 'REACTOR', 'HAIR'):
+ if part.is_fluid == False:
col.label(text="Settings:")
col.label(text="Type:")
col = split.column()
col.prop(psys, "name", text="")
- if part.type in ('EMITTER', 'REACTOR', 'HAIR'):
- col.template_ID(psys, "settings", new="particle.new")
+ if part.is_fluid == False:
+ row = col.row()
+ row.enabled = particle_panel_enabled(context, psys)
+ row.template_ID(psys, "settings", new="particle.new")
#row = layout.row()
#row.label(text="Viewport")
#row.label(text="Render")
if part:
- if part.type not in ('EMITTER', 'REACTOR', 'HAIR'):
- layout.label(text="No settings for fluid particles")
+ if part.is_fluid:
+ layout.label(text=str(part.count) + " fluid particles for this frame.")
return
row = col.row()
@@ -119,7 +125,10 @@ class PARTICLE_PT_context_particles(ParticleButtonsPanel, bpy.types.Panel):
if psys.is_edited:
split.operator("particle.edited_clear", text="Free Edit")
else:
- split.label(text="")
+ row = split.row()
+ row.enabled = particle_panel_enabled(context, psys)
+ row.prop(part, "regrow_hair")
+ row.prop(part, "use_advanced_hair")
row = split.row()
row.enabled = particle_panel_enabled(context, psys)
row.prop(part, "hair_step")
@@ -142,10 +151,16 @@ class PARTICLE_PT_emission(ParticleButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
+ psys = context.particle_system
+ if psys is None:
+ return False
+ if psys.settings is None:
+ return False
+ if psys.settings.is_fluid:
+ return False
if particle_panel_poll(PARTICLE_PT_emission, context):
return not context.particle_system.point_cache.use_external
- else:
- return False
+ return False
def draw(self, context):
layout = self.layout
@@ -159,6 +174,10 @@ class PARTICLE_PT_emission(ParticleButtonsPanel, bpy.types.Panel):
row.active = part.distribution != 'GRID'
row.prop(part, "count")
+ if part.type == 'HAIR' and not part.use_advanced_hair:
+ row.prop(part, "hair_length")
+ return
+
if part.type != 'HAIR':
split = layout.split()
@@ -176,8 +195,10 @@ class PARTICLE_PT_emission(ParticleButtonsPanel, bpy.types.Panel):
row.prop(part, "emit_from", expand=True)
row = layout.row()
- row.prop(part, "use_emit_random")
- if part.distribution != 'GRID':
+ if part.distribution == 'GRID':
+ row.prop(part, "invert_grid")
+ else:
+ row.prop(part, "use_emit_random")
row.prop(part, "use_even_distribution")
if part.emit_from == 'FACE' or part.emit_from == 'VOLUME':
@@ -192,6 +213,7 @@ class PARTICLE_PT_emission(ParticleButtonsPanel, bpy.types.Panel):
row.prop(part, "jitter_factor", text="Jittering Amount", slider=True)
elif part.distribution == 'GRID':
row.prop(part, "grid_resolution")
+ row.prop(part, "grid_random", text="Random", slider=True)
class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, bpy.types.Panel):
@@ -228,7 +250,7 @@ class PARTICLE_PT_hair_dynamics(ParticleButtonsPanel, bpy.types.Panel):
#part = psys.settings
cloth = psys.cloth.settings
- layout.enabled = psys.use_hair_dynamics
+ layout.enabled = psys.use_hair_dynamics and psys.point_cache.is_baked == False
split = layout.split()
@@ -265,15 +287,17 @@ class PARTICLE_PT_cache(ParticleButtonsPanel, bpy.types.Panel):
return False
if psys.settings is None:
return False
+ if psys.settings.is_fluid:
+ return False
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.use_hair_dynamics)) and engine in cls.COMPAT_ENGINES
+ return (psys.settings.type in ('EMITTER', 'REACTOR') or (psys.settings.type == 'HAIR' and (psys.use_hair_dynamics or psys.point_cache.is_baked))) and engine in cls.COMPAT_ENGINES
def draw(self, context):
psys = context.particle_system
- point_cache_ui(self, context, psys.point_cache, True, 'HAIR' if psys.use_hair_dynamics else 'PSYS')
+ point_cache_ui(self, context, psys.point_cache, True, 'HAIR' if (psys.settings.type == 'HAIR') else 'PSYS')
class PARTICLE_PT_velocity(ParticleButtonsPanel, bpy.types.Panel):
@@ -284,6 +308,8 @@ class PARTICLE_PT_velocity(ParticleButtonsPanel, bpy.types.Panel):
def poll(cls, context):
if particle_panel_poll(PARTICLE_PT_velocity, context):
psys = context.particle_system
+ if psys.settings.type == 'HAIR' and not psys.settings.use_advanced_hair:
+ return False
return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.use_external
else:
return False
@@ -332,6 +358,8 @@ class PARTICLE_PT_rotation(ParticleButtonsPanel, bpy.types.Panel):
def poll(cls, context):
if particle_panel_poll(PARTICLE_PT_rotation, context):
psys = context.particle_system
+ if psys.settings.type == 'HAIR' and not psys.settings.use_advanced_hair:
+ return False
return psys.settings.physics_type != 'BOIDS' and not psys.point_cache.use_external
else:
return False
@@ -374,7 +402,10 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
if particle_panel_poll(PARTICLE_PT_physics, context):
- return not context.particle_system.point_cache.use_external
+ psys = context.particle_system
+ if psys.settings.type == 'HAIR' and not psys.settings.use_advanced_hair:
+ return False
+ return not psys.point_cache.use_external
else:
return False
@@ -437,24 +468,32 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
split = layout.split()
sub = split.column()
sub.label(text="Fluid Interaction:")
- sub.prop(fluid, "fluid_radius", slider=True)
- sub.prop(fluid, "stiffness")
- sub.prop(fluid, "stiffness_near")
- sub.prop(fluid, "rest_density")
+ sub.prop(fluid, "fluid_radius")
+ sub.prop(fluid, "repulsion_force")
+ subsub = sub.column(align=True)
+ subsub.prop(fluid, "rest_density")
+ subsub.prop(fluid, "density_force", text="Force")
sub.label(text="Viscosity:")
- sub.prop(fluid, "viscosity_omega", text="Linear")
- sub.prop(fluid, "viscosity_beta", text="Square")
+ subsub = sub.column(align=True)
+ subsub.prop(fluid, "linear_viscosity", text="Linear")
+ subsub.prop(fluid, "square_viscosity", text="Square")
sub = split.column()
sub.label(text="Springs:")
- sub.prop(fluid, "spring_force", text="Force", slider=True)
- sub.prop(fluid, "rest_length", slider=True)
- layout.label(text="Multiple fluids interactions:")
+ sub.prop(fluid, "spring_force", text="Force")
+ #Hidden to make ui a bit lighter, can be unhidden for a bit more control
+ #sub.prop(fluid, "rest_length", slider=True)
+ sub.prop(fluid, "use_viscoelastic_springs")
+ subsub = sub.column(align=True)
+ subsub.active = fluid.use_viscoelastic_springs
+ subsub.prop(fluid, "yield_ratio", slider=True)
+ subsub.prop(fluid, "plasticity", slider=True)
+ subsub.prop(fluid, "use_initial_rest_length")
sub.label(text="Buoyancy:")
- sub.prop(fluid, "buoyancy", slider=True)
+ sub.prop(fluid, "buoyancy", text="Strength", slider=True)
elif part.physics_type == 'KEYED':
split = layout.split()
@@ -518,6 +557,8 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
if part.physics_type == 'KEYED' or part.physics_type == 'BOIDS' or part.physics_type == 'FLUID':
if part.physics_type == 'BOIDS':
layout.label(text="Relations:")
+ elif part.physics_type == 'FLUID':
+ layout.label(text="Fluid interaction:")
row = layout.row()
row.template_list(psys, "targets", psys, "active_particle_target_index")
@@ -538,7 +579,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
if part.physics_type == 'KEYED':
col = row.column()
#doesn't work yet
- #col.red_alert = key.valid
+ #col.alert = key.valid
col.prop(key, "object", text="")
col.prop(key, "system", text="System")
col = row.column()
@@ -548,7 +589,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
elif part.physics_type == 'BOIDS':
sub = row.row()
#doesn't work yet
- #sub.red_alert = key.valid
+ #sub.alert = key.valid
sub.prop(key, "object", text="")
sub.prop(key, "system", text="System")
@@ -556,7 +597,7 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, bpy.types.Panel):
elif part.physics_type == 'FLUID':
sub = row.row()
#doesn't work yet
- #sub.red_alert = key.valid
+ #sub.alert = key.valid
sub.prop(key, "object", text="")
sub.prop(key, "system", text="System")
@@ -731,7 +772,7 @@ class PARTICLE_PT_render(ParticleButtonsPanel, bpy.types.Panel):
row = layout.row()
col = row.column()
- if part.type == 'HAIR' and part.use_strand_primitive == True and part.child_type == 'FACES':
+ if part.type == 'HAIR' and part.use_strand_primitive == True and part.child_type == 'INTERPOLATED':
layout.prop(part, "use_simplify")
if part.use_simplify == True:
row = layout.row()
@@ -917,60 +958,76 @@ class PARTICLE_PT_children(ParticleButtonsPanel, bpy.types.Panel):
col.prop(part, "child_nbr", text="Display")
col.prop(part, "rendered_child_count", text="Render")
- col = row.column(align=True)
-
- if part.child_type == 'FACES':
+ if part.child_type == 'INTERPOLATED':
+ col = row.column()
+ col.prop(psys, "child_seed", text="Seed")
col.prop(part, "virtual_parents", slider=True)
+ col.prop(part, "create_long_hair_children")
else:
- col.prop(part, "child_radius", text="Radius")
- col.prop(part, "child_roundness", text="Roundness", slider=True)
-
col = row.column(align=True)
col.prop(part, "child_size", text="Size")
col.prop(part, "child_size_random", text="Random")
- layout.row().label(text="Effects:")
-
- row = layout.row()
+ split = layout.split()
- col = row.column(align=True)
- col.prop(part, "clump_factor", slider=True)
- col.prop(part, "clump_shape", slider=True)
+ col = split.column()
+ col.label(text="Effects:")
- col = row.column(align=True)
- col.prop(part, "roughness_endpoint")
- col.prop(part, "roughness_end_shape")
+ sub = col.column(align=True)
+ sub.prop(part, "clump_factor", slider=True)
+ sub.prop(part, "clump_shape", slider=True)
- row = layout.row()
+ sub = col.column(align=True)
+ sub.prop(part, "child_length", slider=True)
+ sub.prop(part, "child_length_threshold", slider=True)
+
+ if part.child_type == 'SIMPLE':
+ sub = col.column(align=True)
+ sub.prop(part, "child_radius", text="Radius")
+ sub.prop(part, "child_roundness", text="Roundness", slider=True)
+ sub.prop(psys, "child_seed", text="Seed")
+ elif part.virtual_parents > 0.0:
+ sub = col.column(align=True)
+ sub.label(text="Parting not")
+ sub.label(text="available with")
+ sub.label(text="virtual parents.")
+ else:
+ sub = col.column(align=True)
+ sub.prop(part, "child_parting_factor", text="Parting", slider=True)
+ sub.prop(part, "child_parting_min", text="Min")
+ sub.prop(part, "child_parting_max", text="Max")
- col = row.column(align=True)
- col.prop(part, "roughness_1")
- col.prop(part, "roughness_1_size")
+ col = split.column()
+ col.label(text="Roughness:")
- col = row.column(align=True)
- col.prop(part, "roughness_2")
- col.prop(part, "roughness_2_size")
- col.prop(part, "roughness_2_threshold", slider=True)
+ sub = col.column(align=True)
+ sub.prop(part, "roughness_1", text="Uniform")
+ sub.prop(part, "roughness_1_size", text="Size")
- row = layout.row()
- col = row.column(align=True)
- col.prop(part, "child_length", slider=True)
- col.prop(part, "child_length_threshold", slider=True)
+ sub = col.column(align=True)
+ sub.prop(part, "roughness_endpoint", "Endpoint")
+ sub.prop(part, "roughness_end_shape")
- col = row.column(align=True)
- col.label(text="Space reserved for")
- col.label(text="hair parting controls")
+ sub = col.column(align=True)
+ sub.prop(part, "roughness_2", text="Random")
+ sub.prop(part, "roughness_2_size", text="Size")
+ sub.prop(part, "roughness_2_threshold", slider=True)
layout.row().label(text="Kink:")
layout.row().prop(part, "kink", expand=True)
split = layout.split()
+ split.active = part.kink != 'NO'
col = split.column()
- col.prop(part, "kink_amplitude")
- col.prop(part, "kink_frequency")
+ sub = col.column(align=True)
+ sub.prop(part, "kink_amplitude")
+ sub.prop(part, "kink_amplitude_clump", text="Clump", slider=True)
+ col.prop(part, "kink_flat", slider=True)
col = split.column()
- col.prop(part, "kink_shape", slider=True)
+ sub = col.column(align=True)
+ sub.prop(part, "kink_frequency")
+ sub.prop(part, "kink_shape", slider=True)
class PARTICLE_PT_field_weights(ParticleButtonsPanel, bpy.types.Panel):
@@ -978,12 +1035,20 @@ class PARTICLE_PT_field_weights(ParticleButtonsPanel, bpy.types.Panel):
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
+ @classmethod
+ def poll(cls, context):
+ return particle_panel_poll(cls, context)
+
def draw(self, context):
part = context.particle_system.settings
effector_weights_ui(self, context, part.effector_weights)
if part.type == 'HAIR':
- self.layout.prop(part.effector_weights, "apply_to_hair_growing")
+ row = self.layout.row()
+ row.prop(part.effector_weights, "apply_to_hair_growing")
+ row.prop(part, "apply_effector_to_children")
+ row = self.layout.row()
+ row.prop(part, "effect_hair", slider=True)
class PARTICLE_PT_force_fields(ParticleButtonsPanel, bpy.types.Panel):
@@ -1019,6 +1084,10 @@ class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, bpy.types.Panel):
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
+ @classmethod
+ def poll(cls, context):
+ return particle_panel_poll(cls, context)
+
def draw(self, context):
layout = self.layout
@@ -1085,14 +1154,15 @@ class PARTICLE_PT_vertexgroups(ParticleButtonsPanel, bpy.types.Panel):
class PARTICLE_PT_custom_props(ParticleButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER'}
_context_path = "particle_system.settings"
+ _property_type = bpy.types.ParticleSettings
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_physics_cloth.py b/release/scripts/ui/properties_physics_cloth.py
index 26670438b3f..0ac4429c71a 100644
--- a/release/scripts/ui/properties_physics_cloth.py
+++ b/release/scripts/ui/properties_physics_cloth.py
@@ -47,7 +47,7 @@ class PhysicButtonsPanel():
def poll(cls, 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) and (context.cloth)
class PHYSICS_PT_cloth(PhysicButtonsPanel, bpy.types.Panel):
@@ -59,21 +59,6 @@ class PHYSICS_PT_cloth(PhysicButtonsPanel, bpy.types.Panel):
md = context.cloth
ob = context.object
- split = layout.split()
-
- if md:
- # remove modifier + settings
- split.context_pointer_set("modifier", md)
- split.operator("object.modifier_remove", text="Remove")
-
- row = split.row(align=True)
- row.prop(md, "show_render", text="")
- row.prop(md, "show_viewport", text="")
- else:
- # add modifier
- split.operator("object.modifier_add", text="Add").type = 'CLOTH'
- split.label()
-
if md:
cloth = md.settings
@@ -232,11 +217,11 @@ class PHYSICS_PT_cloth_field_weights(PhysicButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_physics_common.py b/release/scripts/ui/properties_physics_common.py
index b5aee894562..3d854533506 100644
--- a/release/scripts/ui/properties_physics_common.py
+++ b/release/scripts/ui/properties_physics_common.py
@@ -20,8 +20,62 @@
import bpy
-#cachetype can be 'PSYS' 'HAIR' 'SMOKE' etc
+class PhysicButtonsPanel():
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "physics"
+
+ @classmethod
+ def poll(cls, context):
+ rd = context.scene.render
+ return (context.object) and (not rd.use_game_engine)
+
+
+def physics_add(self, layout, md, name, type, typeicon, toggles):
+ sub = layout.row(align=True)
+ if md:
+ sub.context_pointer_set("modifier", md)
+ sub.operator("object.modifier_remove", text=name, icon='X')
+ if(toggles):
+ sub.prop(md, "show_render", text="")
+ sub.prop(md, "show_viewport", text="")
+ else:
+ sub.operator("object.modifier_add", text=name, icon=typeicon).type = type
+
+
+class PHYSICS_PT_add(PhysicButtonsPanel, bpy.types.Panel):
+ bl_label = ""
+ bl_options = {'HIDE_HEADER'}
+
+ def draw(self, context):
+ ob = context.object
+
+ layout = self.layout
+ layout.label("Enable physics for:")
+ split = layout.split()
+ col = split.column()
+
+ if(context.object.field.type == 'NONE'):
+ col.operator("object.forcefield_toggle", text="Force Field", icon='FORCE_FORCE')
+ else:
+ col.operator("object.forcefield_toggle", text="Force Field", icon='X')
+
+ if(ob.type == 'MESH'):
+ physics_add(self, col, context.collision, "Collision", 'COLLISION', 'MOD_PHYSICS', False)
+ physics_add(self, col, context.cloth, "Cloth", 'CLOTH', 'MOD_CLOTH', True)
+
+ col = split.column()
+
+ if(ob.type == 'MESH' or ob.type == 'LATTICE'or ob.type == 'CURVE'):
+ physics_add(self, col, context.soft_body, "Soft Body", 'SOFT_BODY', 'MOD_SOFT', True)
+
+ if(ob.type == 'MESH'):
+ physics_add(self, col, context.fluid, "Fluid", 'FLUID_SIMULATION', 'MOD_FLUIDSIM', True)
+ physics_add(self, col, context.smoke, "Smoke", 'SMOKE', 'MOD_SMOKE', True)
+
+
+#cachetype can be 'PSYS' 'HAIR' 'SMOKE' etc
def point_cache_ui(self, context, cache, enabled, cachetype):
layout = self.layout
@@ -51,32 +105,44 @@ def point_cache_ui(self, context, cache, enabled, cachetype):
layout.label(text=cache.info)
else:
- layout.prop(cache, "name", text="File Name")
+ if cachetype == 'SMOKE':
+ if bpy.data.is_dirty:
+ layout.label(text="Cache is disabled until the file is saved")
+ layout.enabled = False
- split = layout.split()
- col = split.column(align=True)
+ if cache.use_disk_cache:
+ layout.prop(cache, "name", text="File Name")
+ else:
+ layout.prop(cache, "name", text="Cache Name")
+
+ row = layout.row(align=True)
if cachetype != 'PSYS':
- col.enabled = enabled
- col.prop(cache, "frame_start")
- col.prop(cache, "frame_end")
+ row.enabled = enabled
+ row.prop(cache, "frame_start")
+ row.prop(cache, "frame_end")
if cachetype not in ('SMOKE', 'CLOTH'):
- col.prop(cache, "frame_step")
-
- col = split.column()
+ row.prop(cache, "frame_step")
+ row.prop(cache, "use_quick_cache")
+ if cachetype != 'SMOKE':
+ layout.label(text=cache.info)
if cachetype != 'SMOKE':
- sub = col.column()
- sub.enabled = enabled
- sub.prop(cache, "use_quick_cache")
+ split = layout.split()
+ split.enabled = enabled and (not bpy.data.is_dirty)
+
+ col = split.column()
+ col.prop(cache, "use_disk_cache")
- sub = col.column()
- sub.enabled = (not bpy.data.is_dirty)
- sub.prop(cache, "use_disk_cache")
- col.label(text=cache.info)
+ col = split.column()
+ col.active = cache.use_disk_cache
+ col.prop(cache, "use_library_path", "Use Lib Path")
- sub = col.column()
- sub.prop(cache, "use_library_path", "Use Lib Path")
+ row = layout.row()
+ row.enabled = enabled and (not bpy.data.is_dirty)
+ row.active = cache.use_disk_cache
+ row.label(text="Compression:")
+ row.prop(cache, "compression", expand=True)
layout.separator()
@@ -213,11 +279,11 @@ def basic_force_field_falloff_ui(self, context, field):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_physics_field.py b/release/scripts/ui/properties_physics_field.py
index b5005a78c01..8a697806aa1 100644
--- a/release/scripts/ui/properties_physics_field.py
+++ b/release/scripts/ui/properties_physics_field.py
@@ -38,6 +38,12 @@ class PhysicButtonsPanel():
class PHYSICS_PT_field(PhysicButtonsPanel, bpy.types.Panel):
bl_label = "Force Fields"
+ @classmethod
+ def poll(cls, context):
+ ob = context.object
+ rd = context.scene.render
+ return (not rd.use_game_engine) and (ob.field) and (ob.field.type != 'NONE')
+
def draw(self, context):
layout = self.layout
@@ -164,7 +170,7 @@ class PHYSICS_PT_collision(PhysicButtonsPanel, bpy.types.Panel):
def poll(cls, 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) and (context.collision)
def draw(self, context):
layout = self.layout
@@ -173,24 +179,7 @@ class PHYSICS_PT_collision(PhysicButtonsPanel, bpy.types.Panel):
split = layout.split()
- if md:
- # remove modifier + settings
- split.context_pointer_set("modifier", md)
- split.operator("object.modifier_remove", text="Remove")
- col = split.column()
-
- #row = split.row(align=True)
- #row.prop(md, "show_render", text="")
- #row.prop(md, "show_viewport", text="")
-
- coll = md.settings
-
- else:
- # add modifier
- split.operator("object.modifier_add", text="Add").type = 'COLLISION'
- split.label()
-
- coll = None
+ coll = md.settings
if coll:
settings = context.object.collision
@@ -228,11 +217,11 @@ class PHYSICS_PT_collision(PhysicButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_physics_fluid.py b/release/scripts/ui/properties_physics_fluid.py
index 1c371f80f16..6385a535a44 100644
--- a/release/scripts/ui/properties_physics_fluid.py
+++ b/release/scripts/ui/properties_physics_fluid.py
@@ -29,7 +29,7 @@ class PhysicButtonsPanel():
def poll(cls, 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) and (context.fluid)
class PHYSICS_PT_fluid(PhysicButtonsPanel, bpy.types.Panel):
@@ -40,36 +40,20 @@ class PHYSICS_PT_fluid(PhysicButtonsPanel, bpy.types.Panel):
md = context.fluid
- split = layout.split()
-
if md:
- # remove modifier + settings
- split.context_pointer_set("modifier", md)
- split.operator("object.modifier_remove", text="Remove")
-
- row = split.row(align=True)
- row.prop(md, "show_render", text="")
- row.prop(md, "show_viewport", text="")
-
fluid = md.settings
- else:
- # add modifier
- split.operator("object.modifier_add", text="Add").type = 'FLUID_SIMULATION'
- split.label()
-
- if md:
row = layout.row()
if fluid is None:
row.label("built without fluids")
return
row.prop(fluid, "type")
- if fluid.type not in ('NONE', 'DOMAIN', 'PARTICLE'):
+ if fluid.type not in ('NONE', 'DOMAIN', 'PARTICLE', 'FLUID'):
row.prop(fluid, "use", text="")
layout = layout.column()
- if fluid.type not in ('NONE', 'DOMAIN', 'PARTICLE'):
+ if fluid.type not in ('NONE', 'DOMAIN', 'PARTICLE', 'FLUID'):
layout.active = fluid.use
if fluid.type == 'DOMAIN':
@@ -298,11 +282,11 @@ class PHYSICS_PT_domain_particles(PhysicButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_physics_smoke.py b/release/scripts/ui/properties_physics_smoke.py
index 536c1e09f44..56ddff292d9 100644
--- a/release/scripts/ui/properties_physics_smoke.py
+++ b/release/scripts/ui/properties_physics_smoke.py
@@ -33,7 +33,7 @@ class PhysicButtonsPanel():
def poll(cls, 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) and (context.smoke)
class PHYSICS_PT_smoke(PhysicButtonsPanel, bpy.types.Panel):
@@ -45,22 +45,6 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, bpy.types.Panel):
md = context.smoke
ob = context.object
- split = layout.split()
-
- if md:
- # remove modifier + settings
- split.context_pointer_set("modifier", md)
- split.operator("object.modifier_remove", text="Remove")
-
- row = split.row(align=True)
- row.prop(md, "show_render", text="")
- row.prop(md, "show_viewport", text="")
-
- else:
- # add modifier
- split.operator("object.modifier_add", text="Add").type = 'SMOKE'
- split.label()
-
if md:
layout.prop(md, "smoke_type", expand=True)
@@ -69,6 +53,8 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, bpy.types.Panel):
split = layout.split()
+ split.enabled = not domain.point_cache.is_baked
+
col = split.column()
col.label(text="Resolution:")
col.prop(domain, "resolution_max", text="Divisions")
@@ -80,7 +66,7 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, bpy.types.Panel):
col = split.column()
col.label(text="Behavior:")
col.prop(domain, "alpha")
- col.prop(domain, "beta")
+ col.prop(domain, "beta", text="Temp. Diff.")
col.prop(domain, "vorticity")
col.prop(domain, "use_dissolve_smoke", text="Dissolve")
sub = col.column()
@@ -109,10 +95,10 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, bpy.types.Panel):
sub = split.column()
sub.active = not md.flow_settings.use_outflow
- sub.label(text="Behavior:")
- sub.prop(flow, "temperature")
- sub.prop(flow, "density")
+ sub.label(text="Initial Values:")
sub.prop(flow, "use_absolute")
+ sub.prop(flow, "density")
+ sub.prop(flow, "temperature")
#elif md.smoke_type == 'COLLISION':
# layout.separator()
@@ -146,27 +132,6 @@ class PHYSICS_PT_smoke_groups(PhysicButtonsPanel, bpy.types.Panel):
col.prop(group, "collision_group", text="")
-class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, bpy.types.Panel):
- bl_label = "Smoke Cache"
- bl_options = {'DEFAULT_CLOSED'}
-
- @classmethod
- def poll(cls, context):
- md = context.smoke
- return md and (md.smoke_type == 'DOMAIN')
-
- def draw(self, context):
- layout = self.layout
-
- md = context.smoke.domain_settings
- cache = md.point_cache_low
-
- layout.label(text="Compression:")
- layout.prop(md, "point_cache_compress_type", expand=True)
-
- point_cache_ui(self, context, cache, (cache.is_baked is False), 'SMOKE')
-
-
class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, bpy.types.Panel):
bl_label = "Smoke High Resolution"
bl_options = {'DEFAULT_CLOSED'}
@@ -189,36 +154,38 @@ class PHYSICS_PT_smoke_highres(PhysicButtonsPanel, bpy.types.Panel):
layout.active = md.use_high_resolution
split = layout.split()
+ split.enabled = not md.point_cache.is_baked
col = split.column()
col.label(text="Resolution:")
col.prop(md, "amplify", text="Divisions")
col.prop(md, "smooth_emitter")
- col.prop(md, "show_high_resolution")
col = split.column()
col.label(text="Noise Method:")
col.row().prop(md, "noise_type", text="")
col.prop(md, "strength")
+ layout.prop(md, "show_high_resolution")
+
-class PHYSICS_PT_smoke_cache_highres(PhysicButtonsPanel, bpy.types.Panel):
- bl_label = "Smoke High Resolution Cache"
+class PHYSICS_PT_smoke_cache(PhysicButtonsPanel, bpy.types.Panel):
+ bl_label = "Smoke Cache"
bl_options = {'DEFAULT_CLOSED'}
@classmethod
def poll(cls, context):
md = context.smoke
- return md and (md.smoke_type == 'DOMAIN') and md.domain_settings.use_high_resolution
+ return md and (md.smoke_type == 'DOMAIN')
def draw(self, context):
layout = self.layout
md = context.smoke.domain_settings
- cache = md.point_cache_high
+ cache = md.point_cache
layout.label(text="Compression:")
- layout.prop(md, "point_cache_compress_high_type", expand=True)
+ layout.prop(md, "point_cache_compress_type", expand=True)
point_cache_ui(self, context, cache, (cache.is_baked is False), 'SMOKE')
@@ -238,11 +205,11 @@ class PHYSICS_PT_smoke_field_weights(PhysicButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_physics_softbody.py b/release/scripts/ui/properties_physics_softbody.py
index a07c6a8e43b..7d3fa66ed02 100644
--- a/release/scripts/ui/properties_physics_softbody.py
+++ b/release/scripts/ui/properties_physics_softbody.py
@@ -39,7 +39,7 @@ class PhysicButtonsPanel():
rd = context.scene.render
# 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)
+ return (ob and (ob.type == 'MESH' or ob.type == 'LATTICE'or ob.type == 'CURVE')) and (not rd.use_game_engine) and (context.soft_body)
class PHYSICS_PT_softbody(PhysicButtonsPanel, bpy.types.Panel):
@@ -51,21 +51,6 @@ class PHYSICS_PT_softbody(PhysicButtonsPanel, bpy.types.Panel):
md = context.soft_body
ob = context.object
- split = layout.split()
-
- if md:
- # remove modifier + settings
- split.context_pointer_set("modifier", md)
- split.operator("object.modifier_remove", text="Remove")
-
- row = split.row(align=True)
- row.prop(md, "show_render", text="")
- row.prop(md, "show_viewport", text="")
- else:
- # add modifier
- split.operator("object.modifier_add", text="Add").type = 'SOFT_BODY'
- split.column()
-
if md:
softbody = md.settings
@@ -277,11 +262,11 @@ class PHYSICS_PT_softbody_field_weights(PhysicButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_render.py b/release/scripts/ui/properties_render.py
index dba9ff44d51..5dfed9ccb20 100644
--- a/release/scripts/ui/properties_render.py
+++ b/release/scripts/ui/properties_render.py
@@ -34,6 +34,13 @@ class RENDER_MT_ffmpeg_presets(bpy.types.Menu):
draw = bpy.types.Menu.draw_preset
+class RENDER_MT_framerate_presets(bpy.types.Menu):
+ bl_label = "Frame Rate Presets"
+ preset_subdir = "framerate"
+ preset_operator = "script.execute_preset"
+ draw = bpy.types.Menu.draw_preset
+
+
class RenderButtonsPanel():
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
@@ -84,10 +91,11 @@ class RENDER_PT_layers(RenderButtonsPanel, bpy.types.Panel):
col.operator("scene.render_layer_add", icon='ZOOMIN', text="")
col.operator("scene.render_layer_remove", icon='ZOOMOUT', text="")
+ row = layout.row()
rl = rd.layers.active
-
if rl:
- layout.prop(rl, "name")
+ row.prop(rl, "name")
+ row.prop(rd, "use_single_layer", text="", icon_only=True)
split = layout.split()
@@ -222,6 +230,7 @@ class RENDER_PT_performance(RenderButtonsPanel, bpy.types.Panel):
sub = col.column()
sub.active = rd.use_compositing
sub.prop(rd, "use_free_image_textures")
+ sub.prop(rd, "use_free_unused_nodes")
sub = col.column()
sub.active = rd.use_raytrace
sub.label(text="Acceleration structure:")
@@ -335,7 +344,10 @@ class RENDER_PT_output(RenderButtonsPanel, bpy.types.Panel):
col.prop(rd, "jpeg2k_ycc")
elif file_format in ('CINEON', 'DPX'):
+
split = layout.split()
+ split.label("FIXME: hard coded Non-Linear, Gamma:1.0")
+ '''
col = split.column()
col.prop(rd, "use_cineon_log", text="Convert to Log")
@@ -344,6 +356,7 @@ class RENDER_PT_output(RenderButtonsPanel, bpy.types.Panel):
col.prop(rd, "cineon_black", text="Black")
col.prop(rd, "cineon_white", text="White")
col.prop(rd, "cineon_gamma", text="Gamma")
+ '''
elif file_format == 'TIFF':
split = layout.split()
@@ -482,10 +495,15 @@ class RENDER_PT_antialiasing(RenderButtonsPanel, bpy.types.Panel):
class RENDER_PT_motion_blur(RenderButtonsPanel, bpy.types.Panel):
- bl_label = "Full Sample Motion Blur"
+ bl_label = "Sampled Motion Blur"
bl_options = {'DEFAULT_CLOSED'}
COMPAT_ENGINES = {'BLENDER_RENDER'}
+ @classmethod
+ def poll(cls, context):
+ rd = context.scene.render
+ return not rd.use_full_sample and (rd.engine in cls.COMPAT_ENGINES)
+
def draw_header(self, context):
rd = context.scene.render
@@ -516,6 +534,7 @@ class RENDER_PT_dimensions(RenderButtonsPanel, bpy.types.Panel):
row.menu("RENDER_MT_presets", text=bpy.types.RENDER_MT_presets.bl_label)
row.operator("render.preset_add", text="", icon="ZOOMIN")
row.operator("render.preset_add", text="", icon="ZOOMOUT").remove_active = True
+
split = layout.split()
col = split.column()
@@ -543,10 +562,29 @@ class RENDER_PT_dimensions(RenderButtonsPanel, bpy.types.Panel):
sub.prop(scene, "frame_step", text="Step")
sub.label(text="Frame Rate:")
+ if rd.fps_base == 1:
+ fps_rate = round(rd.fps / rd.fps_base)
+ else:
+ fps_rate = round(rd.fps / rd.fps_base, 2)
- sub = col.column(align=True)
- sub.prop(rd, "fps")
- sub.prop(rd, "fps_base", text="/")
+ # TODO: Change the following to iterate over existing presets
+ if (fps_rate in (23.98, 24, 25, 29.97, 30, 50, 59.94, 60)):
+ custom_framerate = False
+ else:
+ custom_framerate = True
+
+ if custom_framerate == True:
+ fps_label_text = "Custom (" + str(fps_rate) + " fps)"
+ else:
+ fps_label_text = str(fps_rate) + " fps"
+
+ sub.menu("RENDER_MT_framerate_presets", text=fps_label_text)
+
+ if (bpy.types.RENDER_MT_framerate_presets.bl_label == "Custom") or (custom_framerate == True):
+ sub.prop(rd, "fps")
+ sub.prop(rd, "fps_base", text="/")
+ subrow = sub.row(align=True)
+ subrow.label(text="Time Remapping:")
subrow = sub.row(align=True)
subrow.prop(rd, "frame_map_old", text="Old")
subrow.prop(rd, "frame_map_new", text="New")
@@ -578,6 +616,7 @@ class RENDER_PT_stamp(RenderButtonsPanel, bpy.types.Panel):
col.prop(rd, "use_stamp_frame", text="Frame")
col.prop(rd, "use_stamp_scene", text="Scene")
col.prop(rd, "use_stamp_camera", text="Camera")
+ col.prop(rd, "use_stamp_lens", text="Lens")
col.prop(rd, "use_stamp_filename", text="Filename")
col.prop(rd, "use_stamp_marker", text="Marker")
col.prop(rd, "use_stamp_sequencer_strip", text="Seq. Strip")
@@ -636,11 +675,11 @@ class RENDER_PT_bake(RenderButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_scene.py b/release/scripts/ui/properties_scene.py
index 46a8e90393d..51fe7c9e132 100644
--- a/release/scripts/ui/properties_scene.py
+++ b/release/scripts/ui/properties_scene.py
@@ -53,6 +53,7 @@ class SCENE_PT_unit(SceneButtonsPanel, bpy.types.Panel):
col = layout.column()
col.row().prop(unit, "system", expand=True)
+ col.row().prop(unit, "system_rotation", expand=True)
split = layout.split()
split.active = (unit.system != 'NONE')
@@ -63,8 +64,6 @@ class SCENE_PT_unit(SceneButtonsPanel, bpy.types.Panel):
col = split.column()
col.prop(unit, "use_separate")
- layout.column().prop(unit, "rotation_units")
-
class SCENE_PT_keying_sets(SceneButtonsPanel, bpy.types.Panel):
bl_label = "Keying Sets"
@@ -198,6 +197,7 @@ class SCENE_PT_simplify(SceneButtonsPanel, bpy.types.Panel):
class SCENE_PT_custom_props(SceneButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "scene"
+ _property_type = bpy.types.Scene
from bpy.props import *
@@ -229,7 +229,7 @@ class ANIM_OT_keying_set_export(bpy.types.Operator):
f.write("# Keying Set: %s\n" % ks.name)
f.write("import bpy\n\n")
- f.write("scene= bpy.data.scenes[0]\n\n") # XXX, why not use the current scene?
+ f.write("scene= bpy.data.scenes[0]\n\n") # XXX, why not use the current scene?
# Add KeyingSet and set general settings
f.write("# Keying Set Level declarations\n")
@@ -238,7 +238,7 @@ class ANIM_OT_keying_set_export(bpy.types.Operator):
if not ks.is_path_absolute:
f.write("ks.is_path_absolute = False\n")
f.write("\n")
-
+
f.write("ks.bl_options = %r\n" % ks.bl_options)
f.write("\n")
@@ -306,13 +306,13 @@ class ANIM_OT_keying_set_export(bpy.types.Operator):
def invoke(self, context, event):
wm = context.window_manager
- wm.add_fileselect(self)
+ wm.fileselect_add(self)
return {'RUNNING_MODAL'}
class SCENE_PT_navmesh(SceneButtonsPanel, bpy.types.Panel):
bl_label = "Navmesh"
bl_default_closed = True
- COMPAT_ENGINES = {'BLENDER_RENDER'}
+ COMPAT_ENGINES = {'BLENDER_GAME'}
def draw(self, context):
layout = self.layout
@@ -382,11 +382,11 @@ class SCENE_PT_navmesh(SceneButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_texture.py b/release/scripts/ui/properties_texture.py
index bf0c5d56e4c..05e130fac2d 100644
--- a/release/scripts/ui/properties_texture.py
+++ b/release/scripts/ui/properties_texture.py
@@ -94,7 +94,15 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel, bpy.types.Panel):
space = context.space_data
tex = context.texture
idblock = context_tex_datablock(context)
- tex_collection = space.pin_id is None and type(idblock) != bpy.types.Brush and not node
+ pin_id = space.pin_id
+
+ if not isinstance(pin_id, bpy.types.Material):
+ pin_id = None
+
+ if not space.use_pin_id:
+ layout.prop(space, "texture_context", expand=True)
+
+ tex_collection = (not space.use_pin_id) and (node is None) and (not isinstance(idblock, bpy.types.Brush))
if tex_collection:
row = layout.row()
@@ -116,14 +124,11 @@ class TEXTURE_PT_context_texture(TextureButtonsPanel, bpy.types.Panel):
elif idblock:
col.template_ID(idblock, "texture", new="texture.new")
- if space.pin_id:
+ if pin_id:
col.template_ID(space, "pin_id")
col = split.column()
- if not space.pin_id:
- col.prop(space, "show_brush_texture", text="Brush", toggle=True)
-
if tex:
split = layout.split(percentage=0.2)
@@ -199,216 +204,6 @@ class TextureSlotPanel(TextureButtonsPanel):
return TextureButtonsPanel.poll(self, context) and (engine in cls.COMPAT_ENGINES)
-class TEXTURE_PT_mapping(TextureSlotPanel, bpy.types.Panel):
- bl_label = "Mapping"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, 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 cls.COMPAT_ENGINES)
-
- def draw(self, context):
- layout = self.layout
-
- idblock = context_tex_datablock(context)
-
- tex = context.texture_slot
- # textype = context.texture
-
- if type(idblock) != bpy.types.Brush:
- split = layout.split(percentage=0.3)
- col = split.column()
- col.label(text="Coordinates:")
- col = split.column()
- col.prop(tex, "texture_coords", text="")
-
- if tex.texture_coords == 'ORCO':
- """
- ob = context.object
- if ob and ob.type == 'MESH':
- split = layout.split(percentage=0.3)
- split.label(text="Mesh:")
- split.prop(ob.data, "texco_mesh", text="")
- """
- elif tex.texture_coords == 'UV':
- split = layout.split(percentage=0.3)
- split.label(text="Layer:")
- ob = context.object
- if ob and ob.type == 'MESH':
- split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="")
- else:
- split.prop(tex, "uv_layer", text="")
-
- elif tex.texture_coords == 'OBJECT':
- split = layout.split(percentage=0.3)
- split.label(text="Object:")
- split.prop(tex, "object", text="")
-
- if type(idblock) == bpy.types.Brush:
- 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 ('FIXED', 'TILED')
- row.prop(tex, "angle")
- else:
- if type(idblock) == bpy.types.Material:
- split = layout.split(percentage=0.3)
- split.label(text="Projection:")
- split.prop(tex, "mapping", text="")
-
- split = layout.split()
-
- col = split.column()
- if tex.texture_coords in ('ORCO', 'UV'):
- col.prop(tex, "use_from_dupli")
- elif tex.texture_coords == 'OBJECT':
- col.prop(tex, "use_from_original")
- else:
- col.label()
-
- col = split.column()
- row = col.row()
- row.prop(tex, "mapping_x", text="")
- row.prop(tex, "mapping_y", text="")
- row.prop(tex, "mapping_z", text="")
-
- split = layout.split()
-
- col = split.column()
- col.prop(tex, "offset")
-
- col = split.column()
-
- col.prop(tex, "scale")
-
-
-class TEXTURE_PT_influence(TextureSlotPanel, bpy.types.Panel):
- bl_label = "Influence"
- COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
-
- @classmethod
- def poll(cls, context):
- idblock = context_tex_datablock(context)
- if type(idblock) == bpy.types.Brush:
- return False
-
- if not getattr(context, "texture_slot", None):
- return False
-
- engine = context.scene.render.engine
- return (engine in cls.COMPAT_ENGINES)
-
- def draw(self, context):
-
- layout = self.layout
-
- idblock = context_tex_datablock(context)
-
- # textype = context.texture
- tex = context.texture_slot
-
- def factor_but(layout, active, toggle, factor, name):
- row = layout.row(align=True)
- row.prop(tex, toggle, text="")
- sub = row.row()
- sub.active = active
- sub.prop(tex, factor, text=name, slider=True)
-
- if type(idblock) == bpy.types.Material:
- if idblock.type in ('SURFACE', 'HALO', 'WIRE'):
- split = layout.split()
-
- col = split.column()
- col.label(text="Diffuse:")
- factor_but(col, tex.use_map_diffuse, "use_map_diffuse", "diffuse_factor", "Intensity")
- factor_but(col, tex.use_map_color_diffuse, "use_map_color_diffuse", "diffuse_color_factor", "Color")
- factor_but(col, tex.use_map_alpha, "use_map_alpha", "alpha_factor", "Alpha")
- factor_but(col, tex.use_map_translucency, "use_map_translucency", "translucency_factor", "Translucency")
-
- col.label(text="Specular:")
- factor_but(col, tex.use_map_specular, "use_map_specular", "specular_factor", "Intensity")
- factor_but(col, tex.use_map_color_spec, "use_map_color_spec", "specular_color_factor", "Color")
- factor_but(col, tex.use_map_hardness, "use_map_hardness", "hardness_factor", "Hardness")
-
- col = split.column()
- col.label(text="Shading:")
- factor_but(col, tex.use_map_ambient, "use_map_ambient", "ambient_factor", "Ambient")
- factor_but(col, tex.use_map_emit, "use_map_emit", "emit_factor", "Emit")
- factor_but(col, tex.use_map_mirror, "use_map_mirror", "mirror_factor", "Mirror")
- factor_but(col, tex.use_map_raymir, "use_map_raymir", "raymir_factor", "Ray Mirror")
-
- col.label(text="Geometry:")
- # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
- factor_but(col, (tex.use_map_normal or tex.use_map_displacement), "use_map_normal", "normal_factor", "Normal")
- factor_but(col, tex.use_map_warp, "use_map_warp", "warp_factor", "Warp")
- factor_but(col, tex.use_map_displacement, "use_map_displacement", "displacement_factor", "Displace")
-
- #sub = col.column()
- #sub.active = tex.use_map_translucency or tex.map_emit or tex.map_alpha or tex.map_raymir or tex.map_hardness or tex.map_ambient or tex.map_specularity or tex.map_reflection or tex.map_mirror
- #sub.prop(tex, "default_value", text="Amount", slider=True)
- elif idblock.type == 'VOLUME':
- split = layout.split()
-
- col = split.column()
- factor_but(col, tex.use_map_density, "use_map_density", "density_factor", "Density")
- factor_but(col, tex.use_map_emission, "use_map_emission", "emission_factor", "Emission")
- factor_but(col, tex.use_map_scatter, "use_map_scatter", "scattering_factor", "Scattering")
- factor_but(col, tex.use_map_reflect, "use_map_reflect", "reflection_factor", "Reflection")
-
- col = split.column()
- col.label(text=" ")
- factor_but(col, tex.use_map_color_emission, "use_map_color_emission", "emission_color_factor", "Emission Color")
- factor_but(col, tex.use_map_color_transmission, "use_map_color_transmission", "transmission_color_factor", "Transmission Color")
- factor_but(col, tex.use_map_color_reflection, "use_map_color_reflection", "reflection_color_factor", "Reflection Color")
-
- elif type(idblock) == bpy.types.Lamp:
- split = layout.split()
-
- col = split.column()
- factor_but(col, tex.use_map_color, "map_color", "color_factor", "Color")
-
- col = split.column()
- factor_but(col, tex.use_map_shadow, "map_shadow", "shadow_factor", "Shadow")
-
- elif type(idblock) == bpy.types.World:
- split = layout.split()
-
- col = split.column()
- factor_but(col, tex.use_map_blend, "use_map_blend", "blend_factor", "Blend")
- factor_but(col, tex.use_map_horizon, "use_map_horizon", "horizon_factor", "Horizon")
-
- col = split.column()
- factor_but(col, tex.use_map_zenith_up, "use_map_zenith_up", "zenith_up_factor", "Zenith Up")
- factor_but(col, tex.use_map_zenith_down, "use_map_zenith_down", "zenith_down_factor", "Zenith Down")
-
- layout.separator()
-
- split = layout.split()
-
- col = split.column()
- col.prop(tex, "blend_type", text="Blend")
- col.prop(tex, "use_rgb_to_intensity")
- sub = col.column()
- sub.active = tex.use_rgb_to_intensity
- sub.prop(tex, "color", text="")
-
- col = split.column()
- col.prop(tex, "invert", text="Negative")
- col.prop(tex, "use_stencil")
-
- if type(idblock) in (bpy.types.Material, bpy.types.World):
- col.prop(tex, "default_value", text="DVar", slider=True)
-
# Texture Type Panels #
@@ -599,8 +394,9 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, bpy.types.Panel):
def draw(self, context):
layout = self.layout
+ idblock = context_tex_datablock(context)
tex = context.texture
- # slot = context.texture_slot
+ slot = context.texture_slot
split = layout.split()
@@ -614,10 +410,12 @@ class TEXTURE_PT_image_sampling(TextureTypePanel, bpy.types.Panel):
col = split.column()
- col.prop(tex, "use_normal_map")
- row = col.row()
- row.active = tex.use_normal_map
- row.prop(tex, "normal_space", text="")
+ #Only for Material based textures, not for Lamp/World...
+ if isinstance(idblock, bpy.types.Material):
+ col.prop(tex, "use_normal_map")
+ row = col.row()
+ row.active = tex.use_normal_map
+ row.prop(slot, "normal_map_space", text="")
col.prop(tex, "use_mipmap")
row = col.row()
@@ -651,8 +449,12 @@ class TEXTURE_PT_image_mapping(TextureTypePanel, bpy.types.Panel):
col = split.column(align=True)
col.label(text="Mirror:")
- col.prop(tex, "use_mirror_x", text="X")
- col.prop(tex, "use_mirror_y", text="Y")
+ row = col.row()
+ row.prop(tex, "use_mirror_x", text="X")
+ row.active = (tex.repeat_x > 1)
+ row = col.row()
+ row.prop(tex, "use_mirror_y", text="Y")
+ row.active = (tex.repeat_y > 1)
layout.separator()
elif tex.extension == 'CHECKER':
@@ -751,12 +553,14 @@ class TEXTURE_PT_musgrave(TextureTypePanel, bpy.types.Panel):
col.prop(tex, "lacunarity")
col.prop(tex, "octaves")
+ musgrave_type = tex.musgrave_type
col = split.column()
- if (tex.musgrave_type in ('HETERO_TERRAIN', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL')):
+ if musgrave_type in ('HETERO_TERRAIN', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'):
col.prop(tex, "offset")
- if (tex.musgrave_type in ('RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL')):
- col.prop(tex, "gain")
+ if musgrave_type in ('MULTIFRACTAL', 'RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'):
col.prop(tex, "noise_intensity", text="Intensity")
+ if musgrave_type in ('RIDGED_MULTIFRACTAL', 'HYBRID_MULTIFRACTAL'):
+ col.prop(tex, "gain")
layout.label(text="Noise:")
@@ -864,10 +668,11 @@ class TEXTURE_PT_voxeldata(TextureButtonsPanel, bpy.types.Panel):
layout.template_image(tex, "image", tex.image_user, compact=True)
#layout.prop(vd, "frame_duration")
- layout.prop(vd, "use_still_frame")
- row = layout.row()
- row.active = vd.use_still_frame
- row.prop(vd, "still_frame")
+ if vd.file_format in ('BLENDER_VOXEL', 'RAW_8BIT'):
+ layout.prop(vd, "use_still_frame")
+ row = layout.row()
+ row.active = vd.use_still_frame
+ row.prop(vd, "still_frame")
layout.prop(vd, "interpolation")
layout.prop(vd, "extension")
@@ -970,17 +775,260 @@ class TEXTURE_PT_pointdensity_turbulence(TextureButtonsPanel, bpy.types.Panel):
col.prop(pd, "turbulence_strength")
+class TEXTURE_PT_mapping(TextureSlotPanel, bpy.types.Panel):
+ bl_label = "Mapping"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ @classmethod
+ def poll(cls, context):
+ idblock = context_tex_datablock(context)
+ if isinstance(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 cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+ layout = self.layout
+
+ idblock = context_tex_datablock(context)
+
+ tex = context.texture_slot
+ # textype = context.texture
+
+ if not isinstance(idblock, bpy.types.Brush):
+ split = layout.split(percentage=0.3)
+ col = split.column()
+ col.label(text="Coordinates:")
+ col = split.column()
+ col.prop(tex, "texture_coords", text="")
+
+ if tex.texture_coords == 'ORCO':
+ """
+ ob = context.object
+ if ob and ob.type == 'MESH':
+ split = layout.split(percentage=0.3)
+ split.label(text="Mesh:")
+ split.prop(ob.data, "texco_mesh", text="")
+ """
+ elif tex.texture_coords == 'UV':
+ split = layout.split(percentage=0.3)
+ split.label(text="Layer:")
+ ob = context.object
+ if ob and ob.type == 'MESH':
+ split.prop_search(tex, "uv_layer", ob.data, "uv_textures", text="")
+ else:
+ split.prop(tex, "uv_layer", text="")
+
+ elif tex.texture_coords == 'OBJECT':
+ split = layout.split(percentage=0.3)
+ split.label(text="Object:")
+ split.prop(tex, "object", text="")
+
+ if isinstance(idblock, bpy.types.Brush):
+ 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 ('FIXED', 'TILED')
+ row.prop(tex, "angle")
+ else:
+ if isinstance(idblock, bpy.types.Material):
+ split = layout.split(percentage=0.3)
+ split.label(text="Projection:")
+ split.prop(tex, "mapping", text="")
+
+ split = layout.split()
+
+ col = split.column()
+ if tex.texture_coords in ('ORCO', 'UV'):
+ col.prop(tex, "use_from_dupli")
+ elif tex.texture_coords == 'OBJECT':
+ col.prop(tex, "use_from_original")
+ else:
+ col.label()
+
+ col = split.column()
+ row = col.row()
+ row.prop(tex, "mapping_x", text="")
+ row.prop(tex, "mapping_y", text="")
+ row.prop(tex, "mapping_z", text="")
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(tex, "offset")
+
+ col = split.column()
+
+ col.prop(tex, "scale")
+
+
+class TEXTURE_PT_influence(TextureSlotPanel, bpy.types.Panel):
+ bl_label = "Influence"
+ COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
+
+ @classmethod
+ def poll(cls, context):
+ idblock = context_tex_datablock(context)
+ if isinstance(idblock, bpy.types.Brush):
+ return False
+
+ if not getattr(context, "texture_slot", None):
+ return False
+
+ engine = context.scene.render.engine
+ return (engine in cls.COMPAT_ENGINES)
+
+ def draw(self, context):
+
+ layout = self.layout
+
+ idblock = context_tex_datablock(context)
+
+ # textype = context.texture
+ tex = context.texture_slot
+
+ def factor_but(layout, toggle, factor, name):
+ row = layout.row(align=True)
+ row.prop(tex, toggle, text="")
+ sub = row.row()
+ sub.active = getattr(tex, toggle)
+ sub.prop(tex, factor, text=name, slider=True)
+ return sub # XXX, temp. use_map_normal needs to override.
+
+ if isinstance(idblock, bpy.types.Material):
+ if idblock.type in ('SURFACE', 'WIRE'):
+ split = layout.split()
+
+ col = split.column()
+ col.label(text="Diffuse:")
+ factor_but(col, "use_map_diffuse", "diffuse_factor", "Intensity")
+ factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
+ factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
+ factor_but(col, "use_map_translucency", "translucency_factor", "Translucency")
+
+ col.label(text="Specular:")
+ factor_but(col, "use_map_specular", "specular_factor", "Intensity")
+ factor_but(col, "use_map_color_spec", "specular_color_factor", "Color")
+ factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
+
+ col = split.column()
+ col.label(text="Shading:")
+ factor_but(col, "use_map_ambient", "ambient_factor", "Ambient")
+ factor_but(col, "use_map_emit", "emit_factor", "Emit")
+ factor_but(col, "use_map_mirror", "mirror_factor", "Mirror")
+ factor_but(col, "use_map_raymir", "raymir_factor", "Ray Mirror")
+
+ col.label(text="Geometry:")
+ # XXX replace 'or' when displacement is fixed to not rely on normal influence value.
+ sub_tmp = factor_but(col, "use_map_normal", "normal_factor", "Normal")
+ sub_tmp.active = (tex.use_map_normal or tex.use_map_displacement)
+ # END XXX
+
+ factor_but(col, "use_map_warp", "warp_factor", "Warp")
+ factor_but(col, "use_map_displacement", "displacement_factor", "Displace")
+
+ #sub = col.column()
+ #sub.active = tex.use_map_translucency or tex.map_emit or tex.map_alpha or tex.map_raymir or tex.map_hardness or tex.map_ambient or tex.map_specularity or tex.map_reflection or tex.map_mirror
+ #sub.prop(tex, "default_value", text="Amount", slider=True)
+ elif idblock.type == 'HALO':
+ layout.label(text="Halo:")
+
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_color_diffuse", "diffuse_color_factor", "Color")
+ factor_but(col, "use_map_alpha", "alpha_factor", "Alpha")
+
+ col = split.column()
+ factor_but(col, "use_map_raymir", "raymir_factor", "Size")
+ factor_but(col, "use_map_hardness", "hardness_factor", "Hardness")
+ factor_but(col, "use_map_translucency", "translucency_factor", "Add")
+ elif idblock.type == 'VOLUME':
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_density", "density_factor", "Density")
+ factor_but(col, "use_map_emission", "emission_factor", "Emission")
+ factor_but(col, "use_map_scatter", "scattering_factor", "Scattering")
+ factor_but(col, "use_map_reflect", "reflection_factor", "Reflection")
+
+ col = split.column()
+ col.label(text=" ")
+ factor_but(col, "use_map_color_emission", "emission_color_factor", "Emission Color")
+ factor_but(col, "use_map_color_transmission", "transmission_color_factor", "Transmission Color")
+ factor_but(col, "use_map_color_reflection", "reflection_color_factor", "Reflection Color")
+
+ elif isinstance(idblock, bpy.types.Lamp):
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_color", "color_factor", "Color")
+
+ col = split.column()
+ factor_but(col, "use_map_shadow", "shadow_factor", "Shadow")
+
+ elif isinstance(idblock, bpy.types.World):
+ split = layout.split()
+
+ col = split.column()
+ factor_but(col, "use_map_blend", "blend_factor", "Blend")
+ factor_but(col, "use_map_horizon", "horizon_factor", "Horizon")
+
+ col = split.column()
+ factor_but(col, "use_map_zenith_up", "zenith_up_factor", "Zenith Up")
+ factor_but(col, "use_map_zenith_down", "zenith_down_factor", "Zenith Down")
+
+ layout.separator()
+
+ split = layout.split()
+
+ col = split.column()
+ col.prop(tex, "blend_type", text="Blend")
+ col.prop(tex, "use_rgb_to_intensity")
+ # color is used on grayscale textures even when use_rgb_to_intensity is disabled.
+ col.prop(tex, "color", text="")
+
+ col = split.column()
+ col.prop(tex, "invert", text="Negative")
+ col.prop(tex, "use_stencil")
+
+ if isinstance(idblock, bpy.types.Material) or isinstance(idblock, bpy.types.World):
+ col.prop(tex, "default_value", text="DVar", slider=True)
+
+ if isinstance(idblock, bpy.types.Material):
+ row = layout.row()
+ row.label(text="Bump Mapping:")
+
+ row = layout.row()
+ # only show bump settings if activated but not for normalmap images
+ row.active = tex.use_map_normal and not (tex.texture.type == 'IMAGE' and tex.texture.use_normal_map)
+
+ col = row.column()
+ col.prop(tex, "bump_method", text="Method")
+
+ col = row.column()
+ col.prop(tex, "bump_objectspace", text="Space")
+ col.active = tex.bump_method in ('BUMP_DEFAULT', 'BUMP_BEST_QUALITY')
+
+
class TEXTURE_PT_custom_props(TextureButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "texture"
+ _property_type = bpy.types.Texture
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/properties_world.py b/release/scripts/ui/properties_world.py
index b4507ccc73c..fd11f299f34 100644
--- a/release/scripts/ui/properties_world.py
+++ b/release/scripts/ui/properties_world.py
@@ -139,11 +139,6 @@ class WORLD_PT_indirect_lighting(WorldButtonsPanel, bpy.types.Panel):
bl_label = "Indirect Lighting"
COMPAT_ENGINES = {'BLENDER_RENDER'}
- @classmethod
- def poll(cls, context):
- light = getattr(context.world, "light_settings", None)
- return light and light.gather_method == 'APPROXIMATE'
-
def draw_header(self, context):
light = context.world.light_settings
self.layout.prop(light, "use_indirect_light", text="")
@@ -152,12 +147,15 @@ class WORLD_PT_indirect_lighting(WorldButtonsPanel, bpy.types.Panel):
layout = self.layout
light = context.world.light_settings
- layout.active = light.use_indirect_light
+ layout.active = light.use_indirect_light and light.gather_method == 'APPROXIMATE'
split = layout.split()
split.prop(light, "indirect_factor", text="Factor")
split.prop(light, "indirect_bounces", text="Bounces")
+ if light.gather_method == 'RAYTRACE':
+ layout.label(text="Only works with Approximate gather method")
+
class WORLD_PT_gather(WorldButtonsPanel, bpy.types.Panel):
bl_label = "Gather"
@@ -266,14 +264,15 @@ class WORLD_PT_stars(WorldButtonsPanel, bpy.types.Panel):
class WORLD_PT_custom_props(WorldButtonsPanel, PropertyPanel, bpy.types.Panel):
COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'}
_context_path = "world"
+ _property_type = bpy.types.World
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_console.py b/release/scripts/ui/space_console.py
index 558bded5e7f..b3bd886d8c5 100644
--- a/release/scripts/ui/space_console.py
+++ b/release/scripts/ui/space_console.py
@@ -34,29 +34,10 @@ class CONSOLE_HT_header(bpy.types.Header):
if context.area.show_menus:
sub = row.row(align=True)
+ sub.menu("CONSOLE_MT_console")
- if sc.console_type == 'REPORT':
- sub.menu("CONSOLE_MT_report")
- else:
- sub.menu("CONSOLE_MT_console")
-
- layout.separator()
- layout.prop(sc, "console_type", expand=True)
-
- if sc.console_type == 'REPORT':
- row = layout.row(align=True)
- row.prop(sc, "show_report_debug", text="Debug")
- row.prop(sc, "show_report_info", text="Info")
- row.prop(sc, "show_report_operator", text="Operators")
- row.prop(sc, "show_report_warning", text="Warnings")
- row.prop(sc, "show_report_error", text="Errors")
-
- row = layout.row()
- row.enabled = sc.show_report_operator
- row.operator("console.report_replay")
- else:
- row = layout.row(align=True)
- row.operator("console.autocomplete", text="Autocomplete")
+ row = layout.row(align=True)
+ row.operator("console.autocomplete", text="Autocomplete")
class CONSOLE_MT_console(bpy.types.Menu):
@@ -76,18 +57,6 @@ class CONSOLE_MT_console(bpy.types.Menu):
layout.operator("screen.screen_full_area")
-class CONSOLE_MT_report(bpy.types.Menu):
- bl_label = "Report"
-
- def draw(self, context):
- layout = self.layout
- layout.column()
- layout.operator("console.select_all_toggle")
- layout.operator("console.select_border")
- layout.operator("console.report_delete")
- layout.operator("console.report_copy")
-
-
class CONSOLE_MT_language(bpy.types.Menu):
bl_label = "Languages..."
@@ -138,10 +107,6 @@ class ConsoleAutocomplete(bpy.types.Operator):
bl_idname = "console.autocomplete"
bl_label = "Console Autocomplete"
- @classmethod
- def poll(cls, context):
- return context.space_data.console_type != 'REPORT'
-
def execute(self, context):
sc = context.space_data
module = __import__("console_" + sc.language)
@@ -198,11 +163,11 @@ class ConsoleLanguage(bpy.types.Operator):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_dopesheet.py b/release/scripts/ui/space_dopesheet.py
index 19f64268481..9a1acfd76b8 100644
--- a/release/scripts/ui/space_dopesheet.py
+++ b/release/scripts/ui/space_dopesheet.py
@@ -20,8 +20,12 @@
import bpy
+
+#######################################
+# DopeSheet Filtering
+
# used for DopeSheet, NLA, and Graph Editors
-def dopesheet_filter(layout, context):
+def dopesheet_filter(layout, context, genericFiltersOnly=False):
dopesheet = context.space_data.dopesheet
is_nla = context.area.type == 'NLA_EDITOR'
@@ -29,6 +33,9 @@ def dopesheet_filter(layout, context):
row.prop(dopesheet, "show_only_selected", text="")
row.prop(dopesheet, "show_hidden", text="")
+ if genericFiltersOnly:
+ return
+
row = layout.row(align=True)
row.prop(dopesheet, "show_transforms", text="")
@@ -56,6 +63,8 @@ def dopesheet_filter(layout, context):
row.prop(dopesheet, "show_curves", text="")
if bpy.data.metaballs:
row.prop(dopesheet, "show_metaballs", text="")
+ if bpy.data.lattices:
+ row.prop(dopesheet, "show_lattices", text="")
if bpy.data.armatures:
row.prop(dopesheet, "show_armatures", text="")
if bpy.data.particles:
@@ -68,6 +77,9 @@ def dopesheet_filter(layout, context):
row.prop(dopesheet, "filter_group", text="")
+#######################################
+# DopeSheet Editor - General/Standard UI
+
class DOPESHEET_HT_header(bpy.types.Header):
bl_space_type = 'DOPESHEET_EDITOR'
@@ -84,25 +96,32 @@ class DOPESHEET_HT_header(bpy.types.Header):
sub.menu("DOPESHEET_MT_view")
sub.menu("DOPESHEET_MT_select")
+ sub.menu("DOPESHEET_MT_marker")
if st.mode == 'DOPESHEET' or (st.mode == 'ACTION' and st.action != None):
sub.menu("DOPESHEET_MT_channel")
elif st.mode == 'GPENCIL':
- # gpencil Channel menu
- pass
+ sub.menu("DOPESHEET_MT_gpencil_channel")
if st.mode != 'GPENCIL':
sub.menu("DOPESHEET_MT_key")
+ else:
+ sub.menu("DOPESHEET_MT_gpencil_frame")
layout.prop(st, "mode", text="")
layout.prop(st.dopesheet, "show_summary", text="Summary")
if st.mode == 'DOPESHEET':
dopesheet_filter(layout, context)
-
elif st.mode == 'ACTION':
+ # 'genericFiltersOnly' limits the options to only the relevant 'generic' subset of
+ # filters which will work here and are useful (especially for character animation)
+ dopesheet_filter(layout, context, genericFiltersOnly=True)
+
+ if st.mode in ('ACTION', 'SHAPEKEY'):
layout.template_ID(st, "action", new="action.new")
+ # Grease Pencil mode doesn't need snapping, as it's frame-aligned only
if st.mode != 'GPENCIL':
layout.prop(st, "auto_snap", text="")
@@ -168,14 +187,44 @@ class DOPESHEET_MT_select(bpy.types.Menu):
layout.operator("action.select_column", text="Columns on Selected Markers").mode = 'MARKERS_COLUMN'
layout.operator("action.select_column", text="Between Selected Markers").mode = 'MARKERS_BETWEEN'
- layout.separator()
- layout.operator("action.select_more")
- layout.operator("action.select_less")
+ # FIXME: grease pencil mode isn't supported for these yet, so skip for that mode only
+ if context.space_data.mode != 'GPENCIL':
+ layout.separator()
+ layout.operator("action.select_more")
+ layout.operator("action.select_less")
+
+ layout.separator()
+ layout.operator("action.select_linked")
+
+
+class DOPESHEET_MT_marker(bpy.types.Menu):
+ bl_label = "Marker"
+
+ def draw(self, context):
+ layout = self.layout
+
+ st = context.space_data
+
+ #layout.operator_context = 'EXEC_REGION_WIN'
+
+ layout.column()
+ layout.operator("marker.add", "Add Marker")
+ layout.operator("marker.duplicate", text="Duplicate Marker")
+ layout.operator("marker.delete", text="Delete Marker")
layout.separator()
- layout.operator("action.select_linked")
+
+ layout.operator("marker.rename", text="Rename Marker")
+ layout.operator("marker.move", text="Grab/Move Marker")
+
+ if st.mode in ('ACTION', 'SHAPEKEY') and st.action:
+ layout.separator()
+ layout.prop(st, "show_pose_markers")
+#######################################
+# Keyframe Editing
+
class DOPESHEET_MT_channel(bpy.types.Menu):
bl_label = "Channel"
@@ -194,11 +243,18 @@ class DOPESHEET_MT_channel(bpy.types.Menu):
layout.separator()
layout.operator("anim.channels_editable_toggle")
+ layout.operator_menu_enum("action.extrapolation_type", "type", text="Extrapolation Mode")
layout.separator()
layout.operator("anim.channels_expand")
layout.operator("anim.channels_collapse")
+ layout.separator()
+ layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
+
+ layout.separator()
+ layout.operator("anim.channels_fcurves_enable")
+
class DOPESHEET_MT_key(bpy.types.Menu):
bl_label = "Key"
@@ -223,7 +279,6 @@ class DOPESHEET_MT_key(bpy.types.Menu):
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")
@@ -247,12 +302,64 @@ class DOPESHEET_MT_key_transform(bpy.types.Menu):
layout.operator("transform.transform", text="Scale").mode = 'TIME_SCALE'
+#######################################
+# Grease Pencil Editing
+
+class DOPESHEET_MT_gpencil_channel(bpy.types.Menu):
+ bl_label = "Channel"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_REGION_CHANNELS'
+
+ layout.column()
+ layout.operator("anim.channels_delete")
+
+ layout.separator()
+ layout.operator("anim.channels_setting_toggle")
+ layout.operator("anim.channels_setting_enable")
+ layout.operator("anim.channels_setting_disable")
+
+ layout.separator()
+ layout.operator("anim.channels_editable_toggle")
+
+ # XXX: to be enabled when these are ready for use!
+ #layout.separator()
+ #layout.operator("anim.channels_expand")
+ #layout.operator("anim.channels_collapse")
+
+ #layout.separator()
+ #layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
+
+
+class DOPESHEET_MT_gpencil_frame(bpy.types.Menu):
+ bl_label = "Frame"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.column()
+ layout.menu("DOPESHEET_MT_key_transform", text="Transform")
+
+ #layout.operator_menu_enum("action.snap", "type", text="Snap")
+ #layout.operator_menu_enum("action.mirror", "type", text="Mirror")
+
+ layout.separator()
+ layout.operator("action.duplicate")
+ layout.operator("action.delete")
+
+ #layout.separator()
+ #layout.operator("action.copy")
+ #layout.operator("action.paste")
+
+
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_filebrowser.py b/release/scripts/ui/space_filebrowser.py
index 499fd63f1e6..2d66bb38637 100644
--- a/release/scripts/ui/space_filebrowser.py
+++ b/release/scripts/ui/space_filebrowser.py
@@ -57,9 +57,9 @@ class FILEBROWSER_HT_header(bpy.types.Header):
row = layout.row(align=True)
row.active = params.use_filter
-
+
row.prop(params, "use_filter_folder", text="")
-
+
if params.filter_glob:
#if st.operator and hasattr(st.operator, "filter_glob"):
# row.prop(params, "filter_glob", text="")
@@ -75,11 +75,11 @@ class FILEBROWSER_HT_header(bpy.types.Header):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_graph.py b/release/scripts/ui/space_graph.py
index fe4f2cc1bfd..55c4d4cfd94 100644
--- a/release/scripts/ui/space_graph.py
+++ b/release/scripts/ui/space_graph.py
@@ -39,6 +39,7 @@ class GRAPH_HT_header(bpy.types.Header):
sub.menu("GRAPH_MT_view")
sub.menu("GRAPH_MT_select")
+ sub.menu("GRAPH_MT_marker")
sub.menu("GRAPH_MT_channel")
sub.menu("GRAPH_MT_key")
@@ -80,6 +81,9 @@ class GRAPH_MT_view(bpy.types.Menu):
layout.prop(st, "use_auto_merge_keyframes")
layout.separator()
+ layout.prop(st, "use_fancy_drawing")
+
+ layout.separator()
if st.show_handles:
layout.operator("graph.handles_view_toggle", icon='CHECKBOX_HLT', text="Show All Handles")
else:
@@ -133,6 +137,27 @@ class GRAPH_MT_select(bpy.types.Menu):
layout.operator("graph.select_linked")
+class GRAPH_MT_marker(bpy.types.Menu):
+ bl_label = "Marker"
+
+ def draw(self, context):
+ layout = self.layout
+
+ #layout.operator_context = 'EXEC_REGION_WIN'
+
+ layout.column()
+ layout.operator("marker.add", "Add Marker")
+ layout.operator("marker.duplicate", text="Duplicate Marker")
+ layout.operator("marker.delete", text="Delete Marker")
+
+ layout.separator()
+
+ layout.operator("marker.rename", text="Rename Marker")
+ layout.operator("marker.move", text="Grab/Move Marker")
+
+ # TODO: pose markers for action edit mode only?
+
+
class GRAPH_MT_channel(bpy.types.Menu):
bl_label = "Channel"
@@ -152,13 +177,17 @@ class GRAPH_MT_channel(bpy.types.Menu):
layout.separator()
layout.operator("anim.channels_editable_toggle")
layout.operator("anim.channels_visibility_set")
+ layout.operator_menu_enum("graph.extrapolation_type", "type", text="Extrapolation Mode")
layout.separator()
layout.operator("anim.channels_expand")
layout.operator("anim.channels_collapse")
layout.separator()
- layout.operator("graph.euler_filter", text="Discontinuity (Euler) Filter")
+ layout.operator_menu_enum("anim.channels_move", "direction", text="Move...")
+
+ layout.separator()
+ layout.operator("anim.channels_fcurves_enable")
class GRAPH_MT_key(bpy.types.Menu):
@@ -184,10 +213,10 @@ class GRAPH_MT_key(bpy.types.Menu):
layout.separator()
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")
+ layout.operator("graph.smooth")
layout.operator("graph.sample")
layout.operator("graph.bake")
@@ -195,6 +224,9 @@ class GRAPH_MT_key(bpy.types.Menu):
layout.operator("graph.copy")
layout.operator("graph.paste")
+ layout.separator()
+ layout.operator("graph.euler_filter", text="Discontinuity (Euler) Filter")
+
class GRAPH_MT_key_transform(bpy.types.Menu):
bl_label = "Transform"
@@ -210,11 +242,11 @@ class GRAPH_MT_key_transform(bpy.types.Menu):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_image.py b/release/scripts/ui/space_image.py
index 7b3954a2e74..433c12b0620 100644
--- a/release/scripts/ui/space_image.py
+++ b/release/scripts/ui/space_image.py
@@ -252,6 +252,48 @@ class IMAGE_MT_uvs(bpy.types.Menu):
layout.menu("IMAGE_MT_uvs_showhide")
+class IMAGE_MT_uvs_select_mode(bpy.types.Menu):
+ bl_label = "UV Select Mode"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.operator_context = 'INVOKE_REGION_WIN'
+ toolsettings = context.tool_settings
+
+ # do smart things depending on whether uv_select_sync is on
+
+ if toolsettings.use_uv_select_sync:
+ prop = layout.operator("wm.context_set_value", text="Vertex", icon='VERTEXSEL')
+ prop.value = "(True, False, False)"
+ prop.data_path = "tool_settings.mesh_select_mode"
+
+ prop = layout.operator("wm.context_set_value", text="Edge", icon='EDGESEL')
+ prop.value = "(False, True, False)"
+ prop.data_path = "tool_settings.mesh_select_mode"
+
+ prop = layout.operator("wm.context_set_value", text="Face", icon='FACESEL')
+ prop.value = "(False, False, True)"
+ prop.data_path = "tool_settings.mesh_select_mode"
+
+ else:
+ prop = layout.operator("wm.context_set_string", text="Vertex", icon='UV_VERTEXSEL')
+ prop.value = "VERTEX"
+ prop.data_path = "tool_settings.uv_select_mode"
+
+ prop = layout.operator("wm.context_set_string", text="Edge", icon='UV_EDGESEL')
+ prop.value = "EDGE"
+ prop.data_path = "tool_settings.uv_select_mode"
+
+ prop = layout.operator("wm.context_set_string", text="Face", icon='UV_FACESEL')
+ prop.value = "FACE"
+ prop.data_path = "tool_settings.uv_select_mode"
+
+ prop = layout.operator("wm.context_set_string", text="Island", icon='UV_ISLANDSEL')
+ prop.value = "ISLAND"
+ prop.data_path = "tool_settings.uv_select_mode"
+
+
class IMAGE_HT_header(bpy.types.Header):
bl_space_type = 'IMAGE_EDITOR'
@@ -391,7 +433,7 @@ class IMAGE_PT_game_properties(bpy.types.Panel):
col.prop(ima, "use_tiles")
sub = col.column(align=True)
- sub.active = ima.tiles or ima.use_animation
+ sub.active = ima.use_tiles or ima.use_animation
sub.prop(ima, "tiles_x", text="X")
sub.prop(ima, "tiles_y", text="Y")
@@ -619,6 +661,26 @@ class IMAGE_PT_tools_brush_texture(BrushButtonsPanel, bpy.types.Panel):
col.template_ID_preview(brush, "texture", new="texture.new", rows=3, cols=8)
+class IMAGE_PT_tools_brush_tool(BrushButtonsPanel, bpy.types.Panel):
+ bl_label = "Tool"
+ bl_options = {'DEFAULT_CLOSED'}
+
+ def draw(self, context):
+ layout = self.layout
+ settings = context.tool_settings.image_paint
+ brush = settings.brush
+
+ col = layout.column(align=True)
+
+ col.prop(brush, "imagepaint_tool", expand=False, text="")
+
+ row = layout.row(align=True)
+ row.prop(brush, "use_paint_sculpt", text="", icon='SCULPTMODE_HLT')
+ row.prop(brush, "use_paint_vertex", text="", icon='VPAINT_HLT')
+ row.prop(brush, "use_paint_weight", text="", icon='WPAINT_HLT')
+ row.prop(brush, "use_paint_texture", text="", icon='TPAINT_HLT')
+
+
class IMAGE_PT_paint_stroke(BrushButtonsPanel, bpy.types.Panel):
bl_label = "Paint Stroke"
bl_options = {'DEFAULT_CLOSED'}
@@ -665,11 +727,11 @@ class IMAGE_PT_paint_curve(BrushButtonsPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_info.py b/release/scripts/ui/space_info.py
index 349dd333930..6c392cb9a3d 100644
--- a/release/scripts/ui/space_info.py
+++ b/release/scripts/ui/space_info.py
@@ -28,6 +28,7 @@ class INFO_HT_header(bpy.types.Header):
wm = context.window_manager
window = context.window
+ sinfo = context.space_data
scene = context.scene
rd = scene.render
@@ -49,8 +50,7 @@ class INFO_HT_header(bpy.types.Header):
layout.separator()
else:
layout.template_ID(context.window, "screen", new="screen.new", unlink="screen.delete")
-
- layout.template_ID(context.screen, "scene", new="scene.new", unlink="scene.delete")
+ layout.template_ID(context.screen, "scene", new="scene.new", unlink="scene.delete")
layout.separator()
@@ -68,6 +68,34 @@ class INFO_HT_header(bpy.types.Header):
# XXX: this should be right-aligned to the RHS of the region
layout.operator("wm.window_fullscreen_toggle", icon='FULLSCREEN_ENTER', text="")
+ # XXX: BEFORE RELEASE, MOVE FILE MENU OUT OF INFO!!!
+ """
+ row = layout.row(align=True)
+ row.prop(sinfo, "show_report_debug", text="Debug")
+ row.prop(sinfo, "show_report_info", text="Info")
+ row.prop(sinfo, "show_report_operator", text="Operators")
+ row.prop(sinfo, "show_report_warning", text="Warnings")
+ row.prop(sinfo, "show_report_error", text="Errors")
+
+ row = layout.row()
+ row.enabled = sinfo.show_report_operator
+ row.operator("info.report_replay")
+
+ row.menu("INFO_MT_report")
+ """
+
+
+class INFO_MT_report(bpy.types.Menu):
+ bl_label = "Report"
+
+ def draw(self, context):
+ layout = self.layout
+ layout.column()
+ layout.operator("console.select_all_toggle")
+ layout.operator("console.select_border")
+ layout.operator("console.report_delete")
+ layout.operator("console.report_copy")
+
class INFO_MT_file(bpy.types.Menu):
bl_label = "File"
@@ -97,7 +125,8 @@ class INFO_MT_file(bpy.types.Menu):
layout.operator("screen.userpref_show", text="User Preferences...", icon='PREFERENCES')
layout.operator_context = 'EXEC_AREA'
- layout.operator("wm.read_homefile", text="Load Factory Settings").factory = True
+ layout.operator("wm.save_homefile")
+ layout.operator("wm.read_factory_settings")
layout.separator()
@@ -119,7 +148,7 @@ class INFO_MT_file(bpy.types.Menu):
layout.separator()
layout.operator_context = 'EXEC_AREA'
- layout.operator("wm.exit_blender", text="Quit", icon='QUIT')
+ layout.operator("wm.quit_blender", text="Quit", icon='QUIT')
class INFO_MT_file_import(bpy.types.Menu):
@@ -190,6 +219,22 @@ class INFO_MT_curve_add(bpy.types.Menu):
layout.operator("curve.primitive_nurbs_path_add", icon='CURVE_PATH', text="Path")
+class INFO_MT_edit_curve_add(bpy.types.Menu):
+ bl_idname = "INFO_MT_edit_curve_add"
+ bl_label = "Add"
+
+ def draw(self, context):
+ is_surf = context.active_object.type == 'SURFACE'
+
+ layout = self.layout
+ layout.operator_context = 'INVOKE_REGION_WIN'
+
+ if is_surf:
+ INFO_MT_surface_add.draw(self, context)
+ else:
+ INFO_MT_curve_add.draw(self, context)
+
+
class INFO_MT_surface_add(bpy.types.Menu):
bl_idname = "INFO_MT_surface_add"
bl_label = "Surface"
@@ -231,10 +276,10 @@ class INFO_MT_add(bpy.types.Menu):
#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_context = 'INVOKE_REGION_WIN'
layout.operator("object.text_add", text="Text", icon='OUTLINER_OB_FONT')
layout.separator()
- layout.operator_context = 'INVOKE_REGION_WIN'
layout.menu("INFO_MT_armature_add", icon='OUTLINER_OB_ARMATURE')
layout.operator("object.add", text="Lattice", icon='OUTLINER_OB_LATTICE').type = 'LATTICE'
layout.operator("object.add", text="Empty", icon='OUTLINER_OB_EMPTY').type = 'EMPTY'
@@ -302,10 +347,12 @@ class INFO_MT_help(bpy.types.Menu):
bl_label = "Help"
def draw(self, context):
+ import sys
+
layout = self.layout
layout.operator("wm.url_open", text="Manual", icon='HELP').url = 'http://wiki.blender.org/index.php/Doc:Manual'
- layout.operator("wm.url_open", text="Release Log", icon='URL').url = 'http://www.blender.org/development/release-logs/blender-250/'
+ layout.operator("wm.url_open", text="Release Log", icon='URL').url = 'http://www.blender.org/development/release-logs/blender-256-beta/'
layout.separator()
@@ -318,7 +365,11 @@ class INFO_MT_help(bpy.types.Menu):
layout.separator()
layout.operator("wm.url_open", text="Python API Reference", icon='URL').url = "http://www.blender.org/documentation/blender_python_api_%s/contents.html" % "_".join(str(v) for v in bpy.app.version)
layout.operator("help.operator_cheat_sheet", icon='TEXT')
+ layout.operator("wm.sysinfo", icon='TEXT')
layout.separator()
+ if sys.platform == "win32":
+ layout.operator("wm.toggle_console", icon='CONSOLE')
+ layout.separator()
layout.operator("anim.update_data_paths", text="FCurve/Driver 2.54 fix", icon='HELP')
layout.separator()
layout.operator("wm.splash")
@@ -339,7 +390,7 @@ class HELP_OT_operator_cheat_sheet(bpy.types.Operator):
for op_submodule_name in dir(op_module):
op = getattr(op_module, op_submodule_name)
text = repr(op)
- if text.startswith('bpy.ops.'):
+ if text.split("\n")[-1].startswith('bpy.ops.'):
op_strings.append(text)
tot += 1
@@ -353,11 +404,11 @@ class HELP_OT_operator_cheat_sheet(bpy.types.Operator):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_logic.py b/release/scripts/ui/space_logic.py
index 44c6f5fd684..54dde61e90a 100644
--- a/release/scripts/ui/space_logic.py
+++ b/release/scripts/ui/space_logic.py
@@ -90,11 +90,11 @@ class LOGIC_MT_view(bpy.types.Menu):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_nla.py b/release/scripts/ui/space_nla.py
index 3b187d707ec..13afc97f913 100644
--- a/release/scripts/ui/space_nla.py
+++ b/release/scripts/ui/space_nla.py
@@ -39,6 +39,7 @@ class NLA_HT_header(bpy.types.Header):
sub.menu("NLA_MT_view")
sub.menu("NLA_MT_select")
+ sub.menu("NLA_MT_marker")
sub.menu("NLA_MT_edit")
sub.menu("NLA_MT_add")
@@ -93,6 +94,25 @@ class NLA_MT_select(bpy.types.Menu):
layout.operator("nla.select_border", text="Border Axis Range").axis_range = True
+class NLA_MT_marker(bpy.types.Menu):
+ bl_label = "Marker"
+
+ def draw(self, context):
+ layout = self.layout
+
+ #layout.operator_context = 'EXEC_REGION_WIN'
+
+ layout.column()
+ layout.operator("marker.add", "Add Marker")
+ layout.operator("marker.duplicate", text="Duplicate Marker")
+ layout.operator("marker.delete", text="Delete Marker")
+
+ layout.separator()
+
+ layout.operator("marker.rename", text="Rename Marker")
+ layout.operator("marker.move", text="Grab/Move Marker")
+
+
class NLA_MT_edit(bpy.types.Menu):
bl_label = "Edit"
@@ -117,11 +137,17 @@ class NLA_MT_edit(bpy.types.Menu):
layout.separator()
layout.operator("nla.apply_scale")
layout.operator("nla.clear_scale")
+ layout.operator("nla.action_sync_length").active = False
layout.separator()
+ layout.operator("nla.swap")
layout.operator("nla.move_up")
layout.operator("nla.move_down")
+ # TODO: this really belongs more in a "channel" (or better, "track") menu
+ layout.separator()
+ layout.operator_menu_enum("anim.channels_move", "direction", text="Track Ordering...")
+
layout.separator()
# TODO: names of these tools for 'tweakmode' need changing?
if scene.is_nla_tweakmode:
@@ -162,11 +188,11 @@ class NLA_MT_edit_transform(bpy.types.Menu):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_node.py b/release/scripts/ui/space_node.py
index e37f6ffe4ae..aaf14813ee5 100644
--- a/release/scripts/ui/space_node.py
+++ b/release/scripts/ui/space_node.py
@@ -68,6 +68,10 @@ class NODE_HT_header(bpy.types.Header):
layout.prop(scene, "use_nodes")
layout.prop(scene.render, "use_free_unused_nodes", text="Free Unused")
layout.prop(snode, "show_backdrop")
+ if snode.show_backdrop:
+ row = layout.row(align=True)
+ row.prop(snode, "backdrop_channels", text="", expand=True)
+ layout.prop(snode, "use_auto_render")
layout.separator()
@@ -158,14 +162,46 @@ class NODE_MT_node(bpy.types.Menu):
layout.separator()
layout.operator("node.show_cyclic_dependencies")
+ layout.operator("node.read_renderlayers")
+ layout.operator("node.read_fullsamplelayers")
+
+
+# Node Backdrop options
+class NODE_PT_properties(bpy.types.Panel):
+ bl_space_type = 'NODE_EDITOR'
+ bl_region_type = 'UI'
+ bl_label = "Backdrop"
+
+ @classmethod
+ def poll(cls, context):
+ snode = context.space_data
+ return snode.tree_type == 'COMPOSITING'
+
+ def draw_header(self, context):
+ snode = context.space_data
+ self.layout.prop(snode, "show_backdrop", text="")
+
+ def draw(self, context):
+ layout = self.layout
+
+ snode = context.space_data
+ layout.active = snode.show_backdrop
+ layout.prop(snode, "backdrop_channels", text="")
+ layout.prop(snode, "backdrop_zoom", text="Zoom")
+
+ col = layout.column(align=True)
+ col.label(text="Offset:")
+ col.prop(snode, "backdrop_x", text="X")
+ col.prop(snode, "backdrop_y", text="Y")
+ col.operator("node.backimage_move", text="Move")
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_outliner.py b/release/scripts/ui/space_outliner.py
index 38e749c4a75..219dd1de117 100644
--- a/release/scripts/ui/space_outliner.py
+++ b/release/scripts/ui/space_outliner.py
@@ -118,11 +118,11 @@ class OUTLINER_MT_edit_datablocks(bpy.types.Menu):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_sequencer.py b/release/scripts/ui/space_sequencer.py
index a9dd0663592..3ae1e35aaf8 100644
--- a/release/scripts/ui/space_sequencer.py
+++ b/release/scripts/ui/space_sequencer.py
@@ -42,8 +42,6 @@ class SEQUENCER_HT_header(bpy.types.Header):
sub = row.row(align=True)
sub.menu("SEQUENCER_MT_view")
- row.separator()
-
if (st.view_type == 'SEQUENCER') or (st.view_type == 'SEQUENCER_PREVIEW'):
sub.menu("SEQUENCER_MT_select")
sub.menu("SEQUENCER_MT_marker")
@@ -136,6 +134,7 @@ class SEQUENCER_MT_view(bpy.types.Menu):
if (st.view_type == 'PREVIEW') or (st.view_type == 'SEQUENCER_PREVIEW'):
layout.operator_context = 'INVOKE_REGION_PREVIEW'
layout.operator("sequencer.view_all_preview", text='Fit preview in window')
+ layout.operator("sequencer.view_zoom_ratio", text='Show preview 1:1').ratio = 1.0
layout.operator_context = 'INVOKE_DEFAULT'
# # XXX, invokes in the header view
@@ -183,13 +182,17 @@ class SEQUENCER_MT_marker(bpy.types.Menu):
def draw(self, context):
layout = self.layout
+ #layout.operator_context = 'EXEC_REGION_WIN'
+
layout.column()
- layout.operator("marker.add", text="Add Marker")
+ layout.operator("marker.add", "Add Marker")
layout.operator("marker.duplicate", text="Duplicate Marker")
- layout.operator("marker.move", text="Grab/Move Marker")
layout.operator("marker.delete", text="Delete Marker")
+
layout.separator()
- layout.label(text="ToDo: Name Marker")
+
+ layout.operator("marker.rename", text="Rename Marker")
+ layout.operator("marker.move", text="Grab/Move Marker")
#layout.operator("sequencer.sound_strip_add", text="Transform Markers") # toggle, will be rna - (sseq->flag & SEQ_MARKER_TRANS)
@@ -202,7 +205,12 @@ class SEQUENCER_MT_add(bpy.types.Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
layout.column()
- layout.operator_menu_enum("sequencer.scene_strip_add", "scene", text="Scene...")
+ if len(bpy.data.scenes) > 10:
+ layout.operator_context = 'INVOKE_DEFAULT'
+ layout.operator("sequencer.scene_strip_add", text="Scene...")
+ else:
+ 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")
@@ -295,6 +303,7 @@ class SEQUENCER_MT_strip(bpy.types.Menu):
layout.separator()
layout.operator("sequencer.reload")
layout.operator("sequencer.reassign_inputs")
+ layout.operator("sequencer.swap_inputs")
layout.separator()
layout.operator("sequencer.lock")
layout.operator("sequencer.unlock")
@@ -384,6 +393,16 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, bpy.types.Panel):
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))
+ elem = False
+
+ if strip.type == 'IMAGE':
+ elem = strip.getStripElem(frame_current)
+ elif strip.type == 'MOVIE':
+ elem = strip.elements[0]
+
+ if elem and elem.orig_width > 0 and elem.orig_height > 0:
+ col.label(text="Orig Dim: %dx%d" % (elem.orig_width, elem.orig_height))
+
class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel):
bl_label = "Effect Strip"
@@ -407,6 +426,13 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel):
layout = self.layout
strip = act_strip(context)
+ if strip.input_count > 0:
+ col = layout.column()
+ col.prop(strip, "input_1")
+ if strip.input_count > 1:
+ col.prop(strip, "input_2")
+ if strip.input_count > 2:
+ col.prop(strip, "input_3")
if strip.type == 'COLOR':
layout.prop(strip, "color")
@@ -435,12 +461,17 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel):
row.prop(strip, "use_only_boost")
elif strip.type == 'SPEED':
- layout.prop(strip, "global_speed")
-
- flow = layout.column_flow()
- flow.prop(strip, "use_curve_velocity")
- flow.prop(strip, "use_curve_compress_y")
- flow.prop(strip, "use_frame_blend")
+ layout.prop(strip, "use_default_fade", "Stretch to input strip length")
+ if not strip.use_default_fade:
+ layout.prop(strip, "use_as_speed")
+ if strip.use_as_speed:
+ layout.prop(strip, "speed_factor")
+ else:
+ layout.prop(strip, "speed_factor", text="Frame number")
+ layout.prop(strip, "scale_to_length")
+
+ #doesn't work currently
+ #layout.prop(strip, "use_frame_blend")
elif strip.type == 'TRANSFORM':
self.draw_panel_transform(strip)
@@ -460,7 +491,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, bpy.types.Panel):
col = layout.column(align=True)
if strip.type == 'SPEED':
- col.prop(strip, "speed_fader", text="Speed fader")
+ col.prop(strip, "multiply_speed")
elif strip.type in ('CROSS', 'GAMMA_CROSS', 'PLUGIN', 'WIPE'):
col.prop(strip, "use_default_fade", "Default fade")
if not strip.use_default_fade:
@@ -562,6 +593,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, bpy.types.Panel):
col = split.column()
col.prop(strip, "filepath", text="")
col.prop(strip, "mpeg_preseek", text="MPEG Preseek")
+
# TODO, sound???
# end drawing filename
@@ -579,8 +611,14 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, bpy.types.Panel):
col.prop(strip.crop, "min_y")
col.prop(strip.crop, "max_x")
+ if not isinstance(strip, bpy.types.EffectSequence):
+ col = layout.column(align=True)
+ col.label(text="Trim Duration (hard):")
+ col.prop(strip, "animation_offset_start", text="Start")
+ col.prop(strip, "animation_offset_end", text="End")
+
col = layout.column(align=True)
- col.label(text="Trim Duration:")
+ col.label(text="Trim Duration (soft):")
col.prop(strip, "frame_offset_start", text="Start")
col.prop(strip, "frame_offset_end", text="End")
@@ -650,6 +688,9 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, bpy.types.Panel):
layout.label(text="Camera Override")
layout.template_ID(strip, "scene_camera")
+ sce = strip.scene
+ layout.label(text="Original frame range: %d-%d (%d)" % (sce.frame_start, sce.frame_end, sce.frame_end - sce.frame_start + 1))
+
class SEQUENCER_PT_filter(SequencerButtonsPanel, bpy.types.Panel):
bl_label = "Filter"
@@ -757,9 +798,10 @@ class SEQUENCER_PT_preview(SequencerButtonsPanel_Output, bpy.types.Panel):
render = context.scene.render
col = layout.column()
+ col.active = False # Currently only opengl preview works!
col.prop(render, "use_sequencer_gl_preview", text="Open GL Preview")
col = layout.column()
- col.active = render.use_sequencer_gl_preview
+ #col.active = render.use_sequencer_gl_preview
col.prop(render, "sequencer_gl_preview", text="")
'''
@@ -789,11 +831,11 @@ class SEQUENCER_PT_view(SequencerButtonsPanel_Output, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_text.py b/release/scripts/ui/space_text.py
index 163fa07e1d6..df5967c9128 100644
--- a/release/scripts/ui/space_text.py
+++ b/release/scripts/ui/space_text.py
@@ -174,7 +174,7 @@ class TEXT_MT_text(bpy.types.Menu):
layout.column()
layout.operator("text.run_script")
- #ifndef DISABLE_PYTHON
+ #ifdef WITH_PYTHON
# XXX if(BPY_is_pyconstraint(text))
# XXX uiMenuItemO(head, 0, "text.refresh_pyconstraints");
#endif
@@ -295,11 +295,11 @@ class TEXT_MT_toolbox(bpy.types.Menu):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_time.py b/release/scripts/ui/space_time.py
index de295d0fe76..046274abc89 100644
--- a/release/scripts/ui/space_time.py
+++ b/release/scripts/ui/space_time.py
@@ -57,8 +57,16 @@ class TIME_HT_header(bpy.types.Header):
row.operator("screen.frame_jump", text="", icon='REW').end = False
row.operator("screen.keyframe_jump", text="", icon='PREV_KEYFRAME').next = False
if not screen.is_animation_playing:
- row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True
- row.operator("screen.animation_play", text="", icon='PLAY')
+ # if using JACK and A/V sync:
+ # hide the play-reversed button
+ # since JACK transport doesn't support reversed playback
+ if (context.user_preferences.system.audio_device == 'JACK' and scene.sync_mode == 'AUDIO_SYNC'):
+ sub = row.row()
+ sub.scale_x = 2.0
+ sub.operator("screen.animation_play", text="", icon='PLAY')
+ else:
+ row.operator("screen.animation_play", text="", icon='PLAY_REVERSE').reverse = True
+ row.operator("screen.animation_play", text="", icon='PLAY')
else:
sub = row.row()
sub.scale_x = 2.0
@@ -66,16 +74,17 @@ class TIME_HT_header(bpy.types.Header):
row.operator("screen.keyframe_jump", text="", icon='NEXT_KEYFRAME').next = True
row.operator("screen.frame_jump", text="", icon='FF').end = True
+ layout.prop(scene, "sync_mode", text="")
+
+ layout.separator()
+
row = layout.row(align=True)
row.prop(tools, "use_keyframe_insert_auto", text="", toggle=True)
+ row.prop(tools, "use_keyframe_insert_keyingset", text="", toggle=True)
if screen.is_animation_playing and tools.use_keyframe_insert_auto:
subsub = row.row()
subsub.prop(tools, "use_record_with_nla", toggle=True)
- layout.prop(scene, "sync_mode", text="")
-
- layout.separator()
-
row = layout.row(align=True)
row.prop_search(scene.keying_sets_all, "active", scene, "keying_sets_all", text="")
row.operator("anim.keyframe_insert", text="", icon='KEY_HLT')
@@ -136,15 +145,12 @@ class TIME_MT_frame(bpy.types.Menu):
layout.operator("marker.add", text="Add Marker")
layout.operator("marker.duplicate", text="Duplicate Marker")
- layout.operator("marker.move", text="Grab/Move Marker")
layout.operator("marker.delete", text="Delete Marker")
- # it was ok for riscos... ok TODO, operator
- for marker in context.scene.timeline_markers:
- if marker.select:
- layout.separator()
- layout.prop(marker, "name", text="", icon='MARKER_HLT')
- break
+ layout.separator()
+
+ layout.operator("marker.rename", text="Rename Marker")
+ layout.operator("marker.move", text="Grab/Move Marker")
layout.separator()
@@ -163,16 +169,16 @@ class TIME_MT_playback(bpy.types.Menu):
def draw(self, context):
layout = self.layout
- st = context.space_data
+ screen = context.screen
scene = context.scene
- layout.prop(st, "use_play_top_left_3d_editor")
- layout.prop(st, "use_play_3d_editors")
- layout.prop(st, "use_play_animation_editors")
- layout.prop(st, "use_play_properties_editors")
- layout.prop(st, "use_play_image_editors")
- layout.prop(st, "use_play_sequence_editors")
- layout.prop(st, "use_play_node_editors")
+ layout.prop(screen, "use_play_top_left_3d_editor")
+ layout.prop(screen, "use_play_3d_editors")
+ layout.prop(screen, "use_play_animation_editors")
+ layout.prop(screen, "use_play_properties_editors")
+ layout.prop(screen, "use_play_image_editors")
+ layout.prop(screen, "use_play_sequence_editors")
+ layout.prop(screen, "use_play_node_editors")
layout.separator()
@@ -194,11 +200,11 @@ class TIME_MT_autokey(bpy.types.Menu):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py
index d15dc8934ca..79bdff8ad93 100644
--- a/release/scripts/ui/space_userpref.py
+++ b/release/scripts/ui/space_userpref.py
@@ -92,6 +92,7 @@ class USERPREF_HT_header(bpy.types.Header):
layout.operator("wm.keyconfig_import")
elif userpref.active_section == 'ADDONS':
layout.operator("wm.addon_install")
+ layout.menu("USERPREF_MT_addons_dev_guides", text=" Addons Developer Guides", icon='INFO')
elif userpref.active_section == 'THEMES':
layout.operator("ui.reset_default_theme")
@@ -127,7 +128,11 @@ class USERPREF_MT_splash(bpy.types.Menu):
row.label("")
row = split.row()
row.label("Interaction:")
- row.menu("USERPREF_MT_interaction_presets", text=bpy.types.USERPREF_MT_interaction_presets.bl_label)
+ # XXX, no redraws
+ # text = bpy.path.display_name(context.window_manager.keyconfigs.active.name)
+ # if not text:
+ # text = "Blender (default)"
+ row.menu("USERPREF_MT_keyconfigs", text="Preset")
class USERPREF_PT_interface(bpy.types.Panel):
@@ -152,6 +157,7 @@ class USERPREF_PT_interface(bpy.types.Panel):
col = row.column()
col.label(text="Display:")
col.prop(view, "show_tooltips")
+ col.prop(view, "show_tooltips_python")
col.prop(view, "show_object_info", text="Object Info")
col.prop(view, "show_large_cursors")
col.prop(view, "show_view_name", text="View Name")
@@ -297,7 +303,6 @@ class USERPREF_PT_edit(bpy.types.Panel):
sub = col.column()
# sub.active = edit.use_keyframe_insert_auto # incorrect, timeline can enable
- sub.prop(edit, "use_keyframe_insert_keyingset", text="Only Insert for Keying Set")
sub.prop(edit, "use_keyframe_insert_available", text="Only Insert Available")
col.separator()
@@ -318,8 +323,7 @@ class USERPREF_PT_edit(bpy.types.Panel):
row.separator()
col = row.column()
- row = col.row(align=True)
- row.prop(edit, "sculpt_paint_overlay_color", text="Sculpt Overlay Color")
+ col.prop(edit, "sculpt_paint_overlay_color", text="Sculpt Overlay Color")
col.separator()
col.separator()
@@ -424,6 +428,8 @@ class USERPREF_PT_system(bpy.types.Panel):
#col.prop(system, "use_antialiasing")
col.label(text="Window Draw Method:")
col.prop(system, "window_draw_method", text="")
+ col.label(text="Text Draw Options:")
+ col.prop(system, "use_text_antialiasing")
col.label(text="Textures:")
col.prop(system, "gl_texture_limit", text="Limit Size")
col.prop(system, "texture_time_out", text="Time Out")
@@ -692,14 +698,16 @@ class USERPREF_PT_file(bpy.types.Panel):
col.prop(paths, "use_load_ui")
col.prop(paths, "use_filter_files")
col.prop(paths, "show_hidden_files_datablocks")
+ col.prop(paths, "hide_recent_locations")
+ col.prop(paths, "show_thumbnails")
col.separator()
col.separator()
- col.label(text="Auto Save:")
col.prop(paths, "save_version")
col.prop(paths, "recent_files")
col.prop(paths, "use_save_preview_images")
+ col.label(text="Auto Save:")
col.prop(paths, "use_auto_save_temporary_files")
sub = col.column()
sub.active = paths.use_auto_save_temporary_files
@@ -736,6 +744,7 @@ class USERPREF_PT_input(InputKeyMapPanel):
sub1.active = (inputs.select_mouse == 'RIGHT')
sub1.prop(inputs, "use_mouse_emulate_3_button")
sub.prop(inputs, "use_mouse_continuous")
+ sub.prop(inputs, "drag_threshold")
sub.label(text="Select With:")
sub.row().prop(inputs, "select_mouse", expand=True)
@@ -801,6 +810,20 @@ class USERPREF_PT_input(InputKeyMapPanel):
#print("runtime", time.time() - start)
+class USERPREF_MT_addons_dev_guides(bpy.types.Menu):
+ bl_label = "Addons develoment guides"
+
+ # menu to open webpages with addons development guides
+ def draw(self, context):
+ layout = self.layout
+ layout.operator('wm.url_open', text='API Concepts'
+ ).url = 'http://wiki.blender.org/index.php/Dev:2.5/Py/API/Intro'
+ layout.operator('wm.url_open', text='Addons guidelines',
+ ).url = 'http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Guidelines/Addons'
+ layout.operator('wm.url_open', text='How to share your addon',
+ ).url = 'http://wiki.blender.org/index.php/Dev:Py/Sharing'
+
+
class USERPREF_PT_addons(bpy.types.Panel):
bl_space_type = 'USER_PREFERENCES'
bl_label = "Addons"
@@ -808,6 +831,7 @@ class USERPREF_PT_addons(bpy.types.Panel):
bl_options = {'HIDE_HEADER'}
_addons_cats = None
+ _addons_sups = None
_addons_fake_modules = {}
@classmethod
@@ -827,10 +851,18 @@ class USERPREF_PT_addons(bpy.types.Panel):
modules = []
loaded_modules = set()
+
+ # RELEASE SCRIPTS: official scripts distributed in Blender releases
paths = bpy.utils.script_paths("addons")
- # if folder addons_contrib/ exists, scripts in there will be loaded
+
+ # CONTRIB SCRIPTS: good for testing but not official scripts yet
+ # if folder addons_contrib/ exists, scripts in there will be loaded too
paths += bpy.utils.script_paths("addons_contrib")
+ # EXTERN SCRIPTS: external projects scripts
+ # if folder addons_extern/ exists, scripts in there will be loaded too
+ paths += bpy.utils.script_paths("addons_extern")
+
if bpy.app.debug:
t_main = time.time()
@@ -840,35 +872,46 @@ class USERPREF_PT_addons(bpy.types.Panel):
print("fake_module", mod_name, mod_path)
import ast
ModuleType = type(ast)
+ file_mod = open(mod_path, "r", encoding='UTF-8')
if speedy:
lines = []
- line_iter = iter(open(mod_path, "r", encoding='UTF-8'))
+ line_iter = iter(file_mod)
l = ""
- while not l.startswith("bl_addon_info"):
+ while not l.startswith("bl_info"):
l = line_iter.readline()
if len(l) == 0:
break
while l.rstrip():
lines.append(l)
l = line_iter.readline()
- del line_iter
data = "".join(lines)
else:
- data = open(mod_path, "r").read()
+ data = file_mod.read()
+
+ file_mod.close()
+
+ try:
+ ast_data = ast.parse(data, filename=mod_path)
+ except:
+ print("Syntax error 'ast.parse' can't read %r" % mod_path)
+ import traceback
+ traceback.print_exc()
+ ast_data = None
- ast_data = ast.parse(data, filename=mod_path)
body_info = None
- for body in ast_data.body:
- if body.__class__ == ast.Assign:
- if len(body.targets) == 1:
- if getattr(body.targets[0], "id", "") == "bl_addon_info":
- body_info = body
- break
+
+ if ast_data:
+ for body in ast_data.body:
+ if body.__class__ == ast.Assign:
+ if len(body.targets) == 1:
+ if getattr(body.targets[0], "id", "") == "bl_info":
+ body_info = body
+ break
if body_info:
mod = ModuleType(mod_name)
- mod.bl_addon_info = ast.literal_eval(body.value)
+ mod.bl_info = ast.literal_eval(body.value)
mod.__file__ = mod_path
mod.__time__ = os.path.getmtime(mod_path)
return mod
@@ -898,7 +941,7 @@ class USERPREF_PT_addons(bpy.types.Panel):
del modules_stale
mod_list = list(USERPREF_PT_addons._addons_fake_modules.values())
- mod_list.sort(key=lambda mod: (mod.bl_addon_info['category'], mod.bl_addon_info['name']))
+ mod_list.sort(key=lambda mod: (mod.bl_info['category'], mod.bl_info['name']))
return mod_list
def draw(self, context):
@@ -918,21 +961,35 @@ class USERPREF_PT_addons(bpy.types.Panel):
bpy.types.WindowManager.addon_search = bpy.props.StringProperty(name="Search", description="Search within the selected filter")
USERPREF_PT_addons._addons_cats = cats
+ sups = {info["support"] for mod, info in addons}
+ sups.discard("")
+
+ if USERPREF_PT_addons._addons_sups != sups:
+ bpy.types.WindowManager.addon_support = bpy.props.EnumProperty(items=[(sup, sup.title(), "") for sup in reversed(sorted(sups))], name="Support", description="Display support level", default={'OFFICIAL', 'COMMUNITY'}, options={'ENUM_FLAG'})
+ USERPREF_PT_addons._addons_sups = sups
+
split = layout.split(percentage=0.2)
col = split.column()
col.prop(context.window_manager, "addon_search", text="", icon='VIEWZOOM')
- col.prop(context.window_manager, "addon_filter", text="Filter", expand=True)
+ col.prop(context.window_manager, "addon_filter", expand=True)
+
+ col.label(text="Supported Level")
+ col.prop(context.window_manager, "addon_support", expand=True)
col = split.column()
filter = context.window_manager.addon_filter
search = context.window_manager.addon_search.lower()
+ support = context.window_manager.addon_support
for mod, info in addons:
module_name = mod.__name__
is_enabled = module_name in used_ext
+ if info["support"] not in support:
+ continue
+
# check if add-on should be visible with current filters
if (filter == "All") or \
(filter == info["category"]) or \
@@ -959,6 +1016,14 @@ class USERPREF_PT_addons(bpy.types.Panel):
if info["warning"]:
rowsub.label(icon='ERROR')
+ # icon showing support level.
+ if info["support"] == 'OFFICIAL':
+ rowsub.label(icon='FILE_BLEND')
+ elif info["support"] == 'COMMUNITY':
+ rowsub.label(icon='POSE_DATA')
+ else:
+ rowsub.label(icon='QUESTION')
+
if is_enabled:
row.operator("wm.addon_disable", icon='CHECKBOX_HLT', text="", emboss=False).module = module_name
else:
@@ -1026,15 +1091,15 @@ class USERPREF_PT_addons(bpy.types.Panel):
from bpy.props import *
-def addon_info_get(mod, info_basis={"name": "", "author": "", "version": (), "blender": (), "api": 0, "location": "", "description": "", "wiki_url": "", "tracker_url": "", "category": "", "warning": "", "show_expanded": False}):
- addon_info = getattr(mod, "bl_addon_info", {})
+def addon_info_get(mod, info_basis={"name": "", "author": "", "version": (), "blender": (), "api": 0, "location": "", "description": "", "wiki_url": "", "tracker_url": "", "support": 'COMMUNITY', "category": "", "warning": "", "show_expanded": False}):
+ addon_info = getattr(mod, "bl_info", {})
# avoid re-initializing
if "_init" in addon_info:
return addon_info
if not addon_info:
- mod.bl_addon_info = addon_info
+ mod.bl_info = addon_info
for key, value in info_basis.items():
addon_info.setdefault(key, value)
@@ -1084,29 +1149,60 @@ class WM_OT_addon_install(bpy.types.Operator):
bl_idname = "wm.addon_install"
bl_label = "Install Add-On..."
- module = StringProperty(name="Module", description="Module name of the addon to disable")
+ overwrite = BoolProperty(name="Overwrite", description="Remove existing addons with the same ID", default=True)
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'})
filter_glob = StringProperty(default="*.py;*.zip", options={'HIDDEN'})
+ @staticmethod
+ def _module_remove(path_addons, module):
+ module = os.path.splitext(module)[0]
+ for f in os.listdir(path_addons):
+ f_base = os.path.splitext(f)[0]
+ if f_base == module:
+ f_full = os.path.join(path_addons, f)
+
+ if os.path.isdir(f_full):
+ os.rmdir(f_full)
+ else:
+ os.remove(f_full)
+
def execute(self, context):
import traceback
import zipfile
pyfile = self.filepath
- path_addons = bpy.utils.script_paths("addons")[-1]
+ # dont use bpy.utils.script_paths("addons") because we may not be able to write to it.
+ path_addons = bpy.utils.user_resource('SCRIPTS', "addons", create=True)
+
+ if not path_addons:
+ self.report({'WARNING'}, "Failed to get addons path\n")
+ return {'CANCELLED'}
+
contents = set(os.listdir(path_addons))
#check to see if the file is in compressed format (.zip)
if zipfile.is_zipfile(pyfile):
try:
file_to_extract = zipfile.ZipFile(pyfile, 'r')
+ except:
+ traceback.print_exc()
+ return {'CANCELLED'}
- #extract the file to "addons"
- file_to_extract.extractall(path_addons)
+ if self.overwrite:
+ for f in file_to_extract.namelist():
+ __class__._module_remove(path_addons, f)
+ else:
+ for f in file_to_extract.namelist():
+ path_dest = os.path.join(path_addons, os.path.basename(f))
+ if os.path.exists(path_dest):
+ self.report({'WARNING'}, "File already installed to %r\n" % path_dest)
+ return {'CANCELLED'}
+ try: # extract the file to "addons"
+ file_to_extract.extractall(path_addons)
except:
traceback.print_exc()
return {'CANCELLED'}
@@ -1114,8 +1210,10 @@ class WM_OT_addon_install(bpy.types.Operator):
else:
path_dest = os.path.join(path_addons, os.path.basename(pyfile))
- if os.path.exists(path_dest):
- self.report({'WARNING'}, "File already installed to '%s'\n" % path_dest)
+ if self.overwrite:
+ __class__._module_remove(path_addons, os.path.basename(pyfile))
+ elif os.path.exists(path_dest):
+ self.report({'WARNING'}, "File already installed to %r\n" % path_dest)
return {'CANCELLED'}
#if not compressed file just copy into the addon path
@@ -1148,13 +1246,8 @@ class WM_OT_addon_install(bpy.types.Operator):
return {'FINISHED'}
def invoke(self, context, event):
- paths = bpy.utils.script_paths("addons")
- if not paths:
- self.report({'ERROR'}, "No 'addons' path could be found in " + str(bpy.utils.script_paths()))
- return {'CANCELLED'}
-
wm = context.window_manager
- wm.add_fileselect(self)
+ wm.fileselect_add(self)
return {'RUNNING_MODAL'}
@@ -1183,11 +1276,11 @@ class WM_OT_addon_expand(bpy.types.Operator):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_userpref_keymap.py b/release/scripts/ui/space_userpref_keymap.py
index 0cdebd4734c..a78ef1be36f 100644
--- a/release/scripts/ui/space_userpref_keymap.py
+++ b/release/scripts/ui/space_userpref_keymap.py
@@ -124,10 +124,11 @@ def _merge_keymaps(kc1, kc2):
return merged_keymaps
-class PREFS_MT_keyconfigs(bpy.types.Menu):
+class USERPREF_MT_keyconfigs(bpy.types.Menu):
bl_label = "KeyPresets"
preset_subdir = "keyconfig"
preset_operator = "wm.keyconfig_activate"
+
def draw(self, context):
props = self.layout.operator("wm.context_set_value", text="Blender (default)")
props.data_path = "window_manager.keyconfigs.active"
@@ -279,7 +280,7 @@ class InputKeyMapPanel(bpy.types.Panel):
else:
row.label()
- if kmi.id:
+ if not kmi.is_user_defined:
op = row.operator("wm.keyitem_restore", text="", icon='BACK')
op.item_id = kmi.id
op = row.operator("wm.keyitem_remove", text="", icon='X')
@@ -379,15 +380,15 @@ class InputKeyMapPanel(bpy.types.Panel):
subcol = subsplit.column()
row = subcol.row(align=True)
-
+
#row.prop_search(wm.keyconfigs, "active", wm, "keyconfigs", text="Key Config:")
text = bpy.path.display_name(context.window_manager.keyconfigs.active.name)
if not text:
text = "Blender (default)"
- row.menu("PREFS_MT_keyconfigs", text=text)
+ row.menu("USERPREF_MT_keyconfigs", text=text)
row.operator("wm.keyconfig_preset_add", text="", icon="ZOOMIN")
row.operator("wm.keyconfig_preset_add", text="", icon="ZOOMOUT").remove_active = True
-
+
# layout.context_pointer_set("keyconfig", wm.keyconfigs.active)
# row.operator("wm.keyconfig_remove", text="", icon='X')
@@ -575,7 +576,7 @@ class WM_OT_keyconfig_import(bpy.types.Operator):
def invoke(self, context, event):
wm = context.window_manager
- wm.add_fileselect(self)
+ wm.fileselect_add(self)
return {'RUNNING_MODAL'}
# This operator is also used by interaction presets saving - AddPresetBase
@@ -605,7 +606,7 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
f.write("import bpy\n")
f.write("import os\n\n")
f.write("wm = bpy.context.window_manager\n")
- f.write("kc = wm.keyconfigs.new(os.path.splitext(os.path.basename(__file__))[0])\n\n") # keymap must be created by caller
+ f.write("kc = wm.keyconfigs.new(os.path.splitext(os.path.basename(__file__))[0])\n\n") # keymap must be created by caller
# Generate a list of keymaps to export:
#
@@ -665,7 +666,7 @@ class WM_OT_keyconfig_export(bpy.types.Operator):
def invoke(self, context, event):
wm = context.window_manager
- wm.add_fileselect(self)
+ wm.fileselect_add(self)
return {'RUNNING_MODAL'}
@@ -708,12 +709,18 @@ class WM_OT_keyitem_restore(bpy.types.Operator):
item_id = IntProperty(name="Item Identifier", description="Identifier of the item to remove")
+ @classmethod
+ def poll(cls, context):
+ km = context.keymap
+ return km.is_user_defined
+
def execute(self, context):
wm = context.window_manager
km = context.keymap
kmi = km.items.from_id(self.item_id)
- km.restore_item_to_default(kmi)
+ if not kmi.is_user_defined:
+ km.restore_item_to_default(kmi)
return {'FINISHED'}
@@ -749,8 +756,12 @@ class WM_OT_keyitem_remove(bpy.types.Operator):
item_id = IntProperty(name="Item Identifier", description="Identifier of the item to remove")
+ @classmethod
+ def poll(cls, context):
+ km = context.keymap
+ return km.is_user_defined
+
def execute(self, context):
- wm = context.window_manager
km = context.keymap
kmi = km.items.from_id(self.item_id)
km.items.remove(kmi)
@@ -776,11 +787,11 @@ class WM_OT_keyconfig_remove(bpy.types.Operator):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_view3d.py b/release/scripts/ui/space_view3d.py
index 02f29c7632c..162322a8720 100644
--- a/release/scripts/ui/space_view3d.py
+++ b/release/scripts/ui/space_view3d.py
@@ -152,6 +152,13 @@ class VIEW3D_MT_transform(bpy.types.Menu):
layout.operator("transform.warp", text="Warp")
layout.operator("transform.push_pull", text="Push/Pull")
+ layout.separator()
+
+ layout.operator("transform.translate", text="Move Texture Space").texture_space = True
+ layout.operator("transform.resize", text="Scale Texture Space").texture_space = True
+
+ layout.separator()
+
obj = context.object
if obj.type == 'ARMATURE' and obj.mode in ('EDIT', 'POSE') and obj.data.draw_type in ('BBONE', 'ENVELOPE'):
layout.operator("transform.transform", text="Scale Envelope/BBone").mode = 'BONE_SIZE'
@@ -584,7 +591,7 @@ class VIEW3D_MT_select_edit_metaball(bpy.types.Menu):
layout.separator()
- layout.operator("mball.select_deselect_all_metaelems")
+ layout.operator("mball.select_all").action = 'TOGGLE'
layout.operator("mball.select_inverse_metaelems")
layout.separator()
@@ -647,6 +654,7 @@ class VIEW3D_MT_select_face(bpy.types.Menu): # XXX no matching enum
# ********** Object menu **********
+
class VIEW3D_MT_object(bpy.types.Menu):
bl_context = "objectmode"
bl_label = "Object"
@@ -676,7 +684,7 @@ class VIEW3D_MT_object(bpy.types.Menu):
layout.operator("object.delete", text="Delete...")
layout.operator("object.proxy_make", text="Make Proxy...")
layout.menu("VIEW3D_MT_make_links", text="Make Links...")
- layout.operator("object.make_dupli_face", text="Make Dupliface...")
+ layout.operator("object.make_dupli_face")
layout.operator_menu_enum("object.make_local", "type", text="Make Local...")
layout.menu("VIEW3D_MT_make_single_user")
@@ -755,7 +763,7 @@ class VIEW3D_MT_object_specials(bpy.types.Menu):
props.data_path_item = "data.dof_distance"
props.input_scale = 0.02
- if obj.type in ('CURVE', 'TEXT'):
+ if obj.type in ('CURVE', 'FONT'):
layout.operator_context = 'INVOKE_REGION_WIN'
props = layout.operator("wm.context_modal_mouse", text="Extrude Size")
@@ -897,16 +905,16 @@ class VIEW3D_MT_make_single_user(bpy.types.Menu):
props = layout.operator("object.make_single_user", text="Object")
props.object = True
- props = layout.operator("object.make_single_user", text="Object & ObData")
+ props = layout.operator("object.make_single_user", text="Object & Data")
props.object = props.obdata = True
- props = layout.operator("object.make_single_user", text="Object & ObData & Materials+Tex")
+ props = layout.operator("object.make_single_user", text="Object & Data & Materials+Tex")
props.object = props.obdata = props.material = props.texture = True
props = layout.operator("object.make_single_user", text="Materials+Tex")
props.material = props.texture = True
- props = layout.operator("object.make_single_user", text="Animation")
+ props = layout.operator("object.make_single_user", text="Object Animation")
props.animation = True
@@ -916,8 +924,14 @@ class VIEW3D_MT_make_links(bpy.types.Menu):
def draw(self, context):
layout = self.layout
- 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...")
+ if(len(bpy.data.scenes) > 10):
+ layout.operator_context = 'INVOKE_DEFAULT'
+ layout.operator("object.make_links_scene", text="Objects to Scene...", icon='OUTLINER_OB_EMPTY')
+ layout.operator("object.make_links_scene", text="Markers to Scene...", icon='OUTLINER_OB_EMPTY')
+ else:
+ 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
@@ -1213,7 +1227,7 @@ class VIEW3D_MT_pose_transform(bpy.types.Menu):
def draw(self, context):
layout = self.layout
- layout.label(text="User Transform")
+ layout.operator("pose.transforms_clear", text="All")
layout.operator("pose.loc_clear", text="Location")
layout.operator("pose.rot_clear", text="Rotation")
@@ -1370,7 +1384,7 @@ class VIEW3D_MT_edit_mesh_specials(bpy.types.Menu):
layout.operator("mesh.select_vertex_path")
-class VIEW3D_MT_edit_mesh_selection_mode(bpy.types.Menu):
+class VIEW3D_MT_edit_mesh_select_mode(bpy.types.Menu):
bl_label = "Mesh Select Mode"
def draw(self, context):
@@ -1394,82 +1408,35 @@ class VIEW3D_MT_edit_mesh_selection_mode(bpy.types.Menu):
class VIEW3D_MT_edit_mesh_extrude(bpy.types.Menu):
bl_label = "Extrude"
+ _extrude_funcs = { \
+ "VERT": lambda layout: layout.operator("mesh.extrude_vertices_move", text="Vertices Only"),
+ "EDGE": lambda layout: layout.operator("mesh.extrude_edges_move", text="Edges Only"),
+ "FACE": lambda layout: layout.operator("mesh.extrude_faces_move", text="Individual Faces"),
+ "REGION": lambda layout: layout.operator("view3d.edit_mesh_extrude_move_normal", text="Region"),
+ }
+
@staticmethod
def extrude_options(context):
mesh = context.object.data
- selection_mode = context.tool_settings.mesh_select_mode
-
- totface = mesh.total_face_sel
- totedge = mesh.total_edge_sel
- totvert = mesh.total_vert_sel
+ select_mode = context.tool_settings.mesh_select_mode
- # the following is dependent on selection modes
- # we don't really want that
-# if selection_mode[0]: # vert
-# if totvert == 0:
-# return ()
-# elif totvert == 1:
-# return (3,)
-# elif totedge == 0:
-# return (3,)
-# elif totface == 0:
-# return (2, 3)
-# elif totface == 1:
-# return (0, 2, 3)
-# else:
-# return (0, 1, 2, 3)
-# elif selection_mode[1]: # edge
-# if totedge == 0:
-# return ()
-# elif totedge == 1:
-# return (2,)
-# elif totface == 0:
-# return (2,)
-# elif totface == 1:
-# return (0, 2)
-# else:
-# return (0, 1, 2)
-# elif selection_mode[2]: # face
-# if totface == 0:
-# return ()
-# elif totface == 1:
-# return (0,)
-# else:
-# return (0, 1)
-
- if totvert == 0:
- return ()
- elif totedge == 0:
- return (0, 3)
- elif totface == 0:
- return (0, 2, 3)
- else:
- return (0, 1, 2, 3)
+ menu = []
+ if mesh.total_face_sel:
+ menu += ["REGION", "FACE"]
+ if mesh.total_edge_sel and (select_mode[0] or select_mode[1]):
+ menu += ["EDGE"]
+ if mesh.total_vert_sel and select_mode[0]:
+ menu += ["VERT"]
# should never get here
- return ()
+ return menu
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
- def region_menu():
- layout.operator("view3d.edit_mesh_extrude_move_normal", text="Region")
-
- def face_menu():
- layout.operator("mesh.extrude_faces_move", text="Individual Faces")
-
- def edge_menu():
- layout.operator("mesh.extrude_edges_move", text="Edges Only")
-
- def vert_menu():
- layout.operator("mesh.extrude_vertices_move", text="Vertices Only")
-
- menu_funcs = region_menu, face_menu, edge_menu, vert_menu
-
- for i in self.extrude_options(context):
- func = menu_funcs[i]
- func()
+ for menu_id in self.extrude_options(context):
+ self._extrude_funcs[menu_id](layout)
class VIEW3D_OT_edit_mesh_extrude_individual_move(bpy.types.Operator):
@@ -1479,20 +1446,23 @@ class VIEW3D_OT_edit_mesh_extrude_individual_move(bpy.types.Operator):
def execute(self, context):
mesh = context.object.data
- selection_mode = context.tool_settings.mesh_select_mode
+ select_mode = context.tool_settings.mesh_select_mode
totface = mesh.total_face_sel
totedge = mesh.total_edge_sel
totvert = mesh.total_vert_sel
- if selection_mode[2] and totface == 1:
- return bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": "NORMAL", "constraint_axis": [False, False, True]})
- elif selection_mode[2] and totface > 1:
- return bpy.ops.mesh.extrude_faces_move('INVOKE_REGION_WIN')
- elif selection_mode[1] and totedge >= 1:
- return bpy.ops.mesh.extrude_edges_move('INVOKE_REGION_WIN')
+ if select_mode[2] and totface == 1:
+ bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": 'NORMAL', "constraint_axis": (False, False, True)})
+ elif select_mode[2] and totface > 1:
+ bpy.ops.mesh.extrude_faces_move('INVOKE_REGION_WIN')
+ elif select_mode[1] and totedge >= 1:
+ bpy.ops.mesh.extrude_edges_move('INVOKE_REGION_WIN')
else:
- return bpy.ops.mesh.extrude_vertices_move('INVOKE_REGION_WIN')
+ bpy.ops.mesh.extrude_vertices_move('INVOKE_REGION_WIN')
+
+ # ignore return from operators above because they are 'RUNNING_MODAL', and cause this one not to be freed. [#24671]
+ return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@@ -1511,11 +1481,14 @@ class VIEW3D_OT_edit_mesh_extrude_move(bpy.types.Operator):
totvert = mesh.total_vert_sel
if totface >= 1:
- return bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": "NORMAL", "constraint_axis": [False, False, True]})
+ 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]})
+ bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN', TRANSFORM_OT_translate={"constraint_orientation": 'NORMAL', "constraint_axis": (True, True, False)})
else:
- return bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN')
+ bpy.ops.mesh.extrude_region_move('INVOKE_REGION_WIN')
+
+ # ignore return from operators above because they are 'RUNNING_MODAL', and cause this one not to be freed. [#24671]
+ return {'FINISHED'}
def invoke(self, context, event):
return self.execute(context)
@@ -1708,7 +1681,7 @@ class VIEW3D_MT_edit_curve_ctrlpoints(bpy.types.Menu):
edit_object = context.edit_object
if edit_object.type == 'CURVE':
- layout.operator("transform.transform").mode = 'TILT'
+ layout.operator("transform.transform", text="Tilt").mode = 'TILT'
layout.operator("curve.tilt_clear")
layout.operator("curve.separate")
@@ -1755,7 +1728,7 @@ class VIEW3D_MT_edit_surface(bpy.types.Menu):
draw = draw_curve
-class VIEW3D_MT_edit_text(bpy.types.Menu):
+class VIEW3D_MT_edit_font(bpy.types.Menu):
bl_label = "Text"
def draw(self, context):
@@ -1903,7 +1876,7 @@ class VIEW3D_MT_edit_armature(bpy.types.Menu):
layout.separator()
- layout.operator("armature.subdivide_multi", text="Subdivide")
+ layout.operator("armature.subdivide", text="Subdivide")
layout.operator("armature.switch_direction", text="Switch Direction")
layout.separator()
@@ -1937,7 +1910,7 @@ class VIEW3D_MT_armature_specials(bpy.types.Menu):
layout.operator_context = 'INVOKE_REGION_WIN'
- layout.operator("armature.subdivide_multi", text="Subdivide")
+ layout.operator("armature.subdivide", text="Subdivide")
layout.operator("armature.switch_direction", text="Switch Direction")
layout.separator()
@@ -1998,6 +1971,8 @@ class VIEW3D_PT_view3d_properties(bpy.types.Panel):
col.prop(view, "lock_object", text="")
if view.lock_object and view.lock_object.type == 'ARMATURE':
col.prop_search(view, "lock_bone", view.lock_object.data, "bones", text="")
+ elif not view.lock_object:
+ col.prop(view, "lock_cursor", text="Lock to Cursor")
col = layout.column(align=True)
col.label(text="Clip:")
@@ -2052,7 +2027,8 @@ class VIEW3D_PT_view3d_display(bpy.types.Panel):
layout = self.layout
view = context.space_data
- gs = context.scene.game_settings
+ scene = context.scene
+ gs = scene.game_settings
ob = context.object
col = layout.column()
@@ -2081,8 +2057,10 @@ class VIEW3D_PT_view3d_display(bpy.types.Panel):
sub = col.column(align=True)
sub.active = (display_all and view.show_floor)
sub.prop(view, "grid_lines", text="Lines")
- sub.prop(view, "grid_spacing", text="Spacing")
- sub.prop(view, "grid_subdivisions", text="Subdivisions")
+ sub.prop(view, "grid_scale", text="Scale")
+ subsub = sub.column(align=True)
+ subsub.active = scene.unit_settings.system == 'NONE'
+ subsub.prop(view, "grid_subdivisions", text="Subdivisions")
col = layout.column()
col.label(text="Shading:")
@@ -2139,7 +2117,7 @@ class VIEW3D_PT_view3d_meshdisplay(bpy.types.Panel):
col.separator()
col.label(text="Numerics:")
col.prop(mesh, "show_extra_edge_length")
- col.prop(mesh, "show_extra_edge_angle")
+ col.prop(mesh, "show_extra_face_angle")
col.prop(mesh, "show_extra_face_area")
@@ -2189,7 +2167,7 @@ class VIEW3D_PT_background_image(bpy.types.Panel):
view = context.space_data
col = layout.column()
- col.operator("view3d.add_background_image", text="Add Image")
+ col.operator("view3d.background_image_add", text="Add Image")
for i, bg in enumerate(view.background_images):
layout.active = view.show_background_images
@@ -2200,7 +2178,7 @@ class VIEW3D_PT_background_image(bpy.types.Panel):
row.prop(bg.image, "name", text="", emboss=False)
else:
row.label(text="Not Set")
- row.operator("view3d.remove_background_image", text="", emboss=False, icon='X').index = i
+ row.operator("view3d.background_image_remove", text="", emboss=False, icon='X').index = i
box.prop(bg, "view_axis", text="Axis")
@@ -2210,7 +2188,7 @@ class VIEW3D_PT_background_image(bpy.types.Panel):
if (bg.image):
box.template_image(bg, "image", bg.image_user, compact=True)
- box.prop(bg, "transparency", slider=True)
+ box.prop(bg, "opacity", slider=True)
if bg.view_axis != 'CAMERA':
box.prop(bg, "size")
row = box.row(align=True)
@@ -2320,20 +2298,19 @@ class VIEW3D_PT_context_properties(bpy.types.Panel):
def draw(self, context):
import rna_prop_ui
- # reload(rna_prop_ui)
member = __class__._active_context_member(context)
if member:
# Draw with no edit button
- rna_prop_ui.draw(self.layout, context, member, False)
+ rna_prop_ui.draw(self.layout, context, member, object, False)
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/scripts/ui/space_view3d_toolbar.py b/release/scripts/ui/space_view3d_toolbar.py
index a6f3f7e34c2..163e02817a4 100644
--- a/release/scripts/ui/space_view3d_toolbar.py
+++ b/release/scripts/ui/space_view3d_toolbar.py
@@ -25,6 +25,39 @@ class View3DPanel():
bl_region_type = 'TOOLS'
+# **************** standard tool clusters ******************
+
+# History/Repeat tools
+def draw_repeat_tools(context, layout):
+ col = layout.column(align=True)
+ col.label(text="Repeat:")
+ col.operator("screen.repeat_last")
+ col.operator("screen.repeat_history", text="History...")
+
+
+# Keyframing tools
+def draw_keyframing_tools(context, layout):
+ col = layout.column(align=True)
+ col.label(text="Keyframes:")
+ row = col.row()
+ row.operator("anim.keyframe_insert_menu", text="Insert")
+ row.operator("anim.keyframe_delete_v3d", text="Remove")
+
+
+# Grease Pencil tools
+def draw_gpencil_tools(context, layout):
+ col = layout.column(align=True)
+
+ col.label(text="Grease Pencil:")
+
+ row = col.row()
+ row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
+ row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
+ row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
+
+ row = col.row()
+ row.prop(context.tool_settings, "use_grease_pencil_sessions")
+
# ********** default tools for objectmode ****************
@@ -58,22 +91,16 @@ class VIEW3D_PT_tools_objectmode(View3DPanel, bpy.types.Panel):
col.operator("object.shade_smooth", text="Smooth")
col.operator("object.shade_flat", text="Flat")
- col = layout.column(align=True)
- col.label(text="Keyframes:")
- col.operator("anim.keyframe_insert_menu", text="Insert")
- col.operator("anim.keyframe_delete_v3d", text="Remove")
+ draw_keyframing_tools(context, layout)
col = layout.column(align=True)
- col.label(text="Repeat:")
- col.operator("screen.repeat_last")
- col.operator("screen.repeat_history", text="History...")
+ col.label(text="Motion Paths:")
+ col.operator("object.paths_calculate", text="Calculate Paths")
+ col.operator("object.paths_clear", text="Clear Paths")
- col = layout.column(align=True)
- col.label(text="Grease Pencil:")
- row = col.row()
- row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
- row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
- row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
+ draw_repeat_tools(context, layout)
+
+ draw_gpencil_tools(context, layout)
# ********** default tools for editmode_mesh ****************
@@ -96,6 +123,7 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, bpy.types.Panel):
col.label(text="Deform:")
col.operator("transform.edge_slide")
col.operator("mesh.rip_move")
+ col.operator("mesh.noise")
col.operator("mesh.vertices_smooth")
col = layout.column(align=True)
@@ -130,17 +158,9 @@ class VIEW3D_PT_tools_meshedit(View3DPanel, bpy.types.Panel):
col.operator("mesh.faces_shade_smooth", text="Smooth")
col.operator("mesh.faces_shade_flat", text="Flat")
- col = layout.column(align=True)
- col.label(text="Repeat:")
- col.operator("screen.repeat_last")
- col.operator("screen.repeat_history", text="History...")
+ draw_repeat_tools(context, layout)
- col = layout.column(align=True)
- col.label(text="Grease Pencil:")
- row = col.row()
- row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
- row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
- row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
+ draw_gpencil_tools(context, layout)
class VIEW3D_PT_tools_meshedit_options(View3DPanel, bpy.types.Panel):
@@ -193,7 +213,7 @@ class VIEW3D_PT_tools_curveedit(View3DPanel, bpy.types.Panel):
row.operator("curve.handle_type_set", text="Auto").type = 'AUTOMATIC'
row.operator("curve.handle_type_set", text="Vector").type = 'VECTOR'
row = col.row()
- row.operator("curve.handle_type_set", text="Align").type = 'ALIGN'
+ row.operator("curve.handle_type_set", text="Align").type = 'ALIGNED'
row.operator("curve.handle_type_set", text="Free").type = 'FREE_ALIGN'
col = layout.column(align=True)
@@ -201,17 +221,9 @@ class VIEW3D_PT_tools_curveedit(View3DPanel, bpy.types.Panel):
col.operator("curve.extrude")
col.operator("curve.subdivide")
- col = layout.column(align=True)
- col.label(text="Repeat:")
- col.operator("screen.repeat_last")
- col.operator("screen.repeat_history", text="History...")
+ draw_repeat_tools(context, layout)
- col = layout.column(align=True)
- col.label(text="Grease Pencil:")
- row = col.row()
- row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
- row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
- row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
+ draw_gpencil_tools(context, layout)
# ********** default tools for editmode_surface ****************
@@ -241,17 +253,9 @@ class VIEW3D_PT_tools_surfaceedit(View3DPanel, bpy.types.Panel):
col.operator("curve.extrude")
col.operator("curve.subdivide")
- col = layout.column(align=True)
- col.label(text="Repeat:")
- col.operator("screen.repeat_last")
- col.operator("screen.repeat_history", text="History...")
+ draw_repeat_tools(context, layout)
- col = layout.column(align=True)
- col.label(text="Grease Pencil:")
- row = col.row()
- row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
- row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
- row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
+ draw_gpencil_tools(context, layout)
# ********** default tools for editmode_text ****************
@@ -280,10 +284,7 @@ class VIEW3D_PT_tools_textedit(View3DPanel, bpy.types.Panel):
col.operator("font.style_toggle", text="Italic").style = 'ITALIC'
col.operator("font.style_toggle", text="Underline").style = 'UNDERLINE'
- col = layout.column(align=True)
- col.label(text="Repeat:")
- col.operator("screen.repeat_last")
- col.operator("screen.repeat_history", text="History...")
+ draw_repeat_tools(context, layout)
# ********** default tools for editmode_armature ****************
@@ -311,19 +312,11 @@ class VIEW3D_PT_tools_armatureedit(View3DPanel, bpy.types.Panel):
col = layout.column(align=True)
col.label(text="Modeling:")
col.operator("armature.extrude_move")
- col.operator("armature.subdivide_multi", text="Subdivide")
+ col.operator("armature.subdivide", text="Subdivide")
- col = layout.column(align=True)
- col.label(text="Repeat:")
- col.operator("screen.repeat_last")
- col.operator("screen.repeat_history", text="History...")
+ draw_repeat_tools(context, layout)
- col = layout.column(align=True)
- col.label(text="Grease Pencil:")
- row = col.row()
- row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
- row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
- row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
+ draw_gpencil_tools(context, layout)
class VIEW3D_PT_tools_armatureedit_options(View3DPanel, bpy.types.Panel):
@@ -354,17 +347,9 @@ class VIEW3D_PT_tools_mballedit(View3DPanel, bpy.types.Panel):
col.operator("transform.rotate")
col.operator("transform.resize", text="Scale")
- col = layout.column(align=True)
- col.label(text="Repeat:")
- col.operator("screen.repeat_last")
- col.operator("screen.repeat_history", text="History...")
+ draw_repeat_tools(context, layout)
- col = layout.column(align=True)
- col.label(text="Grease Pencil:")
- row = col.row()
- row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
- row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
- row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
+ draw_gpencil_tools(context, layout)
# ********** default tools for editmode_lattice ****************
@@ -385,17 +370,9 @@ class VIEW3D_PT_tools_latticeedit(View3DPanel, bpy.types.Panel):
col = layout.column(align=True)
col.operator("lattice.make_regular")
- col = layout.column(align=True)
- col.label(text="Repeat:")
- col.operator("screen.repeat_last")
- col.operator("screen.repeat_history", text="History...")
+ draw_repeat_tools(context, layout)
- col = layout.column(align=True)
- col.label(text="Grease Pencil:")
- row = col.row()
- row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
- row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
- row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
+ draw_gpencil_tools(context, layout)
# ********** default tools for posemode ****************
@@ -430,23 +407,16 @@ class VIEW3D_PT_tools_posemode(View3DPanel, bpy.types.Panel):
col = layout.column(align=True)
col.operator("poselib.pose_add", text="Add To Library")
- col = layout.column(align=True)
- col.label(text="Keyframes:")
-
- col.operator("anim.keyframe_insert_menu", text="Insert")
- col.operator("anim.keyframe_delete_v3d", text="Remove")
+ draw_keyframing_tools(context, layout)
col = layout.column(align=True)
- col.label(text="Repeat:")
- col.operator("screen.repeat_last")
- col.operator("screen.repeat_history", text="History...")
+ col.label(text="Motion Paths:")
+ col.operator("pose.paths_calculate", text="Calculate Paths")
+ col.operator("pose.paths_clear", text="Clear Paths")
- col = layout.column(align=True)
- col.label(text="Grease Pencil:")
- row = col.row()
- row.operator("gpencil.draw", text="Draw").mode = 'DRAW'
- row.operator("gpencil.draw", text="Line").mode = 'DRAW_STRAIGHT'
- row.operator("gpencil.draw", text="Erase").mode = 'ERASER'
+ draw_repeat_tools(context, layout)
+
+ draw_gpencil_tools(context, layout)
class VIEW3D_PT_tools_posemode_options(View3DPanel, bpy.types.Panel):
@@ -459,7 +429,6 @@ class VIEW3D_PT_tools_posemode_options(View3DPanel, bpy.types.Panel):
arm = context.active_object.data
col = layout.column(align=True)
- col.prop(arm, "use_mirror_x")
col.prop(arm, "use_auto_ik")
# ********** default tools for paint modes ****************
@@ -1077,7 +1046,10 @@ class VIEW3D_PT_tools_weightpaint(View3DPanel, bpy.types.Panel):
def draw(self, context):
layout = self.layout
+ ob = context.active_object
+
col = layout.column()
+ col.active = ob.vertex_groups.active != None
col.operator("object.vertex_group_normalize_all", text="Normalize All")
col.operator("object.vertex_group_normalize", text="Normalize")
col.operator("object.vertex_group_invert", text="Invert")
@@ -1158,7 +1130,7 @@ class VIEW3D_PT_tools_projectpaint(View3DPanel, bpy.types.Panel):
@classmethod
def poll(cls, context):
brush = context.tool_settings.image_paint.brush
- return (brush and brush.imagepaint_tool != 'SMEAR')
+ return (brush and brush.imagepaint_tool != 'SOFTEN')
def draw_header(self, context):
ipaint = context.tool_settings.image_paint
@@ -1294,7 +1266,7 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, bpy.types.Panel):
if not pe.is_editable:
layout.label(text="Point cache must be baked")
- layout.label(text="to enable editing!")
+ layout.label(text="in memory to enable editing!")
col = layout.column(align=True)
if pe.is_hair:
@@ -1330,11 +1302,11 @@ class VIEW3D_PT_tools_particlemode(View3DPanel, bpy.types.Panel):
def register():
- pass
+ bpy.utils.register_module(__name__)
def unregister():
- pass
+ bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
diff --git a/release/test/pep8.py b/release/test/pep8.py
deleted file mode 100644
index 7909036a5f1..00000000000
--- a/release/test/pep8.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# ##### 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 os
-
-# depends on pep8, pyflakes, pylint
-# for ubuntu
-#
-# sudo apt-get install pylint pyflakes
-#
-# sudo apt-get install python-setuptools python-pip
-# sudo pip install pep8
-#
-# in debian install pylint pyflakes pep8 with apt-get/aptitude/etc
-#
-# on *nix run
-# python release/test/pep8.py > pep8_error.txt 2>&1
-
-# how many lines to read into the file, pep8 comment
-# should be directly after the licence header, ~20 in most cases
-PEP8_SEEK_COMMENT = 40
-SKIP_PREFIX = "./tools", "./config", "./scons", "./extern"
-
-
-def file_list_py(path):
- for dirpath, dirnames, filenames in os.walk(path):
- for filename in filenames:
- if filename.endswith(".py"):
- yield os.path.join(dirpath, filename)
-
-
-def is_pep8(path):
- f = open(path, 'r')
- for i in range(PEP8_SEEK_COMMENT):
- line = f.readline()
- if line.startswith("# <pep8"):
- if line.startswith("# <pep8 compliant>"):
- return 1
- elif line.startswith("# <pep8-80 compliant>"):
- return 2
- f.close()
- return 0
-
-
-def main():
- files = []
- files_skip = []
- for f in file_list_py("."):
- pep8_type = is_pep8(f)
-
- if pep8_type:
- # so we can batch them for each tool.
- files.append((os.path.abspath(f), pep8_type))
- else:
- if not [None for prefix in SKIP_PREFIX if f.startswith(prefix)]:
- files_skip.append(f)
-
- print("\nSkipping...")
- for f in files_skip:
- print(" %s" % f)
-
- # pyflakes
- print("\n\n\n# running pep8...")
- for f, pep8_type in files:
- if pep8_type == 1:
- # E501:80 line length
- os.system("pep8 --repeat --ignore=E501 '%s'" % (f))
- else:
- os.system("pep8 --repeat '%s'" % (f))
-
- print("\n\n\n# running pyflakes...")
- for f, pep8_type in files:
- os.system("pyflakes '%s'" % f)
-
- print("\n\n\n# running pylint...")
- for f, pep8_type in files:
- # let pep8 complain about line length
- os.system("pylint --reports=n --max-line-length=1000 '%s'" % f)
-
-if __name__ == "__main__":
- main()
diff --git a/release/test/rna_array.py b/release/test/rna_array.py
deleted file mode 100644
index 06b4735cc0d..00000000000
--- a/release/test/rna_array.py
+++ /dev/null
@@ -1,297 +0,0 @@
-# ##### 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 unittest
-import random
-
-test= bpy.data.test
-
-# farr - 1-dimensional array of float
-# fdarr - dynamic 1-dimensional array of float
-# fmarr - 3-dimensional ([3][4][5]) array of float
-# fdmarr - dynamic 3-dimensional (ditto size) array of float
-
-# same as above for other types except that the first letter is "i" for int and "b" for bool
-
-class TestArray(unittest.TestCase):
- # test that assignment works by: assign -> test value
- # - rvalue = list of float
- # - rvalue = list of numbers
- # test.object
- # bpy.data.test.farr[3], iarr[3], barr[...], fmarr, imarr, bmarr
-
- def setUp(self):
- test.farr= (1.0, 2.0, 3.0)
- test.iarr= (7, 8, 9)
- test.barr= (False, True, False)
-
- # test access
- # test slice access, negative indices
- def test_access(self):
- rvals= ([1.0, 2.0, 3.0], [7, 8, 9], [False, True, False])
- for arr, rval in zip((test.farr, test.iarr, test.barr), rvals):
- self.assertEqual(prop_to_list(arr), rval)
- self.assertEqual(arr[0:3], rval)
- self.assertEqual(arr[1:2], rval[1:2])
- self.assertEqual(arr[-1], arr[2])
- self.assertEqual(arr[-2], arr[1])
- self.assertEqual(arr[-3], arr[0])
-
- # fail when index out of bounds
- def test_access_fail(self):
- for arr in (test.farr, test.iarr, test.barr):
- self.assertRaises(IndexError, lambda : arr[4])
-
- # test assignment of a whole array
- def test_assign_array(self):
- # should accept int as float
- test.farr= (1, 2, 3)
-
- # fail when: unexpected no. of items, invalid item type
- def test_assign_array_fail(self):
- def assign_empty_list(arr):
- setattr(test, arr, ())
-
- for arr in ("farr", "iarr", "barr"):
- self.assertRaises(ValueError, assign_empty_list, arr)
-
- def assign_invalid_float():
- test.farr= (1.0, 2.0, "3.0")
-
- def assign_invalid_int():
- test.iarr= ("1", 2, 3)
-
- def assign_invalid_bool():
- test.barr= (True, 0.123, False)
-
- for func in [assign_invalid_float, assign_invalid_int, assign_invalid_bool]:
- self.assertRaises(TypeError, func)
-
- # shouldn't accept float as int
- def assign_float_as_int():
- test.iarr= (1, 2, 3.0)
- self.assertRaises(TypeError, assign_float_as_int)
-
- # non-dynamic arrays cannot change size
- def assign_different_size(arr, val):
- setattr(test, arr, val)
- for arr, val in zip(("iarr", "farr", "barr"), ((1, 2), (1.0, 2.0), (True, False))):
- self.assertRaises(ValueError, assign_different_size, arr, val)
-
- # test assignment of specific items
- def test_assign_item(self):
- for arr, rand_func in zip((test.farr, test.iarr, test.barr), (rand_float, rand_int, rand_bool)):
- for i in range(len(arr)):
- val= rand_func()
- arr[i]= val
-
- self.assertEqual(arr[i], val)
-
- # float prop should accept also int
- for i in range(len(test.farr)):
- val= rand_int()
- test.farr[i]= val
- self.assertEqual(test.farr[i], float(val))
-
- #
-
- def test_assign_item_fail(self):
- def assign_bad_index(arr):
- arr[4] = 1.0
-
- def assign_bad_type(arr):
- arr[1]= "123"
-
- for arr in [test.farr, test.iarr, test.barr]:
- self.assertRaises(IndexError, assign_bad_index, arr)
-
- # not testing bool because bool allows not only (True|False)
- for arr in [test.farr, test.iarr]:
- self.assertRaises(TypeError, assign_bad_type, arr)
-
- def test_dynamic_assign_array(self):
- # test various lengths here
- for arr, rand_func in zip(("fdarr", "idarr", "bdarr"), (rand_float, rand_int, rand_bool)):
- for length in range(1, 64):
- rval= make_random_array(length, rand_func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- def test_dynamic_assign_array_fail(self):
- # could also test too big length here
-
- def assign_empty_list(arr):
- setattr(test, arr, ())
-
- for arr in ("fdarr", "idarr", "bdarr"):
- self.assertRaises(ValueError, assign_empty_list, arr)
-
-
-class TestMArray(unittest.TestCase):
- def setUp(self):
- # reset dynamic array sizes
- for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
- setattr(test, arr, make_random_3d_array((3, 4, 5), func))
-
- # test assignment
- def test_assign_array(self):
- for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
- # assignment of [3][4][5]
- rval= make_random_3d_array((3, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- # test assignment of [2][4][5], [1][4][5] should work on dynamic arrays
-
- def test_assign_array_fail(self):
- def assign_empty_array():
- test.fmarr= ()
- self.assertRaises(ValueError, assign_empty_array)
-
- def assign_invalid_size(arr, rval):
- setattr(test, arr, rval)
-
- # assignment of 3,4,4 or 3,3,5 should raise ex
- for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
- rval= make_random_3d_array((3, 4, 4), func)
- self.assertRaises(ValueError, assign_invalid_size, arr, rval)
-
- rval= make_random_3d_array((3, 3, 5), func)
- self.assertRaises(ValueError, assign_invalid_size, arr, rval)
-
- rval= make_random_3d_array((3, 3, 3), func)
- self.assertRaises(ValueError, assign_invalid_size, arr, rval)
-
- def test_assign_item(self):
- # arr[i] = x
- for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
- rval= make_random_2d_array((4, 5), func)
-
- for i in range(3):
- getattr(test, arr)[i]= rval
- self.assertEqual(prop_to_list(getattr(test, arr)[i]), rval)
-
- # arr[i][j] = x
- for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
-
- arr= getattr(test, arr)
- rval= make_random_array(5, func)
-
- for i in range(3):
- for j in range(4):
- arr[i][j]= rval
- self.assertEqual(prop_to_list(arr[i][j]), rval)
-
-
- def test_assign_item_fail(self):
- def assign_wrong_size(arr, i, rval):
- getattr(test, arr)[i]= rval
-
- # assign wrong size at level 2
- for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
- rval1= make_random_2d_array((3, 5), func)
- rval2= make_random_2d_array((4, 3), func)
-
- for i in range(3):
- self.assertRaises(ValueError, assign_wrong_size, arr, i, rval1)
- self.assertRaises(ValueError, assign_wrong_size, arr, i, rval2)
-
- def test_dynamic_assign_array(self):
- for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
- # assignment of [3][4][5]
- rval= make_random_3d_array((3, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- # [2][4][5]
- rval= make_random_3d_array((2, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- # [1][4][5]
- rval= make_random_3d_array((1, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
-
- # test access
- def test_access(self):
- pass
-
- # test slice access, negative indices
- def test_access_fail(self):
- pass
-
-random.seed()
-
-def rand_int():
- return random.randint(-1000, 1000)
-
-def rand_float():
- return float(rand_int())
-
-def rand_bool():
- return bool(random.randint(0, 1))
-
-def make_random_array(len, rand_func):
- arr= []
- for i in range(len):
- arr.append(rand_func())
-
- return arr
-
-def make_random_2d_array(dimsize, rand_func):
- marr= []
- for i in range(dimsize[0]):
- marr.append([])
-
- for j in range(dimsize[1]):
- marr[-1].append(rand_func())
-
- return marr
-
-def make_random_3d_array(dimsize, rand_func):
- marr= []
- for i in range(dimsize[0]):
- marr.append([])
-
- for j in range(dimsize[1]):
- marr[-1].append([])
-
- for k in range(dimsize[2]):
- marr[-1][-1].append(rand_func())
-
- return marr
-
-def prop_to_list(prop):
- ret= []
-
- for x in prop:
- if type(x) not in (bool, int, float):
- ret.append(prop_to_list(x))
- else:
- ret.append(x)
-
- return ret
-
-def suite():
- return unittest.TestSuite([unittest.TestLoader().loadTestsFromTestCase(TestArray), unittest.TestLoader().loadTestsFromTestCase(TestMArray)])
-
-if __name__ == "__main__":
- unittest.TextTestRunner(verbosity=2).run(suite())
-
diff --git a/release/test/rna_info_dump.py b/release/test/rna_info_dump.py
deleted file mode 100644
index 62c1248d733..00000000000
--- a/release/test/rna_info_dump.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# ##### 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>
-
-# Used for generating API diff's between releases
-# ./blender.bin --background --python release/test/rna_info_dump.py
-
-import bpy
-
-
-def api_dump(use_properties=True, use_functions=True):
-
- def prop_type(prop):
- if prop.type == "pointer":
- return prop.fixed_type.identifier
- else:
- return prop.type
-
- def func_to_str(struct_id_str, func_id, func):
-
- args = []
- for prop in func.args:
- data_str = "%s %s" % (prop_type(prop), prop.identifier)
- if prop.array_length:
- data_str += "[%d]" % prop.array_length
- if not prop.is_required:
- data_str += "=%s" % prop.default_str
- args.append(data_str)
-
- data_str = "%s.%s(%s)" % (struct_id_str, func_id, ", ".join(args))
- if func.return_values:
- return_args = ", ".join(prop_type(arg) for arg in func.return_values)
- if len(func.return_values) > 1:
- data_str += " --> (%s)" % return_args
- else:
- data_str += " --> %s" % return_args
- return data_str
-
- def prop_to_str(struct_id_str, prop_id, prop):
-
- prop_str = " <-- %s" % prop_type(prop)
- if prop.array_length:
- prop_str += "[%d]" % prop.array_length
-
- data_str = "%s.%s %s" % (struct_id_str, prop_id, prop_str)
- return data_str
-
- def struct_full_id(v):
- struct_id_str = v.identifier # "".join(sid for sid in struct_id if struct_id)
-
- for base in v.get_bases():
- struct_id_str = base.identifier + "|" + struct_id_str
-
- return struct_id_str
-
- def dump_funcs():
- data = []
- for struct_id, v in sorted(struct.items()):
- struct_id_str = struct_full_id(v)
-
- funcs = [(func.identifier, func) for func in v.functions]
-
- for func_id, func in funcs:
- data.append(func_to_str(struct_id_str, func_id, func))
-
- for prop in v.properties:
- if prop.collection_type:
- funcs = [(prop.identifier + "." + func.identifier, func) for func in prop.collection_type.functions]
- for func_id, func in funcs:
- data.append(func_to_str(struct_id_str, func_id, func))
- data.sort()
- data.append("# * functions *")
- return data
-
- def dump_props():
- data = []
- for struct_id, v in sorted(struct.items()):
- struct_id_str = struct_full_id(v)
-
- props = [(prop.identifier, prop) for prop in v.properties]
-
- for prop_id, prop in props:
- data.append(prop_to_str(struct_id_str, prop_id, prop))
-
- for prop in v.properties:
- if prop.collection_type:
- props = [(prop.identifier + "." + prop_sub.identifier, prop_sub) for prop_sub in prop.collection_type.properties]
- for prop_sub_id, prop_sub in props:
- data.append(prop_to_str(struct_id_str, prop_sub_id, prop_sub))
- data.sort()
- data.insert(0, "# * properties *")
- return data
-
- import rna_info
- struct = rna_info.BuildRNAInfo()[0]
- data = []
-
- if use_functions:
- data.extend(dump_funcs())
-
- if use_properties:
- data.extend(dump_props())
-
- if bpy.app.background:
- import sys
- sys.stderr.write("\n".join(data))
- sys.stderr.write("\n\nEOF\n")
- else:
- text = bpy.data.texts.new(name="api.py")
- text.from_string(data)
-
- print("END")
-
-if __name__ == "__main__":
- api_dump()
diff --git a/release/text/readme.html b/release/text/readme.html
index 1b14c63e14a..aa73a8cb512 100644
--- a/release/text/readme.html
+++ b/release/text/readme.html
@@ -12,15 +12,15 @@
</style>
</head>
<body>
-<p class="title"><b>Blender 2.5 Beta</b></p>
+<p class="title"><b>Blender 2.56 Beta</b></p>
<p><br></p>
<p class="header"><b>About</b></p>
<p class="body">Welcome to Blender, the free, open source 3D application for modeling, animation, rendering, compositing, video editing and game creation. Blender is available for Linux, Mac OS X, Windows, Solaris and Irix and has a large world-wide community.</p>
<p class="body">Blender can be used freely for any purpose, including commercial use and distribution. It's free and open-source software, released under the GNU GPL licence. The entire source code is available on our website.</p>
<p class="body">For more information, visit <a href="http://www.blender.org">blender.org</a>.</p>
<p><br></p>
-<p class="header"><b>2.5 Beta</b></p>
-<p class="body">The Blender Foundation and online developer community is proud to present Blender 2.5 Beta. This release is the third official testing release of the Blender 2.5 series, and represents the culmination of many years of redesign and development work. <a href="http://www.blender.org/development/release-logs/blender-250/">More information about this release</a>.</p>
+<p class="header"><b>2.56 Beta</b></p>
+<p class="body">The Blender Foundation and online developer community is proud to present Blender 2.56 Beta. This release is the fourth official beta release of the Blender 2.5 series, and represents the culmination of many years of redesign and development work. <a href="http://www.blender.org/development/release-logs/blender-256-beta/">More information about this release</a>.</p>
<p class="body">What to Expect:</p>
<p class="body"> • Big improvements - This is our most exciting version to date, already a significant improvement in many ways over 2.49</p>
<p class="body"> • Missing/Incomplete Features - Although most of it is there, not all functionality from pre-2.5 versions has been restored yet. Some functionality may be re-implemented a different way.</p>
@@ -28,7 +28,7 @@
<p class="body"> • Changes - If you're used to the old Blenders, Blender 2.5 may seem quite different at first, but it won't be long before it grows on you even more than before.</p>
<p><br></p>
<p class="header"><b>Bugs</b></p>
-<p class="body">Blender 2.5 Beta is unfinished software. If you encounter a bug, please help us by posting it in the bug tracker or using Help → Report a Bug from inside Blender 2.5. If it wasn’t reported yet, please log in (or register) and fill in detailed information about the error. Please post detailed instructions on how to reproduce it or post a .blend file showcasing the bug.</p>
+<p class="body">Blender 2.56 Beta is unfinished software. If you encounter a bug, please help us by posting it in the bug tracker or using Help → Report a Bug from inside Blender 2.56. If it wasn’t reported yet, please log in (or register) and fill in detailed information about the error. Please post detailed instructions on how to reproduce it or post a .blend file showcasing the bug.</p>
<p><br></p>
<p class="header"><b>Package Contents</b></p>
<p class="body">The downloaded Blender package includes:</p>
@@ -53,7 +53,7 @@ Install scripts by putting them in the .blender/scripts inside your home folder.
<p class="header"><b>Links</b></p>
<p class="body">Users:</p>
<p class="body"> General information <a href="http://www.blender.org">www.blender.org</a> <br>
- Full release log <a href="http://www.blender.org/development/release-logs/blender-250/">www.blender.org/development/release-logs/blender-250/</a><br>
+ Full release log <a href="http://www.blender.org/development/release-logs/blender-254-beta/">www.blender.org/development/release-logs/blender-256-beta/</a><br>
Tutorials <a href="http://www.blender.org/education-help/">www.blender.org/education-help/</a> <br>
Manual <a href="http://wiki.blender.org/index.php/Doc:Manual">wiki.blender.org/index.php/Doc:Manual</a><br>
User Forum <a href="http://www.blenderartists.org">www.blenderartists.org</a><br>
diff --git a/release/windows/extra/Help.url b/release/windows/extra/Help.url
deleted file mode 100644
index 417c237ceda..00000000000
--- a/release/windows/extra/Help.url
+++ /dev/null
@@ -1,4 +0,0 @@
-[DEFAULT]
-BASEURL=http://www.blender.org/education-help/
-[InternetShortcut]
-URL=http://www.blender.org/education-help/
diff --git a/release/windows/installer/00.sconsblender.nsi b/release/windows/installer/00.sconsblender.nsi
index d16e0f1ae61..e5ebf8b2f64 100644
--- a/release/windows/installer/00.sconsblender.nsi
+++ b/release/windows/installer/00.sconsblender.nsi
@@ -11,6 +11,9 @@
!include "FileFunc.nsh"
!include "WordFunc.nsh"
!include "nsDialogs.nsh"
+!include "x64.nsh"
+
+RequestExecutionLevel user
SetCompressor /SOLID lzma
@@ -67,7 +70,10 @@ UninstallIcon "[RELDIR]\00.installer.ico"
Caption "Blender [VERSION] Installer"
OutFile "[DISTDIR]\..\blender-[VERSION]-windows[BITNESS].exe"
-InstallDir "$PROGRAMFILES[BITNESS]\Blender Foundation\Blender"
+;InstallDir "$PROGRAMFILES[BITNESS]\Blender Foundation\Blender"
+; Install to user profile dir. While it is non-standard, it allows
+; users to install without having to have the installer run in elevated mode.
+InstallDir "$PROFILE\Blender Foundation\Blender"
BrandingText "Blender Foundation | http://www.blender.org"
ComponentText "This will install Blender [VERSION] on your computer."
@@ -148,6 +154,9 @@ Section "Blender-[VERSION] (required)" SecCopyUI
[DODATAFILES]
SetOutPath $INSTDIR
+ ${If} ${RunningX64}
+ SetRegView 64
+ ${EndIf}
; Write the installation path into the registry
WriteRegStr HKLM "SOFTWARE\BlenderFoundation" "Install_Dir" "$INSTDIR"
WriteRegStr HKLM "SOFTWARE\BlenderFoundation" "ConfigData_Dir" "$BLENDERHOME"
@@ -157,10 +166,6 @@ Section "Blender-[VERSION] (required)" SecCopyUI
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteUninstaller "uninstall.exe"
- ; Let's now run silent vcredist installer
- SetOutPath $TEMP
- [VCREDIST]
-
SectionEnd
Section "Add Start Menu shortcuts" Section2
@@ -179,6 +184,9 @@ SectionEnd
Section "Open .blend files with Blender-[VERSION]" Section4
+ ${If} ${RunningX64}
+ SetRegView 64
+ ${EndIf}
WriteRegStr HKCR ".blend" "" "blendfile"
WriteRegStr HKCR "blendfile" "" "Blender .blend File"
WriteRegStr HKCR "blendfile\shell" "" "open"
@@ -188,32 +196,50 @@ Section "Open .blend files with Blender-[VERSION]" Section4
SectionEnd
-UninstallText "This will uninstall Blender [VERSION], and all datafiles from the installation dir. Hit next to continue."
+UninstallText "This will uninstall Blender [VERSION], and all installed files. Before continuing make sure you have created backup of all the files you may want to keep: startup.blend, bookmarks.txt, recent-files.txt. Hit next to continue."
Section "Uninstall"
; remove registry keys
+ ${If} ${RunningX64}
+ SetRegView 64
+ ${EndIf}
ReadRegStr $BLENDERHOME HKLM "SOFTWARE\BlenderFoundation" "ConfigData_Dir"
ReadRegStr $SHORTVERSION HKLM "SOFTWARE\BlenderFoundation" "ShortVersion"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Blender"
DeleteRegKey HKLM "SOFTWARE\BlenderFoundation"
SetShellVarContext all
-
- StrCpy $0 "$SMPROGRAMS\Blender Foundation\"
- MessageBox MB_OK $0
+
; remove files
[DELROOTDIRCONTS]
+ ; remove bundled python
+ RmDir /r $INSTDIR\$SHORTVERSION\python
+
Delete "$INSTDIR\uninstall.exe"
- MessageBox MB_YESNO "Erase $BLENDERHOME? This includes all installed scripts and configuration files and any file you may have created there." IDNO Next
- RMDir /r "$BLENDERHOME"
-Next:
- ; remove shortcuts, if any.
+ MessageBox MB_YESNO "Recursively erase contents of $BLENDERHOME\$SHORTVERSION\scripts? NOTE: This includes all installed scripts and *any* file and directory you have manually created, installed later or copied. This also including .blend files." IDNO NextNoScriptRemove
+ RMDir /r "$BLENDERHOME\$SHORTVERSION\scripts"
+NextNoScriptRemove:
+ MessageBox MB_YESNO "Recursively erase contents from $BLENDERHOME\$SHORTVERSION\config? NOTE: This includes your startup.blend, bookmarks and any other file and directory you may have created in that directory" IDNO NextNoConfigRemove
+ RMDir /r "$BLENDERHOME\$SHORTVERSION\config"
+NextNoConfigRemove:
+ MessageBox MB_YESNO "Recursively erase contents from $BLENDERHOME\$SHORTVERSION\plugins? NOTE: This includes files and subdirectories in this directory" IDNO NextNoPluginRemove
+ RMDir /r "$BLENDERHOME\$SHORTVERSION\plugins"
+NextNoPluginRemove:
+ ; try to remove dirs, but leave them if they contain anything
+ RMDir "$BLENDERHOME\$SHORTVERSION\plugins"
+ RMDir "$BLENDERHOME\$SHORTVERSION\config"
+ RMDir "$BLENDERHOME\$SHORTVERSION\scripts"
+ RMDir "$BLENDERHOME\$SHORTVERSION"
+ RMDir "$BLENDERHOME"
+ ; remove shortcuts
+ Delete "$SMPROGRAMS\Blender Foundation\Blender\*.*"
Delete "$DESKTOP\Blender.lnk"
; remove all link related directories and files
- RMDir /r "$SMPROGRAMS\Blender Foundation\"
- ; remove entire installation directory, including any file created by the user
- RMDir /r "$INSTDIR"
+ RMDir "$SMPROGRAMS\Blender Foundation\Blender"
+ RMDir "$SMPROGRAMS\Blender Foundation"
+ ; Clear out installation dir
+ RMDir "$INSTDIR"
SectionEnd
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
diff --git a/release/windows/specific.sh b/release/windows/specific.sh
deleted file mode 100755
index 3ded917e591..00000000000
--- a/release/windows/specific.sh
+++ /dev/null
@@ -1,95 +0,0 @@
-#!/bin/sh
-#
-# $Id$
-#
-# ***** 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.
-#
-# The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
-# All rights reserved.
-#
-# The Original Code is: all of this file.
-#
-# Contributor(s): none yet.
-#
-# ***** END GPL LICENSE BLOCK *****
-#
-# OS specific stuff for the package, only to be executed by ../Makefile
-
-SHORTVERS=`echo $VERSION | sed 's/\.//'`
-
-# Create ^M in readme.txt
-#awk '{printf("%s\r\n", $0);}' $DISTDIR/README > $DISTDIR/Readme.txt
-#rm -f $DISTDIR/README
-cp -f ../text/Blender.html $DISTDIR/Blender.html
-
-# Create ^M in copyright.txt
-awk '{printf("%s\r\n", $0);}' $DISTDIR/copyright.txt > $DISTDIR/aCopyright.txt
-rm -f $DISTDIR/copyright.txt
-mv -f $DISTDIR/aCopyright.txt $DISTDIR/Copyright.txt
-# PS. the whole aCopyright kludge is because of windows being braindead
-
-# Create ^M in copyright.txt
-awk '{printf("%s\r\n", $0);}' $DISTDIR/GPL-license.txt > $DISTDIR/temp.txt
-mv -f $DISTDIR/temp.txt $DISTDIR/GPL-license.txt
-
-# Add Release info text
-cp -f ../text/Release_$SHORTVERS.txt $DISTDIR/Release_$SHORTVERS.txt
-awk '{printf("%s\r\n", $0);}' $DISTDIR/Release_$SHORTVERS.txt > $DISTDIR/temp.txt
-mv -f $DISTDIR/temp.txt $DISTDIR/Release_$SHORTVERS.txt
-
-# Add Python DLL to package
-# Stupid windows needs the . removed :
-PVERS=`echo $NAN_PYTHON_VERSION | sed 's/\.//'`
-cp -f $NAN_PYTHON/lib/python$PVERS.dll $DISTDIR/python$PVERS.dll
-chmod +x $DISTDIR/python$PVERS.dll
-
-#Add pthreads dll to package
-cp -f $NAN_PTHREADS/lib/pthreadGC2.dll $DISTDIR/pthreadGC2.dll
-
-# Add gettext DLL to package
-cp -f $NAN_GETTEXT/lib/gnu_gettext.dll $DISTDIR/gnu_gettext.dll
-
-# Add SDL DLL to package
-cp -f $NAN_SDL/lib/sdl.dll $DISTDIR/sdl.dll
-
-# Add the Help.url to the ditribution
-cp -f extra/Help.url $DISTDIR/
-
-# Add Python23.zip & zlib.pyd
-cp -f extra/Python23.zip $DISTDIR/
-cp -f extra/zlib.pyd $DISTDIR/
-
-# Add the language files to package
-cp -f -R $NAN_OBJDIR/windows/bin/.blender $DISTDIR/
-# Remove the pesky CVS dirs
-find $DISTDIR/.blender -name CVS -prune -exec rm -rf {} \;
-
-# Add .bfont.ttf and .Blanguages
-cp -f $NANBLENDERHOME/bin/.blender/.bfont.ttf $DISTDIR/.blender/.bfont.ttf
-cp -f $NANBLENDERHOME/bin/.blender/.Blanguages $DISTDIR/.blender/.Blanguages
-
-# make the installer package with NSIS
-NSIS="$PROGRAMFILES/NSIS/makensis.exe"
-if (`test -x "$NSIS"`) then
- cd installer
- TEMPFILE=00.blender_tmp.nsi
- DISTDIR=`cygpath -m $DISTDIR`
- # make a installer config for this release
- cat 00.blender.nsi | sed "s|VERSION|$VERSION|g" | sed "s|DISTDIR|$DISTDIR|g" | sed "s|SHORTVERS|$SHORTVERS|g" | sed "s|MUI_$VERSION|MUI_VERSION|g" > $TEMPFILE
- "$NSIS" $TEMPFILE
- rm $TEMPFILE
-fi