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--GNUmakefile73
-rw-r--r--build_files/cmake/cmake_consistency_check.py30
-rw-r--r--build_files/cmake/cmake_qtcreator_project.py22
-rw-r--r--doc/python_api/examples/mathutils.Vector.py2
-rw-r--r--doc/python_api/examples/mathutils.py8
-rw-r--r--doc/python_api/sphinx_doc_gen.py163
-rwxr-xr-xdoc/python_api/sphinx_doc_gen.sh15
-rw-r--r--intern/audaspace/OpenAL/AUD_OpenALDevice.cpp28
-rw-r--r--intern/ghost/intern/GHOST_WindowWin32.cpp8
-rwxr-xr-xrelease/bin/blender-thumbnailer.py4
-rw-r--r--release/scripts/io/netrender/operators.py2
-rw-r--r--release/scripts/io/netrender/ui.py6
-rw-r--r--release/scripts/io/netrender/utils.py28
-rw-r--r--release/scripts/keyingsets/keyingsets_builtins.py134
-rw-r--r--release/scripts/keyingsets/keyingsets_utils.py82
-rw-r--r--release/scripts/modules/add_object_utils.py6
-rw-r--r--release/scripts/modules/bpy/path.py2
-rw-r--r--release/scripts/modules/bpy_types.py8
-rw-r--r--release/scripts/op/fcurve_euler_filter.py42
-rw-r--r--release/scripts/op/nla.py10
-rw-r--r--release/scripts/op/object.py4
-rw-r--r--release/scripts/op/uvcalc_smart_project.py10
-rw-r--r--release/scripts/presets/ffmpeg/DVD.py2
-rw-r--r--release/scripts/presets/ffmpeg/SVCD.py2
-rw-r--r--release/scripts/presets/ffmpeg/VCD.py2
-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/sss/apple.py2
-rw-r--r--release/scripts/templates/background_job.py2
-rw-r--r--release/scripts/ui/properties_particle.py7
-rw-r--r--release/scripts/ui/properties_physics_common.py29
-rw-r--r--release/scripts/ui/properties_physics_field.py2
-rw-r--r--release/scripts/ui/properties_render.py12
-rw-r--r--release/scripts/ui/space_dopesheet.py11
-rw-r--r--release/scripts/ui/space_graph.py1
-rw-r--r--release/scripts/ui/space_info.py3
-rw-r--r--release/scripts/ui/space_node.py35
-rw-r--r--release/scripts/ui/space_time.py17
-rw-r--r--release/scripts/ui/space_userpref.py37
-rw-r--r--release/scripts/ui/space_view3d_toolbar.py8
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h4
-rw-r--r--source/blender/blenkernel/BKE_blender.h2
-rw-r--r--source/blender/blenkernel/BKE_modifier.h6
-rw-r--r--source/blender/blenkernel/BKE_multires.h1
-rw-r--r--source/blender/blenkernel/BKE_paint.h9
-rw-r--r--source/blender/blenkernel/BKE_subsurf.h1
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c81
-rw-r--r--source/blender/blenkernel/intern/action.c20
-rw-r--r--source/blender/blenkernel/intern/anim.c6
-rw-r--r--source/blender/blenkernel/intern/armature.c7
-rw-r--r--source/blender/blenkernel/intern/brush.c8
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c12
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c4
-rw-r--r--source/blender/blenkernel/intern/multires.c16
-rw-r--r--source/blender/blenkernel/intern/object.c43
-rw-r--r--source/blender/blenkernel/intern/particle.c19
-rw-r--r--source/blender/blenkernel/intern/particle_system.c77
-rw-r--r--source/blender/blenkernel/intern/report.c2
-rw-r--r--source/blender/blenkernel/intern/scene.c1
-rw-r--r--source/blender/blenkernel/intern/sequencer.c1
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c62
-rw-r--r--source/blender/blenlib/BLI_math_geom.h2
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h1
-rw-r--r--source/blender/blenlib/BLI_math_vector.h4
-rw-r--r--source/blender/blenlib/BLI_pbvh.h2
-rw-r--r--source/blender/blenlib/intern/math_geom.c66
-rw-r--r--source/blender/blenlib/intern/math_matrix.c14
-rw-r--r--source/blender/blenlib/intern/math_rotation.c12
-rw-r--r--source/blender/blenlib/intern/math_vector.c15
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c15
-rw-r--r--source/blender/blenlib/intern/pbvh.c20
-rw-r--r--source/blender/blenloader/intern/readfile.c83
-rw-r--r--source/blender/collada/DocumentImporter.h2
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c4
-rw-r--r--source/blender/editors/animation/anim_filter.c9
-rw-r--r--source/blender/editors/animation/anim_markers.c25
-rw-r--r--source/blender/editors/animation/keyframes_draw.c9
-rw-r--r--source/blender/editors/animation/keyframes_edit.c10
-rw-r--r--source/blender/editors/animation/keyframing.c6
-rw-r--r--source/blender/editors/animation/keyingsets.c6
-rw-r--r--source/blender/editors/armature/editarmature.c51
-rw-r--r--source/blender/editors/armature/poseobject.c26
-rw-r--r--source/blender/editors/curve/editcurve.c127
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c15
-rw-r--r--source/blender/editors/include/ED_keyframing.h8
-rw-r--r--source/blender/editors/include/ED_screen.h2
-rw-r--r--source/blender/editors/include/ED_sculpt.h1
-rw-r--r--source/blender/editors/include/ED_view3d.h5
-rw-r--r--source/blender/editors/interface/resources.c5
-rw-r--r--source/blender/editors/interface/view2d.c8
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/object/object_constraint.c16
-rw-r--r--source/blender/editors/object/object_edit.c6
-rw-r--r--source/blender/editors/object/object_transform.c31
-rw-r--r--source/blender/editors/screen/screen_edit.c8
-rw-r--r--source/blender/editors/screen/screen_intern.h2
-rw-r--r--source/blender/editors/screen/screen_ops.c39
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c206
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c33
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c2
-rw-r--r--source/blender/editors/space_graph/graph_edit.c6
-rw-r--r--source/blender/editors/space_graph/graph_ops.c4
-rw-r--r--source/blender/editors/space_image/image_draw.c2
-rw-r--r--source/blender/editors/space_image/image_ops.c2
-rw-r--r--source/blender/editors/space_logic/logic_window.c4
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_node/SConscript2
-rw-r--r--source/blender/editors/space_node/drawnode.c73
-rw-r--r--source/blender/editors/space_node/node_draw.c3
-rw-r--r--source/blender/editors/space_node/node_edit.c170
-rw-r--r--source/blender/editors/space_node/node_intern.h3
-rw-r--r--source/blender/editors/space_node/node_ops.c7
-rw-r--r--source/blender/editors/space_text/text_ops.c4
-rw-r--r--source/blender/editors/space_time/space_time.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c75
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h1
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c7
-rw-r--r--source/blender/editors/transform/transform_conversions.c50
-rw-r--r--source/blender/editors/transform/transform_generics.c2
-rw-r--r--source/blender/makesdna/DNA_armature_types.h5
-rw-r--r--source/blender/makesdna/DNA_curve_types.h3
-rw-r--r--source/blender/makesdna/DNA_particle_types.h8
-rw-r--r--source/blender/makesdna/DNA_screen_types.h3
-rw-r--r--source/blender/makesdna/DNA_space_types.h6
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h4
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c2
-rw-r--r--source/blender/makesrna/RNA_access.h4
-rw-r--r--source/blender/makesrna/intern/makesrna.c2
-rw-r--r--source/blender/makesrna/intern/rna_access.c19
-rw-r--r--source/blender/makesrna/intern/rna_actuator.c87
-rw-r--r--source/blender/makesrna/intern/rna_animation.c8
-rw-r--r--source/blender/makesrna/intern/rna_armature.c14
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c1
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c8
-rw-r--r--source/blender/makesrna/intern/rna_particle.c12
-rw-r--r--source/blender/makesrna/intern/rna_scene.c7
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_screen.c56
-rw-r--r--source/blender/makesrna/intern/rna_space.c64
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c4
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c15
-rw-r--r--source/blender/modifiers/intern/MOD_array.c1
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c1
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c1
-rw-r--r--source/blender/modifiers/intern/MOD_build.c1
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c1
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c1
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c1
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c1
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c1
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c1
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim.c1
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c1
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c1
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c1
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c1
-rw-r--r--source/blender/modifiers/intern/MOD_none.c1
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c1
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c1
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c1
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c25
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c1
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c1
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c1
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c1
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c1
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c1
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c1
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c1
-rw-r--r--source/blender/python/generic/mathutils.c70
-rw-r--r--source/blender/python/generic/mathutils.h1
-rw-r--r--source/blender/python/generic/mathutils_color.c74
-rw-r--r--source/blender/python/generic/mathutils_euler.c224
-rw-r--r--source/blender/python/generic/mathutils_matrix.c785
-rw-r--r--source/blender/python/generic/mathutils_matrix.h2
-rw-r--r--source/blender/python/generic/mathutils_quat.c432
-rw-r--r--source/blender/python/generic/mathutils_vector.c599
-rw-r--r--source/blender/python/generic/py_capi_utils.c22
-rw-r--r--source/blender/python/generic/py_capi_utils.h3
-rw-r--r--source/blender/python/intern/bpy_interface.c52
-rw-r--r--source/blender/python/intern/bpy_operator.c11
-rw-r--r--source/blender/python/intern/bpy_rna.c131
-rw-r--r--source/blender/python/intern/bpy_rna.h4
-rw-r--r--source/blender/python/rna_dump.py59
-rw-r--r--source/blender/render/CMakeLists.txt17
-rw-r--r--source/blender/render/extern/include/RE_raytrace.h217
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h1
-rw-r--r--source/blender/render/intern/include/raycounter.h30
-rw-r--r--source/blender/render/intern/include/rayintersection.h124
-rw-r--r--source/blender/render/intern/include/rayobject.h195
-rw-r--r--source/blender/render/intern/include/render_types.h1
-rw-r--r--source/blender/render/intern/include/rendercore.h3
-rw-r--r--source/blender/render/intern/include/volumetric.h4
-rw-r--r--source/blender/render/intern/raytrace/bvh.h64
-rw-r--r--source/blender/render/intern/raytrace/rayobject.cpp648
-rw-r--r--source/blender/render/intern/raytrace/rayobject_blibvh.cpp (renamed from source/blender/render/intern/source/rayobject_blibvh.c)24
-rw-r--r--source/blender/render/intern/raytrace/rayobject_empty.cpp75
-rw-r--r--source/blender/render/intern/raytrace/rayobject_hint.h2
-rw-r--r--source/blender/render/intern/raytrace/rayobject_instance.cpp (renamed from source/blender/render/intern/source/rayobject_instance.c)72
-rw-r--r--source/blender/render/intern/raytrace/rayobject_internal.h128
-rw-r--r--source/blender/render/intern/raytrace/rayobject_octree.cpp (renamed from source/blender/render/intern/source/rayobject_octree.c)52
-rw-r--r--source/blender/render/intern/raytrace/rayobject_qbvh.cpp38
-rw-r--r--source/blender/render/intern/raytrace/rayobject_raycounter.cpp (renamed from source/blender/render/intern/source/rayobject_raycounter.c)1
-rw-r--r--source/blender/render/intern/raytrace/rayobject_rtbuild.cpp33
-rw-r--r--source/blender/render/intern/raytrace/rayobject_svbvh.cpp24
-rw-r--r--source/blender/render/intern/raytrace/rayobject_vbvh.cpp26
-rw-r--r--source/blender/render/intern/raytrace/reorganize.h12
-rw-r--r--source/blender/render/intern/raytrace/svbvh.h142
-rw-r--r--source/blender/render/intern/raytrace/vbvh.h14
-rw-r--r--source/blender/render/intern/source/convertblender.c71
-rw-r--r--source/blender/render/intern/source/pipeline.c1
-rw-r--r--source/blender/render/intern/source/rayshade.c213
-rw-r--r--source/blender/render/intern/source/render_texture.c (renamed from source/blender/render/intern/source/texture.c)5
-rw-r--r--source/blender/render/intern/source/rendercore.c41
-rw-r--r--source/blender/render/intern/source/renderdatabase.c2
-rw-r--r--source/blender/render/intern/source/shadeoutput.c6
-rw-r--r--source/blender/render/intern/source/volume_precache.c19
-rw-r--r--source/blender/render/intern/source/volumetric.c31
-rw-r--r--source/blender/windowmanager/intern/wm_files.c8
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c29
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c1
-rw-r--r--source/tests/batch_import.py177
-rw-r--r--source/tests/pep8.py6
232 files changed, 4911 insertions, 3077 deletions
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 00000000000..eb21e0e167a
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,73 @@
+# -*- 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# This Makefile does an out-of-source CMake build in ../build/`OS`_`CPU`
+# eg:
+# ../build/Linux_i386
+# This is for users who like to configure & build blender with a single command.
+
+
+# System Vars
+OS:=$(shell uname -s)
+CPU:=$(shell uname -m)
+
+
+# Source and Build DIR's
+BLENDER_DIR:=$(shell pwd -P)
+BUILD_DIR:=$(shell dirname $(BLENDER_DIR))/build/$(OS)_$(CPU)
+
+
+# Get the number of cores for threaded build
+NPROCS:=1
+ifeq ($(OS), Linux)
+ NPROCS:=$(shell grep -c ^processor /proc/cpuinfo)
+endif
+ifeq ($(OS), Darwin)
+ NPROCS:=$(shell system_profiler | awk '/Number Of CPUs/{print $4}{next;}')
+endif
+ifeq ($(OS), FreeBSD)
+ NPROCS:=$(shell sysctl -a | grep "hw.ncpu " | cut -d" " -f3 )
+endif
+ifeq ($(OS), NetBSD)
+ NPROCS:=$(shell sysctl -a | grep "hw.ncpu " | cut -d" " -f3 )
+endif
+
+
+# Build Blender
+all:
+ @echo
+ @echo Configuring Blender ...
+
+ if test ! -f $(BUILD_DIR)/CMakeCache.txt ; then \
+ mkdir -p $(BUILD_DIR) ; \
+ cd $(BUILD_DIR) ; \
+ cmake $(BLENDER_DIR) ; \
+ fi
+
+ @echo
+ @echo Building Blender ...
+ cd $(BUILD_DIR) ; make -s -j $(NPROCS)
+ @echo
+ @echo run blender from "$(BUILD_DIR)/bin/blender"
+ @echo
+
+.PHONY: all
diff --git a/build_files/cmake/cmake_consistency_check.py b/build_files/cmake/cmake_consistency_check.py
index 0998d221b00..87bbc929a93 100644
--- a/build_files/cmake/cmake_consistency_check.py
+++ b/build_files/cmake/cmake_consistency_check.py
@@ -21,6 +21,8 @@
#
# ***** END GPL LICENSE BLOCK *****
+# <pep8 compliant>
+
IGNORE = \
"/test/",\
"/decimate_glut_test/",\
@@ -45,6 +47,8 @@ global_c = set()
import os
from os.path import splitext
+
+
def source_list(path, filename_check=None):
for dirpath, dirnames, filenames in os.walk(path):
@@ -56,31 +60,37 @@ def source_list(path, filename_check=None):
if filename_check is None or filename_check(filename):
yield os.path.join(dirpath, filename)
+
# extension checking
def is_c_header(filename):
ext = splitext(filename)[1]
return (ext in (".h", ".hpp", ".hxx"))
+
def is_cmake(filename):
ext = splitext(filename)[1]
return (ext == ".cmake") or (filename == "CMakeLists.txt")
+
def is_c_header(filename):
ext = splitext(filename)[1]
return (ext in (".h", ".hpp", ".hxx"))
+
def is_c(filename):
ext = splitext(filename)[1]
return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc"))
+
def is_c_any(filename):
return is_c(filename) or is_c_header(filename)
+
def cmake_get_src(f):
-
+
sources_h = []
sources_c = []
-
+
filen = open(f, "r", encoding="utf8")
it = iter(filen)
found = False
@@ -101,7 +111,7 @@ def cmake_get_src(f):
raise Exception("strict formatting not kept 'set(SRC*' %s:%d" % (f, i))
found = True
break
-
+
if "list(APPEND SRC" in l:
if l.endswith(")"):
raise Exception("strict formatting not kept 'list(APPEND SRC...)' on 1 line %s:%d" % (f, i))
@@ -118,11 +128,11 @@ def cmake_get_src(f):
except StopIteration:
it = None
break
-
+
l = l.strip()
if not l.startswith("#"):
-
+
if ")" in l:
if l.strip() != ")":
raise Exception("strict formatting not kept '*)' %s:%d" % (f, i))
@@ -130,7 +140,6 @@ def cmake_get_src(f):
# replace dirs
l = l.replace("${CMAKE_CURRENT_SOURCE_DIR}", cmake_base)
-
if not l:
pass
@@ -140,7 +149,7 @@ def cmake_get_src(f):
raise Exception("Multi-line define '%s' %s:%d" % (l, f, i))
else:
new_file = normpath(join(cmake_base, l))
-
+
if is_c_header(new_file):
sources_h.append(new_file)
elif is_c(new_file):
@@ -168,19 +177,20 @@ def cmake_get_src(f):
if ff not in sources_c:
print(" missing: " + ff)
'''
-
+
filen.close()
for cmake in source_list(base, is_cmake):
cmake_get_src(cmake)
+
def is_ignore(f):
for ig in IGNORE:
if ig in f:
return True
return False
-
+
# First do stupid check, do these files exist?
for f in (global_h | global_c):
if f.endswith("dna.c"):
@@ -189,7 +199,7 @@ for f in (global_h | global_c):
if not os.path.exists(f):
raise Exception("CMake referenced file missing: " + f)
-
+
# now check on files not accounted for.
print("\nC/C++ Files CMake doesnt know about...")
for cf in sorted(source_list(base, is_c)):
diff --git a/build_files/cmake/cmake_qtcreator_project.py b/build_files/cmake/cmake_qtcreator_project.py
index edb15443ebf..3adce66fade 100644
--- a/build_files/cmake/cmake_qtcreator_project.py
+++ b/build_files/cmake/cmake_qtcreator_project.py
@@ -21,6 +21,8 @@
#
# ***** END GPL LICENSE BLOCK *****
+# <pep8 compliant>
+
import os
from os.path import join, dirname, normpath, abspath, splitext, relpath, exists
@@ -28,6 +30,7 @@ base = join(os.path.dirname(__file__), "..", "..")
base = normpath(base)
base = abspath(base)
+
def source_list(path, filename_check=None):
for dirpath, dirnames, filenames in os.walk(path):
@@ -40,33 +43,40 @@ def source_list(path, filename_check=None):
if filename_check is None or filename_check(filepath):
yield filepath
+
# extension checking
def is_c_header(filename):
ext = splitext(filename)[1]
return (ext in (".h", ".hpp", ".hxx"))
+
def is_cmake(filename):
ext = splitext(filename)[1]
return (ext == ".cmake") or (filename == "CMakeLists.txt")
+
def is_c_header(filename):
ext = splitext(filename)[1]
return (ext in (".h", ".hpp", ".hxx"))
+
def is_c(filename):
ext = splitext(filename)[1]
return (ext in (".c", ".cpp", ".cxx", ".m", ".mm", ".rc"))
+
def is_c_any(filename):
return is_c(filename) or is_c_header(filename)
+
def is_svn_file(filename):
- dn, fn = os.path.split(filename)
- filename_svn = join(dn, ".svn", "text-base", "%s.svn-base" % fn)
- return exists(filename_svn)
+ dn, fn = os.path.split(filename)
+ filename_svn = join(dn, ".svn", "text-base", "%s.svn-base" % fn)
+ return exists(filename_svn)
+
def is_project_file(filename):
- return (is_c_any(filename) or is_cmake(filename)) and is_svn_file(filename)
+ return (is_c_any(filename) or is_cmake(filename)) and is_svn_file(filename)
files = list(source_list(base, filename_check=is_project_file))
files_rel = [relpath(f, start=base) for f in files]
@@ -87,8 +97,8 @@ f.write("[General]\n")
qtc_cfg = join(base, "%s.config" % PROJECT_NAME)
if not exists(qtc_cfg):
- f = open(qtc_cfg, 'w')
- f.write("// ADD PREDEFINED MACROS HERE!\n")
+ f = open(qtc_cfg, 'w')
+ f.write("// ADD PREDEFINED MACROS HERE!\n")
print("Project file written to: %s" % qtc_prj)
# --- end
diff --git a/doc/python_api/examples/mathutils.Vector.py b/doc/python_api/examples/mathutils.Vector.py
index fb00e8aead6..880b4ef2590 100644
--- a/doc/python_api/examples/mathutils.Vector.py
+++ b/doc/python_api/examples/mathutils.Vector.py
@@ -10,7 +10,7 @@ vec_b = mathutils.Vector((0, 1, 2))
vec2d = mathutils.Vector((1, 2))
vec3d = mathutils.Vector((1, 0, 0))
-vec4d = vec_a.copy().resize4D()
+vec4d = vec_a.to_4d()
# other mathutuls types
quat = mathutils.Quaternion()
diff --git a/doc/python_api/examples/mathutils.py b/doc/python_api/examples/mathutils.py
index 02f69515f21..dcc10c5885c 100644
--- a/doc/python_api/examples/mathutils.py
+++ b/doc/python_api/examples/mathutils.py
@@ -3,15 +3,15 @@ from math import radians
vec = mathutils.Vector((1.0, 2.0, 3.0))
-mat_rot = mathutils.Matrix.Rotation(radians(90), 4, 'X')
+mat_rot = mathutils.Matrix.Rotation(radians(90.0), 4, 'X')
mat_trans = mathutils.Matrix.Translation(vec)
mat = mat_trans * mat_rot
mat.invert()
-mat3 = mat.rotation_part()
-quat1 = mat.to_quat()
-quat2 = mat3.to_quat()
+mat3 = mat.to_3x3()
+quat1 = mat.to_quaternion()
+quat2 = mat3.to_quaternion()
angle = quat1.difference(quat2)
diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py
index 7cf286b5ac1..b1437c60bf6 100644
--- a/doc/python_api/sphinx_doc_gen.py
+++ b/doc/python_api/sphinx_doc_gen.py
@@ -18,6 +18,8 @@
#
# #**** END GPL LICENSE BLOCK #****
+# <pep8 compliant>
+
script_help_msg = '''
Usage:
@@ -31,11 +33,11 @@ For HTML generation
assuming that ./blender.bin is or links to the blender executable
- Generate html docs by running...
-
+
sphinx-build doc/python_api/sphinx-in doc/python_api/sphinx-out
assuming that you have sphinx 0.6.7 installed
-
+
For PDF generation
------------------
- After you have built doc/python_api/sphinx-in (see above), run:
@@ -82,10 +84,12 @@ def range_str(val):
Converts values to strings for the range directive.
(unused function it seems)
'''
- if val < -10000000: return '-inf'
- if val > 10000000: return 'inf'
- if type(val)==float:
- return '%g' % val
+ if val < -10000000:
+ return '-inf'
+ elif val > 10000000:
+ return 'inf'
+ elif type(val) == float:
+ return '%g' % val
else:
return str(val)
@@ -140,7 +144,7 @@ def pyfunc2sphinx(ident, fw, identifier, py_func, is_class=True):
if not is_class:
func_type = "function"
-
+
# ther rest are class methods
elif arg_str.startswith("(self, "):
arg_str = "(" + arg_str[7:]
@@ -157,14 +161,14 @@ def pyfunc2sphinx(ident, fw, identifier, py_func, is_class=True):
fw("\n")
-def py_descr2sphinx(ident, fw, descr, module_name, type_name, identifier):
+def py_descr2sphinx(ident, fw, descr, module_name, type_name, identifier):
if identifier.startswith("_"):
return
-
+
doc = descr.__doc__
if not doc:
doc = undocumented_message(module_name, type_name, identifier)
-
+
if type(descr) == GetSetDescriptorType:
fw(ident + ".. attribute:: %s\n\n" % identifier)
write_indented_lines(ident + " ", fw, doc, False)
@@ -181,7 +185,7 @@ def py_c_func2sphinx(ident, fw, module_name, type_name, identifier, py_func, is_
'''
c defined function to sphinx.
'''
-
+
# dump the docstring, assume its formatted correctly
if py_func.__doc__:
write_indented_lines(ident, fw, py_func.__doc__, False)
@@ -209,30 +213,30 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
import types
attribute_set = set()
filepath = os.path.join(BASEPATH, module_name + ".rst")
-
+
file = open(filepath, "w")
fw = file.write
-
+
fw(title + "\n")
fw(("=" * len(title)) + "\n\n")
-
+
fw(".. module:: %s\n\n" % module_name)
-
+
if module.__doc__:
# Note, may contain sphinx syntax, dont mangle!
fw(module.__doc__.strip())
fw("\n\n")
-
+
write_example_ref("", fw, module_name)
-
+
# write members of the module
# only tested with PyStructs which are not exactly modules
for key, descr in sorted(type(module).__dict__.items()):
if key.startswith("__"):
continue
# naughty, we also add getset's into PyStructs, this is not typical py but also not incorrect.
- if type(descr) == types.GetSetDescriptorType: # 'bpy_app_type' name is only used for examples and messages
+ if type(descr) == types.GetSetDescriptorType: # 'bpy_app_type' name is only used for examples and messages
py_descr2sphinx("", fw, descr, module_name, "bpy_app_type", key)
attribute_set.add(key)
for key, descr in sorted(type(module).__dict__.items()):
@@ -246,7 +250,7 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
attribute_set.add(key)
fw("\n")
del key, descr
-
+
classes = []
for attribute in sorted(dir(module)):
@@ -255,16 +259,16 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
if attribute in attribute_set:
continue
- if attribute.startswith("n_"): # annoying exception, needed for bpy.app
+ if attribute.startswith("n_"): # annoying exception, needed for bpy.app
continue
-
+
value = getattr(module, attribute)
value_type = type(value)
if value_type == types.FunctionType:
pyfunc2sphinx("", fw, attribute, value, is_class=False)
- elif value_type in (types.BuiltinMethodType, types.BuiltinFunctionType): # both the same at the moment but to be future proof
+ elif value_type in (types.BuiltinMethodType, types.BuiltinFunctionType): # both the same at the moment but to be future proof
# note: can't get args from these, so dump the string as is
# this means any module used like this must have fully formatted docstrings.
py_c_func2sphinx("", fw, module_name, module, attribute, value, is_class=False)
@@ -317,7 +321,6 @@ def pymodule2sphinx(BASEPATH, module_name, module, title):
file.close()
-
def rna2sphinx(BASEPATH):
structs, funcs, ops, props = rna_info.BuildRNAInfo()
@@ -332,14 +335,13 @@ def rna2sphinx(BASEPATH):
file = open(filepath, "w")
fw = file.write
-
- version_string = bpy.app.version_string.split("(")[0]
+ version_string = ".".join(str(v) for v in bpy.app.version)
if bpy.app.build_revision != "Unknown":
version_string = version_string + " r" + bpy.app.build_revision
-
+
# for use with files
version_string_fp = "_".join(str(v) for v in bpy.app.version)
-
+
fw("project = 'Blender'\n")
# fw("master_doc = 'index'\n")
fw("copyright = u'Blender Foundation'\n")
@@ -356,11 +358,11 @@ def rna2sphinx(BASEPATH):
fw("latex_paper_size = 'a4paper'\n")
file.close()
-
+ # main page needed for sphinx (index.html)
filepath = os.path.join(BASEPATH, "contents.rst")
file = open(filepath, "w")
fw = file.write
-
+
fw("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n")
fw(" Blender Documentation contents\n")
fw("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n")
@@ -395,15 +397,15 @@ def rna2sphinx(BASEPATH):
fw("\n")
fw(".. toctree::\n")
fw(" :maxdepth: 1\n\n")
- fw(" bpy.data.rst\n\n") # note: not actually a module
+ fw(" bpy.data.rst\n\n") # note: not actually a module
fw(" bpy.ops.rst\n\n")
fw(" bpy.types.rst\n\n")
-
+
# py modules
fw(" bpy.utils.rst\n\n")
fw(" bpy.path.rst\n\n")
fw(" bpy.app.rst\n\n")
-
+
# C modules
fw(" bpy.props.rst\n\n")
@@ -414,7 +416,6 @@ def rna2sphinx(BASEPATH):
fw(".. toctree::\n")
fw(" :maxdepth: 1\n\n")
-
fw(" mathutils.rst\n\n")
fw(" Freestyle.rst\n\n")
fw(" mathutils.geometry.rst\n\n")
@@ -422,7 +423,7 @@ def rna2sphinx(BASEPATH):
#fw(" bgl.rst\n\n")
fw(" blf.rst\n\n")
fw(" aud.rst\n\n")
-
+
# game engine
fw("===================\n")
fw("Game Engine Modules\n")
@@ -437,7 +438,6 @@ def rna2sphinx(BASEPATH):
file.close()
-
# internal modules
filepath = os.path.join(BASEPATH, "bpy.ops.rst")
file = open(filepath, "w")
@@ -459,7 +459,6 @@ def rna2sphinx(BASEPATH):
fw(" bpy.types.*\n\n")
file.close()
-
# not actually a module, only write this file so we
# can reference in the TOC
filepath = os.path.join(BASEPATH, "bpy.data.rst")
@@ -482,7 +481,6 @@ def rna2sphinx(BASEPATH):
EXAMPLE_SET_USED.add("bpy.data")
-
# python modules
from bpy import utils as module
pymodule2sphinx(BASEPATH, "bpy.utils", module, "Utilities (bpy.utils)")
@@ -496,7 +494,7 @@ def rna2sphinx(BASEPATH):
from bpy import props as module
pymodule2sphinx(BASEPATH, "bpy.props", module, "Property Definitions (bpy.props)")
-
+
import mathutils as module
pymodule2sphinx(BASEPATH, "mathutils", module, "Math Types & Utilities (mathutils)")
del module
@@ -512,7 +510,7 @@ def rna2sphinx(BASEPATH):
import blf as module
pymodule2sphinx(BASEPATH, "blf", module, "Font Drawing (blf)")
del module
-
+
# XXX TODO
#import bgl as module
#pymodule2sphinx(BASEPATH, "bgl", module, "Blender OpenGl wrapper (bgl)")
@@ -525,17 +523,16 @@ def rna2sphinx(BASEPATH):
## game engine
import shutil
# copy2 keeps time/date stamps
- shutil.copy2(os.path.join(BASEPATH,"..","rst","bge.types.rst"), BASEPATH)
- shutil.copy2(os.path.join(BASEPATH,"..","rst","bge.logic.rst"), BASEPATH)
- shutil.copy2(os.path.join(BASEPATH,"..","rst","bge.render.rst"), BASEPATH)
- shutil.copy2(os.path.join(BASEPATH,"..","rst","bge.events.rst"), BASEPATH)
-
+ shutil.copy2(os.path.join(BASEPATH, "..", "rst", "bge.types.rst"), BASEPATH)
+ shutil.copy2(os.path.join(BASEPATH, "..", "rst", "bge.logic.rst"), BASEPATH)
+ shutil.copy2(os.path.join(BASEPATH, "..", "rst", "bge.render.rst"), BASEPATH)
+ shutil.copy2(os.path.join(BASEPATH, "..", "rst", "bge.events.rst"), BASEPATH)
if 0:
filepath = os.path.join(BASEPATH, "bpy.rst")
file = open(filepath, "w")
fw = file.write
-
+
fw("\n")
title = ":mod:`bpy` --- Blender Python Module"
@@ -570,7 +567,7 @@ def rna2sphinx(BASEPATH):
filepath = os.path.join(BASEPATH, "bpy.types.%s.rst" % struct.identifier)
file = open(filepath, "w")
fw = file.write
-
+
base_id = getattr(struct.base, "identifier", "")
if _BPY_STRUCT_FAKE:
@@ -583,16 +580,16 @@ def rna2sphinx(BASEPATH):
title = struct.identifier
fw("%s\n%s\n\n" % (title, "=" * len(title)))
-
+
fw(".. module:: bpy.types\n\n")
-
+
base_ids = [base.identifier for base in struct.get_bases()]
if _BPY_STRUCT_FAKE:
base_ids.append(_BPY_STRUCT_FAKE)
base_ids.reverse()
-
+
if base_ids:
if len(base_ids) > 1:
fw("base classes --- ")
@@ -601,13 +598,13 @@ def rna2sphinx(BASEPATH):
fw(", ".join((":class:`%s`" % base_id) for base_id in base_ids))
fw("\n\n")
-
+
subclass_ids = [s.identifier for s in structs.values() if s.base is struct if not rna_info.rna_id_ignore(s.identifier)]
if subclass_ids:
fw("subclasses --- \n" + ", ".join((":class:`%s`" % s) for s in subclass_ids) + "\n\n")
-
+
base_id = getattr(struct.base, "identifier", "")
-
+
if _BPY_STRUCT_FAKE:
if not base_id:
base_id = _BPY_STRUCT_FAKE
@@ -618,7 +615,7 @@ def rna2sphinx(BASEPATH):
fw(".. class:: %s\n\n" % struct.identifier)
fw(" %s\n\n" % struct.description)
-
+
# properties sorted in alphabetical order
sorted_struct_properties = struct.properties[:]
sorted_struct_properties.sort(key=lambda prop: prop.identifier)
@@ -633,7 +630,7 @@ def rna2sphinx(BASEPATH):
if prop.description:
fw(" %s\n\n" % prop.description)
fw(" :type: %s\n\n" % type_descr)
-
+
# python attributes
py_properties = struct.get_py_properties()
py_prop = None
@@ -646,13 +643,13 @@ def rna2sphinx(BASEPATH):
fw(" .. %s:: %s(%s)\n\n" % ("classmethod" if func.is_classmethod else "method", func.identifier, args_str))
fw(" %s\n\n" % func.description)
-
+
for prop in func.args:
write_param(" ", fw, prop)
if len(func.return_values) == 1:
write_param(" ", fw, func.return_values[0], is_return=True)
- elif func.return_values: # multiple return values
+ elif func.return_values: # multiple return values
fw(" :return (%s):\n" % ", ".join(prop.identifier for prop in func.return_values))
for prop in func.return_values:
type_descr = prop.get_type_description(as_ret=True, class_fmt=":class:`%s`")
@@ -663,11 +660,10 @@ def rna2sphinx(BASEPATH):
fw("\n")
-
# python methods
py_funcs = struct.get_py_functions()
py_func = None
-
+
for identifier, py_func in py_funcs:
pyfunc2sphinx(" ", fw, identifier, py_func, is_class=True)
del py_funcs, py_func
@@ -679,10 +675,10 @@ def rna2sphinx(BASEPATH):
# props
lines[:] = []
-
+
if _BPY_STRUCT_FAKE:
descr_items = [(key, descr) for key, descr in sorted(bpy.types.Struct.__bases__[0].__dict__.items()) if not key.startswith("__")]
-
+
if _BPY_STRUCT_FAKE:
for key, descr in descr_items:
if type(descr) == GetSetDescriptorType:
@@ -694,10 +690,10 @@ def rna2sphinx(BASEPATH):
for identifier, py_prop in base.get_py_properties():
lines.append(" * :class:`%s.%s`\n" % (base.identifier, identifier))
-
+
for identifier, py_prop in base.get_py_properties():
lines.append(" * :class:`%s.%s`\n" % (base.identifier, identifier))
-
+
if lines:
fw(".. rubric:: Inherited Properties\n\n")
@@ -708,7 +704,6 @@ def rna2sphinx(BASEPATH):
fw(line)
fw("\n")
-
# funcs
lines[:] = []
@@ -732,9 +727,8 @@ def rna2sphinx(BASEPATH):
for line in lines:
fw(line)
fw("\n")
-
- lines[:] = []
+ lines[:] = []
if struct.references:
# use this otherwise it gets in the index for a normal heading.
@@ -750,13 +744,12 @@ def rna2sphinx(BASEPATH):
fw(" * :class:`%s`\n" % ref)
fw("\n")
-
for struct in structs.values():
# TODO, rna_info should filter these out!
if "_OT_" in struct.identifier:
continue
write_struct(struct)
-
+
# special case, bpy_struct
if _BPY_STRUCT_FAKE:
filepath = os.path.join(BASEPATH, "bpy.types.%s.rst" % _BPY_STRUCT_FAKE)
@@ -781,41 +774,40 @@ def rna2sphinx(BASEPATH):
descr_items = [(key, descr) for key, descr in sorted(bpy.types.Struct.__bases__[0].__dict__.items()) if not key.startswith("__")]
for key, descr in descr_items:
- if type(descr) == MethodDescriptorType: # GetSetDescriptorType, GetSetDescriptorType's are not documented yet
+ if type(descr) == MethodDescriptorType: # GetSetDescriptorType, GetSetDescriptorType's are not documented yet
py_descr2sphinx(" ", fw, descr, "bpy.types", _BPY_STRUCT_FAKE, key)
for key, descr in descr_items:
if type(descr) == GetSetDescriptorType:
py_descr2sphinx(" ", fw, descr, "bpy.types", _BPY_STRUCT_FAKE, key)
-
# operators
def write_ops():
- API_BASEURL='https://svn.blender.org/svnroot/bf-blender/trunk/blender/release/scripts'
+ API_BASEURL = "https://svn.blender.org/svnroot/bf-blender/trunk/blender/release/scripts"
fw = None
last_mod = ''
-
+
for op_key in sorted(ops.keys()):
op = ops[op_key]
-
+
if last_mod != op.module_name:
filepath = os.path.join(BASEPATH, "bpy.ops.%s.rst" % op.module_name)
file = open(filepath, "w")
fw = file.write
-
- title = "%s Operators" % (op.module_name[0].upper() + op.module_name[1:])
+
+ title = "%s Operators" % (op.module_name[0].upper() + op.module_name[1:])
fw("%s\n%s\n\n" % (title, "=" * len(title)))
-
+
fw(".. module:: bpy.ops.%s\n\n" % op.module_name)
last_mod = op.module_name
args_str = ", ".join(prop.get_arg_default(force=True) for prop in op.args)
fw(".. function:: %s(%s)\n\n" % (op.func_name, args_str))
- # if the description isn't valid, we output the standard warning
+ # if the description isn't valid, we output the standard warning
# with a link to the wiki so that people can help
if not op.description or op.description == "(undocumented operator)":
- operator_description = undocumented_message('bpy.ops',op.module_name,op.func_name)
+ operator_description = undocumented_message('bpy.ops', op.module_name, op.func_name)
else:
operator_description = op.description
@@ -827,12 +819,13 @@ def rna2sphinx(BASEPATH):
location = op.get_location()
if location != (None, None):
- fw(" :file: `%s <%s/%s>`_:%d\n\n" % (location[0],API_BASEURL,location[0],location[1]))
-
+ fw(" :file: `%s <%s/%s>`_:%d\n\n" % (location[0], API_BASEURL, location[0], location[1]))
+
write_ops()
file.close()
+
def main():
import bpy
if 'bpy' not in dir():
@@ -842,9 +835,9 @@ def main():
import shutil
script_dir = os.path.dirname(__file__)
- path_in = os.path.join(script_dir,'sphinx-in')
- path_out = os.path.join(script_dir,'sphinx-out')
- path_examples = os.path.join(script_dir,'examples')
+ path_in = os.path.join(script_dir, "sphinx-in")
+ path_out = os.path.join(script_dir, "sphinx-out")
+ path_examples = os.path.join(script_dir, "examples")
# only for partial updates
path_in_tmp = path_in + "-tmp"
@@ -855,7 +848,6 @@ def main():
if f.endswith(".py"):
EXAMPLE_SET.add(os.path.splitext(f)[0])
-
# only for full updates
if _BPY_FULL_REBUILD:
shutil.rmtree(path_in, True)
@@ -872,7 +864,7 @@ def main():
# now move changed files from 'path_in_tmp' --> 'path_in'
file_list_path_in = set(os.listdir(path_in))
file_list_path_in_tmp = set(os.listdir(path_in_tmp))
-
+
# remove deprecated files that have been removed.
for f in sorted(file_list_path_in):
if f not in file_list_path_in_tmp:
@@ -888,14 +880,13 @@ def main():
if f in file_list_path_in:
if filecmp.cmp(f_from, f_to):
do_copy = False
-
+
if do_copy:
print("\tupdating: %s" % f)
shutil.copy(f_from, f_to)
'''else:
print("\tkeeping: %s" % f) # eh, not that useful'''
-
EXAMPLE_SET_UNUSED = EXAMPLE_SET - EXAMPLE_SET_USED
if EXAMPLE_SET_UNUSED:
print("\nUnused examples found in '%s'..." % path_examples)
diff --git a/doc/python_api/sphinx_doc_gen.sh b/doc/python_api/sphinx_doc_gen.sh
index 90116b43414..c027db83831 100755
--- a/doc/python_api/sphinx_doc_gen.sh
+++ b/doc/python_api/sphinx_doc_gen.sh
@@ -4,10 +4,11 @@
# ssh upload means you need an account on the server
BLENDER="./blender.bin"
-SSH_HOST="ideasman42@emo.blender.org"
+SSH_USER="ideasman42"
+SSH_HOST=$SSH_USER"@emo.blender.org"
SSH_UPLOAD="/data/www/vhosts/www.blender.org/documentation" # blender_python_api_VERSION, added after
-# sed string from hell, 'Blender 2.53 (sub 1) Build' --> '2_53_1'
+# 'Blender 2.53 (sub 1) Build' --> '2_53_1' as a shell script.
# "_".join(str(v) for v in bpy.app.version)
# custom blender vars
blender_srcdir=$(dirname $0)/../../
@@ -25,12 +26,18 @@ $BLENDER --background --factory-startup --python $SPHINXBASE/sphinx_doc_gen.py
# html
sphinx-build $SPHINXBASE/sphinx-in $SPHINXBASE/sphinx-out
cp $SPHINXBASE/sphinx-out/contents.html $SPHINXBASE/sphinx-out/index.html
-ssh ideasman42@emo.blender.org 'rm -rf '$SSH_UPLOAD_FULL'/*'
+ssh $SSH_USER@emo.blender.org 'rm -rf '$SSH_UPLOAD_FULL'/*'
rsync --progress -avze "ssh -p 22" $SPHINXBASE/sphinx-out/* $SSH_HOST:$SSH_UPLOAD_FULL/
+# symlink the dir to a static URL
+ssh $SSH_USER@emo.blender.org 'rm '$SSH_UPLOAD'/250PythonDoc && ln -s '$SSH_UPLOAD_FULL' '$SSH_UPLOAD'/250PythonDoc'
+
# pdf
sphinx-build -b latex $SPHINXBASE/sphinx-in $SPHINXBASE/sphinx-out
cd $SPHINXBASE/sphinx-out
make
cd -
-rsync --progress -avze "ssh -p 22" $SPHINXBASE/sphinx-out/contents.pdf $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.pdf
+
+# rename so local PDF has matching name.
+mv $SPHINXBASE/sphinx-out/contents.pdf $SPHINXBASE/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf
+rsync --progress -avze "ssh -p 22" $SPHINXBASE/sphinx-out/blender_python_reference_$BLENDER_VERSION.pdf $SSH_HOST:$SSH_UPLOAD_FULL/blender_python_reference_$BLENDER_VERSION.pdf
diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
index 5df7ec4fb0c..6a9f2c40d92 100644
--- a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
+++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
@@ -129,6 +129,9 @@ void AUD_OpenALDevice::updateStreams()
ALint info;
AUD_DeviceSpecs specs = m_specs;
ALCenum cerr;
+ std::list<AUD_OpenALHandle*> stopSounds;
+ std::list<AUD_OpenALHandle*> pauseSounds;
+ AUD_HandleIterator it;
while(1)
{
@@ -139,7 +142,7 @@ void AUD_OpenALDevice::updateStreams()
if(cerr == ALC_NO_ERROR)
{
// for all sounds
- for(AUD_HandleIterator it = m_playingSounds->begin(); it != m_playingSounds->end(); it++)
+ for(it = m_playingSounds->begin(); it != m_playingSounds->end(); it++)
{
sound = *it;
@@ -234,21 +237,12 @@ void AUD_OpenALDevice::updateStreams()
if(sound->stop)
sound->stop(sound->stop_data);
- // increment the iterator to the next value,
- // because the sound gets deleted in the list here.
- ++it;
// pause or
if(sound->keep)
- pause(sound);
+ pauseSounds.push_back(sound);
// stop
else
- stop(sound);
- // decrement again, so that we get the next sound in the
- // next loop run
- if(m_playingSounds->empty())
- break;
- else
- --it;
+ stopSounds.push_back(sound);
}
// continue playing
else
@@ -256,6 +250,15 @@ void AUD_OpenALDevice::updateStreams()
}
}
+ for(it = pauseSounds.begin(); it != pauseSounds.end(); it++)
+ pause(*it);
+
+ for(it = stopSounds.begin(); it != stopSounds.end(); it++)
+ stop(*it);
+
+ pauseSounds.clear();
+ stopSounds.clear();
+
alcProcessContext(m_context);
}
@@ -340,6 +343,7 @@ AUD_OpenALDevice::AUD_OpenALDevice(AUD_DeviceSpecs specs, int buffersize)
m_useMC = alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE;
alGetError();
+ alcGetError(m_device);
m_specs = specs;
m_buffersize = buffersize;
diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp
index 7afd3fef832..f5773ea2d90 100644
--- a/intern/ghost/intern/GHOST_WindowWin32.cpp
+++ b/intern/ghost/intern/GHOST_WindowWin32.cpp
@@ -805,12 +805,10 @@ GHOST_TSuccess GHOST_WindowWin32::removeDrawingContext()
GHOST_TSuccess success;
switch (m_drawingContextType) {
case GHOST_kDrawingContextTypeOpenGL:
- if (m_hGlRc) {
- bool first = m_hGlRc == s_firsthGLRc;
+ // we shouldn't remove the drawing context if it's the first OpenGL context
+ // If we do, we get corrupted drawing. See #19997
+ if (m_hGlRc && m_hGlRc!=s_firsthGLRc) {
success = ::wglDeleteContext(m_hGlRc) == TRUE ? GHOST_kSuccess : GHOST_kFailure;
- if (first) {
- s_firsthGLRc = 0;
- }
m_hGlRc = 0;
}
else {
diff --git a/release/bin/blender-thumbnailer.py b/release/bin/blender-thumbnailer.py
index 16a89d29724..abd85cd3bec 100755
--- a/release/bin/blender-thumbnailer.py
+++ b/release/bin/blender-thumbnailer.py
@@ -18,6 +18,8 @@
#
# ##### END GPL LICENSE BLOCK #####
+# <pep8 compliant>
+
"""
Thumbnailer runs with python 2.6 and 3.x.
To run automatically with nautilus:
@@ -116,7 +118,7 @@ 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]
diff --git a/release/scripts/io/netrender/operators.py b/release/scripts/io/netrender/operators.py
index 30f53666f19..f2c2fda7bde 100644
--- a/release/scripts/io/netrender/operators.py
+++ b/release/scripts/io/netrender/operators.py
@@ -401,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
diff --git a/release/scripts/io/netrender/ui.py b/release/scripts/io/netrender/ui.py
index fffb8a74e2a..0581e054dff 100644
--- a/release/scripts/io/netrender/ui.py
+++ b/release/scripts/io/netrender/ui.py
@@ -276,7 +276,7 @@ class RENDER_PT_network_slaves(NeedValidAddress, NetRenderButtonsPanel, bpy.type
sub.operator("render.netclientslaves", icon='FILE_REFRESH', text="")
sub.operator("render.netclientblacklistslave", icon='ZOOMOUT', text="")
- 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]
@@ -307,7 +307,7 @@ class RENDER_PT_network_slaves_blacklist(NeedValidAddress, NetRenderButtonsPanel
sub = row.column(align=True)
sub.operator("render.netclientwhitelistslave", icon='ZOOMOUT', text="")
- 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]
@@ -341,7 +341,7 @@ class RENDER_PT_network_jobs(NeedValidAddress, NetRenderButtonsPanel, bpy.types.
sub.operator("render.netclientcancelall", icon='PANEL_CLOSE', text="")
sub.operator("render.netclientdownload", icon='RENDER_ANIMATION', text="")
- 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]
diff --git a/release/scripts/io/netrender/utils.py b/release/scripts/io/netrender/utils.py
index e18d915dae0..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("1.2", encoding='utf8')
+VERSION = bytes("1.3", encoding='utf8')
# Jobs status
JOB_WAITING = 0 # before all data has been entered
@@ -227,6 +227,10 @@ def prefixPath(prefix_directory, file_path, prefix_path, force = False):
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:
@@ -236,14 +240,28 @@ def getResults(server_address, server_port, job_id, resolution_x, resolution_y,
filepath = os.path.join(bpy.app.tempdir, "netrender_temp.blend")
bpy.ops.wm.save_as_mainfile(filepath=filepath, copy=True, check_existing=False)
-
- process = subprocess.Popen([sys.argv[0], "-b", "-noaudio", filepath, "-P", __file__] + frame_arguments + ["--", "GetResults", server_address, str(server_port), job_id, str(resolution_x), str(resolution_y), str(resolution_percentage)], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+
+ 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:
- process.stdout.read(1024) # empty buffer to be sure
- process.stdout.read()
+ 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):
diff --git a/release/scripts/keyingsets/keyingsets_builtins.py b/release/scripts/keyingsets/keyingsets_builtins.py
index 8a10342d6a5..2a6bd682bf7 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
+ # 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
+ # 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
+ # 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,15 +142,16 @@ class BUILTIN_KSI_RotScale(bpy.types.KeyingSetInfo):
# iterator - use callback for selected bones/objects
iterator = RKS_ITER_selected_item
- # generator
+ # 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"
@@ -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 rotation
+ # 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
+ # generator
def generate(self, context, ks, data):
# location
RKS_GEN_location(self, context, ks, data)
@@ -173,39 +205,41 @@ 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 doing this
+ # generator - use callback for doing this
generate = RKS_GEN_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',
+ '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
@@ -221,39 +255,39 @@ class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo):
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):
+ 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('['):
+
+ if prop.startswith('['):
# custom properties
path = id_path + prop
- else:
+ 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):
@@ -262,7 +296,7 @@ class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo):
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
@@ -270,7 +304,7 @@ class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo):
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
@@ -278,16 +312,16 @@ class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo):
ksi.addProp(ks, bone, prop)
else:
if bone.lock_rotation_w == False:
- ksi.addProp(ks, bone, prop, 0) # w = 0
-
+ 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
+ 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
+ # 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")
@@ -295,30 +329,30 @@ class BUILTIN_KSI_WholeCharacter(bpy.types.KeyingSetInfo):
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):
+ 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():
+ 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))
-###############################
+###############################
classes = [
BUILTIN_KSI_Location,
@@ -329,7 +363,7 @@ classes = [
BUILTIN_KSI_LocScale,
BUILTIN_KSI_LocRotScale,
BUILTIN_KSI_RotScale,
-
+
BUILTIN_KSI_WholeCharacter,
BUILTIN_KSI_VisualLoc,
@@ -354,4 +388,4 @@ def unregister():
if __name__ == "__main__":
register()
-###############################
+###############################
diff --git a/release/scripts/keyingsets/keyingsets_utils.py b/release/scripts/keyingsets/keyingsets_utils.py
index 953cff9e01e..630ac12dc7b 100644
--- a/release/scripts/keyingsets/keyingsets_utils.py
+++ b/release/scripts/keyingsets/keyingsets_utils.py
@@ -1,45 +1,51 @@
-# This file defines a set of methods that are useful for various
+# 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.
+
+# <pep8 compliant>
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,25 +58,26 @@ 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;
-
- # if we haven't got an ID-block as 'data', try to restrict
+ 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...
-
+ 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:
@@ -79,19 +86,20 @@ def RKS_GEN_available(ksi, context, ks, data):
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
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:
@@ -101,29 +109,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':
@@ -132,21 +142,22 @@ 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)
@@ -158,6 +169,7 @@ def RKS_GEN_scaling(ksi, context, ks, data):
classes = []
+
def register():
pass
diff --git a/release/scripts/modules/add_object_utils.py b/release/scripts/modules/add_object_utils.py
index 01a1a73aedf..10707734bc4 100644
--- a/release/scripts/modules/add_object_utils.py
+++ b/release/scripts/modules/add_object_utils.py
@@ -37,7 +37,7 @@ def add_object_align_init(context, operator):
location = mathutils.Matrix.Translation(context.scene.cursor_location)
if operator:
- operator.properties.location = location.translation_part()
+ operator.properties.location = location.to_translation()
# rotation
view_align = (context.user_preferences.edit.object_align == 'VIEW')
@@ -49,10 +49,10 @@ def add_object_align_init(context, operator):
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().resize4x4()
+ rotation = mathutils.Euler(operator.properties.rotation).to_matrix().to_4x4()
else:
if view_align and space_data:
- rotation = space_data.region_3d.view_matrix.rotation_part().invert().resize4x4()
+ rotation = space_data.region_3d.view_matrix.to_3x3().inverted().to_4x4()
else:
rotation = mathutils.Matrix()
diff --git a/release/scripts/modules/bpy/path.py b/release/scripts/modules/bpy/path.py
index e131be648ce..9a29b713882 100644
--- a/release/scripts/modules/bpy/path.py
+++ b/release/scripts/modules/bpy/path.py
@@ -129,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
diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py
index 61c3f11ccef..1cb30765bf0 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 Vector((1.0, 0.0, 0.0)) * self.matrix.rotation_part()
+ 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 Vector((0.0, 1.0, 0.0)) * self.matrix.rotation_part()
+ 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 Vector((0.0, 0.0, 1.0)) * self.matrix.rotation_part()
+ return Vector((0.0, 0.0, 1.0)) * self.matrix.to_3x3()
@property
def basename(self):
@@ -284,7 +284,7 @@ class EditBone(StructRNA, _GenericBone, metaclass=StructMetaIDProp):
Expects a 4x4 or 3x3 matrix.
"""
from mathutils import Vector
- z_vec = Vector((0.0, 0.0, 1.0)) * self.matrix.rotation_part()
+ 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
diff --git a/release/scripts/op/fcurve_euler_filter.py b/release/scripts/op/fcurve_euler_filter.py
index b396fa0562f..0e7f0b69eca 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"
@@ -56,9 +78,11 @@ class DiscontFilterOp(bpy.types.Operator):
main(context)
return {'FINISHED'}
+
def register():
pass
+
def unregister():
pass
diff --git a/release/scripts/op/nla.py b/release/scripts/op/nla.py
index acea7d53572..d47668d68e3 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()
@@ -104,8 +104,8 @@ 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.location = matrix.to_translation()
+ #pbone.rotation_quaternion = matrix.to_quaternion()
pbone.matrix_basis = matrix
pbone.keyframe_insert("location", -1, f, name)
diff --git a/release/scripts/op/object.py b/release/scripts/op/object.py
index 15da8f107a2..8fee6e2166d 100644
--- a/release/scripts/op/object.py
+++ b/release/scripts/op/object.py
@@ -484,8 +484,8 @@ 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 [(b * rot) + trans for b in base_tri]
scene = bpy.context.scene
diff --git a/release/scripts/op/uvcalc_smart_project.py b/release/scripts/op/uvcalc_smart_project.py
index 3a835ae671e..aaa8583b70f 100644
--- a/release/scripts/op/uvcalc_smart_project.py
+++ b/release/scripts/op/uvcalc_smart_project.py
@@ -168,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.
@@ -227,7 +227,7 @@ def islandIntersectUvIsland(source, target, SourceOffset):
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
@@ -773,7 +773,7 @@ def packIslands(islandList):
def VectoQuat(vec):
- vec = vec.copy().normalize()
+ vec = vec.normalized()
if abs(vec.x) > 0.5:
return vec.to_track_quat('Z', 'X')
else:
@@ -926,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 = []
@@ -963,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!
diff --git a/release/scripts/presets/ffmpeg/DVD.py b/release/scripts/presets/ffmpeg/DVD.py
index aef11672273..e18ec9f817b 100644
--- a/release/scripts/presets/ffmpeg/DVD.py
+++ b/release/scripts/presets/ffmpeg/DVD.py
@@ -14,7 +14,7 @@ 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/SVCD.py b/release/scripts/presets/ffmpeg/SVCD.py
index 3076c42bd51..c71a3851af0 100644
--- a/release/scripts/presets/ffmpeg/SVCD.py
+++ b/release/scripts/presets/ffmpeg/SVCD.py
@@ -14,7 +14,7 @@ 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
diff --git a/release/scripts/presets/ffmpeg/VCD.py b/release/scripts/presets/ffmpeg/VCD.py
index f559cb18fb0..faf27efe9e6 100644
--- a/release/scripts/presets/ffmpeg/VCD.py
+++ b/release/scripts/presets/ffmpeg/VCD.py
@@ -14,7 +14,7 @@ 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
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/sss/apple.py b/release/scripts/presets/sss/apple.py
index c5f60ee5095..b2ee19ca125 100644
--- a/release/scripts/presets/sss/apple.py
+++ b/release/scripts/presets/sss/apple.py
@@ -1,5 +1,5 @@
import bpy
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/templates/background_job.py b/release/scripts/templates/background_job.py
index f199ee5ad50..0337f8f4922 100644
--- a/release/scripts/templates/background_job.py
+++ b/release/scripts/templates/background_job.py
@@ -82,7 +82,7 @@ def main():
# When --help or no args are given, print this help
usage_text = "Run blender in background mode with this script:"
- usage_text += " blender -b -P " + __file__ + " -- [options]"
+ usage_text += " blender --background --python " + __file__ + " -- [options]"
parser = optparse.OptionParser(usage=usage_text)
diff --git a/release/scripts/ui/properties_particle.py b/release/scripts/ui/properties_particle.py
index 9cde2891177..596d0381f43 100644
--- a/release/scripts/ui/properties_particle.py
+++ b/release/scripts/ui/properties_particle.py
@@ -190,8 +190,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':
@@ -206,6 +208,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):
diff --git a/release/scripts/ui/properties_physics_common.py b/release/scripts/ui/properties_physics_common.py
index 30b9061e982..ec6ec21fa26 100644
--- a/release/scripts/ui/properties_physics_common.py
+++ b/release/scripts/ui/properties_physics_common.py
@@ -20,6 +20,7 @@
import bpy
+
class PhysicButtonsPanel():
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
@@ -29,7 +30,8 @@ class PhysicButtonsPanel():
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:
@@ -41,35 +43,36 @@ def physics_add(self, layout, md, name, type, typeicon, toggles):
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);
-
+ 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);
-
+ 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);
+ 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
diff --git a/release/scripts/ui/properties_physics_field.py b/release/scripts/ui/properties_physics_field.py
index 584cdaad108..f46f78ca017 100644
--- a/release/scripts/ui/properties_physics_field.py
+++ b/release/scripts/ui/properties_physics_field.py
@@ -37,7 +37,7 @@ class PhysicButtonsPanel():
class PHYSICS_PT_field(PhysicButtonsPanel, bpy.types.Panel):
bl_label = "Force Fields"
-
+
@classmethod
def poll(cls, context):
ob = context.object
diff --git a/release/scripts/ui/properties_render.py b/release/scripts/ui/properties_render.py
index 70fda787e9b..2efffa520d8 100644
--- a/release/scripts/ui/properties_render.py
+++ b/release/scripts/ui/properties_render.py
@@ -39,8 +39,8 @@ class RENDER_MT_framerate_presets(bpy.types.Menu):
preset_subdir = "framerate"
preset_operator = "script.execute_preset"
draw = bpy.types.Menu.draw_preset
-
-
+
+
class RenderButtonsPanel():
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
@@ -858,20 +858,20 @@ class RENDER_PT_dimensions(RenderButtonsPanel, bpy.types.Panel):
fps_rate = round(rd.fps / rd.fps_base)
else:
fps_rate = round(rd.fps / rd.fps_base, 2)
-
+
# 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="/")
diff --git a/release/scripts/ui/space_dopesheet.py b/release/scripts/ui/space_dopesheet.py
index f4e0c9c8506..5efdaa58abc 100644
--- a/release/scripts/ui/space_dopesheet.py
+++ b/release/scripts/ui/space_dopesheet.py
@@ -25,7 +25,7 @@ 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'
@@ -33,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="")
@@ -112,8 +115,12 @@ class DOPESHEET_HT_header(bpy.types.Header):
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)
- elif st.mode in ('ACTION', 'SHAPEKEY'):
+ 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
diff --git a/release/scripts/ui/space_graph.py b/release/scripts/ui/space_graph.py
index 6a311409137..51c5ebcfbf8 100644
--- a/release/scripts/ui/space_graph.py
+++ b/release/scripts/ui/space_graph.py
@@ -213,6 +213,7 @@ class GRAPH_MT_key(bpy.types.Menu):
layout.separator()
layout.operator("graph.clean")
+ layout.operator("graph.smooth")
layout.operator("graph.sample")
layout.operator("graph.bake")
diff --git a/release/scripts/ui/space_info.py b/release/scripts/ui/space_info.py
index dda21dea84e..9881cb55692 100644
--- a/release/scripts/ui/space_info.py
+++ b/release/scripts/ui/space_info.py
@@ -50,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()
diff --git a/release/scripts/ui/space_node.py b/release/scripts/ui/space_node.py
index e37f6ffe4ae..31ac25ff41a 100644
--- a/release/scripts/ui/space_node.py
+++ b/release/scripts/ui/space_node.py
@@ -68,6 +68,9 @@ 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.separator()
@@ -158,6 +161,38 @@ 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():
diff --git a/release/scripts/ui/space_time.py b/release/scripts/ui/space_time.py
index 3873dc11d96..c1293e87c85 100644
--- a/release/scripts/ui/space_time.py
+++ b/release/scripts/ui/space_time.py
@@ -80,6 +80,7 @@ class TIME_HT_header(bpy.types.Header):
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)
@@ -168,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()
diff --git a/release/scripts/ui/space_userpref.py b/release/scripts/ui/space_userpref.py
index bcc322eacc9..d1e2c581660 100644
--- a/release/scripts/ui/space_userpref.py
+++ b/release/scripts/ui/space_userpref.py
@@ -1157,13 +1157,27 @@ 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
@@ -1182,10 +1196,22 @@ class WM_OT_addon_install(bpy.types.Operator):
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'}
@@ -1193,9 +1219,12 @@ 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):
+ 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
try:
diff --git a/release/scripts/ui/space_view3d_toolbar.py b/release/scripts/ui/space_view3d_toolbar.py
index 9261324366b..c3280a67b7e 100644
--- a/release/scripts/ui/space_view3d_toolbar.py
+++ b/release/scripts/ui/space_view3d_toolbar.py
@@ -34,6 +34,7 @@ def draw_repeat_tools(context, layout):
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)
@@ -42,6 +43,7 @@ def draw_keyframing_tools(context, layout):
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)
@@ -88,9 +90,9 @@ class VIEW3D_PT_tools_objectmode(View3DPanel, bpy.types.Panel):
col.label(text="Shading:")
col.operator("object.shade_smooth", text="Smooth")
col.operator("object.shade_flat", text="Flat")
-
+
draw_keyframing_tools(context, layout)
-
+
col = layout.column(align=True)
col.label(text="Motion Paths:")
col.operator("object.paths_calculate", text="Calculate Paths")
@@ -406,7 +408,7 @@ class VIEW3D_PT_tools_posemode(View3DPanel, bpy.types.Panel):
col.operator("poselib.pose_add", text="Add To Library")
draw_keyframing_tools(context, layout)
-
+
col = layout.column(align=True)
col.label(text="Motion Paths:")
col.operator("pose.paths_calculate", text="Calculate Paths")
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 5ce6c522e90..48127d3cf4c 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -508,6 +508,10 @@ void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct EditMesh *em
int editmesh_get_first_deform_matrices(struct Scene *, struct Object *, struct EditMesh *em,
float (**deformmats)[3][3], float (**deformcos)[3]);
+/* returns an array of deform matrices for crazyspace correction when sculpting */
+void sculpt_get_deform_matrices(struct Scene *scene, struct Object *ob,
+ float (**deformmats)[3][3], float (**deformcos)[3]);
+
void weight_to_rgb(float input, float *fr, float *fg, float *fb);
/* convert layers requested by a GLSL material to actually available layers in
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index a4b7d8469e0..65e7f848ea0 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -45,7 +45,7 @@ struct Scene;
struct Main;
#define BLENDER_VERSION 256
-#define BLENDER_SUBVERSION 0
+#define BLENDER_SUBVERSION 1
#define BLENDER_MINVERSION 250
#define BLENDER_MINSUBVERSION 0
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 97bef6ab565..5bef7527c87 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -134,6 +134,12 @@ typedef struct ModifierTypeInfo {
float (*vertexCos)[3], int numVerts,
int useRenderParams, int isFinalCalc);
+ /* Like deformMatricesEM but called from object mode (for supporting modifiers in sculpt mode) */
+ void (*deformMatrices)(
+ struct ModifierData *md, struct Object *ob,
+ struct DerivedMesh *derivedData,
+ float (*vertexCos)[3], float (*defMats)[3][3], int numVerts);
+
/* Like deformVerts but called during editmode (for supporting modifiers)
*/
void (*deformVertsEM)(
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index 5cafd24c1fd..23fabce68ba 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -53,6 +53,7 @@ struct DerivedMesh *multires_dm_create_from_derived(struct MultiresModifierData*
struct MultiresModifierData *find_multires_modifier_before(struct Scene *scene,
struct ModifierData *lastmd);
+struct MultiresModifierData *get_multires_modifier(struct Scene *scene, struct Object *ob, int use_first);
struct DerivedMesh *get_multires_dm(struct Scene *scene, struct MultiresModifierData *mmd,
struct Object *ob);
void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 20742033a2e..2203277b301 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -78,8 +78,11 @@ typedef struct SculptSession {
/* PBVH acceleration structure */
struct PBVH *pbvh;
- /* Used temporarily per-stroke */
- float *vertexcosnos;
+ /* Paiting on deformed mesh */
+ int modifiers_active; /* object is deformed with some modifiers */
+ float (*orig_cos)[3]; /* coords of undeformed mesh */
+ float (*deform_cos)[3]; /* coords of deformed mesh but without stroke displacement */
+ float (*deform_imats)[3][3]; /* crazyspace deformation matricies */
/* Partial redraw */
int partial_redraw;
@@ -95,8 +98,6 @@ typedef struct SculptSession {
struct GPUDrawObject *drawobject;
- int modifiers_active;
-
rcti previous_r;
} SculptSession;
diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h
index 940a0027d0b..ef3ad3ad2e9 100644
--- a/source/blender/blenkernel/BKE_subsurf.h
+++ b/source/blender/blenkernel/BKE_subsurf.h
@@ -72,7 +72,6 @@ typedef struct CCGDerivedMesh {
char *faceFlags;
struct PBVH *pbvh;
- int pbvh_draw;
struct ListBase *fmap;
struct IndexNode *fmap_mem;
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index a2ef625c6e6..658d29f0046 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -53,6 +53,7 @@
#include "BKE_object.h"
#include "BKE_paint.h"
#include "BKE_texture.h"
+#include "BKE_multires.h"
#include "BLO_sys_types.h" // for intptr_t support
@@ -65,6 +66,8 @@
#include "GPU_extensions.h"
#include "GPU_material.h"
+#include "ED_sculpt.h" /* for ED_sculpt_modifiers_changed */
+
///////////////////////////////////
///////////////////////////////////
@@ -1676,6 +1679,12 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
int required_mode;
int isPrevDeform= FALSE;
int skipVirtualArmature = (useDeform < 0);
+ MultiresModifierData *mmd= get_multires_modifier(scene, ob, 0);
+ int has_multires = mmd != NULL, multires_applied = 0;
+ int sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt;
+
+ if(mmd && !mmd->sculptlvl)
+ has_multires = 0;
if(!skipVirtualArmature) {
firstmd = modifiers_getVirtualModifierList(ob);
@@ -1714,6 +1723,12 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
if(useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) continue;
if(mti->type == eModifierTypeType_OnlyDeform) {
+ if(sculpt_mode && !has_multires)
+ if(!ELEM(md->type, eModifierType_Armature, eModifierType_ShapeKey)) {
+ modifier_setError(md, "Not supported in sculpt mode.");
+ continue;
+ }
+
if(!deformedVerts)
deformedVerts = mesh_getVertexCos(me, &numVerts);
@@ -1759,13 +1774,18 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
ModifierTypeInfo *mti = modifierType_getInfo(md->type);
md->scene= scene;
-
+
if(!modifier_isEnabled(scene, md, required_mode)) continue;
if(mti->type == eModifierTypeType_OnlyDeform && !useDeform) continue;
if((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
modifier_setError(md, "Modifier requires original data, bad stack position.");
continue;
}
+ if(sculpt_mode && (!has_multires || multires_applied))
+ if(md->type != eModifierType_Armature || multires_applied) {
+ modifier_setError(md, "Not supported in sculpt mode.");
+ continue;
+ }
if(needMapping && !modifier_supportsMapping(md)) continue;
if(useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) continue;
@@ -1928,6 +1948,9 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
/* grab modifiers until index i */
if((index >= 0) && (modifiers_indexInObject(ob, md) >= index))
break;
+
+ if(sculpt_mode && md->type == eModifierType_Multires)
+ multires_applied = 1;
}
for(md=firstmd; md; md=md->next)
@@ -2222,14 +2245,9 @@ static void clear_mesh_caches(Object *ob)
ob->derivedDeform->release(ob->derivedDeform);
ob->derivedDeform= NULL;
}
- /* we free pbvh on changes, except during sculpt since it can't deal with
- changing PVBH node organization, we hope topology does not change in
- the meantime .. weak */
- if(ob->sculpt && ob->sculpt->pbvh) {
- if(!ob->sculpt->cache) {
- BLI_pbvh_free(ob->sculpt->pbvh);
- ob->sculpt->pbvh= NULL;
- }
+
+ if(ob->sculpt) {
+ ED_sculpt_modifiers_changed(ob);
}
}
@@ -2523,6 +2541,51 @@ int editmesh_get_first_deform_matrices(Scene *scene, Object *ob, EditMesh *em, f
return numleft;
}
+void sculpt_get_deform_matrices(Scene *scene, Object *ob, float (**deformmats)[3][3], float (**deformcos)[3])
+{
+ ModifierData *md;
+ DerivedMesh *dm;
+ int a, numVerts= 0;
+ float (*defmats)[3][3]= NULL, (*deformedVerts)[3]= NULL;
+ MultiresModifierData *mmd= get_multires_modifier(scene, ob, 0);
+ int has_multires = mmd != NULL && mmd->sculptlvl > 0;
+
+ if(has_multires) {
+ *deformmats= NULL;
+ *deformcos= NULL;
+ return;
+ }
+
+ dm= NULL;
+ md= modifiers_getVirtualModifierList(ob);
+
+ for(; md; md= md->next) {
+ ModifierTypeInfo *mti= modifierType_getInfo(md->type);
+
+ if(!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
+
+ if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatrices) {
+ if(!defmats) {
+ Mesh *me= (Mesh*)ob->data;
+ dm= getMeshDerivedMesh(me, ob, NULL);
+ deformedVerts= mesh_getVertexCos(me, &numVerts);
+ defmats= MEM_callocN(sizeof(*defmats)*numVerts, "defmats");
+
+ for(a=0; a<numVerts; a++)
+ unit_m3(defmats[a]);
+ }
+
+ mti->deformMatrices(md, ob, dm, deformedVerts, defmats, numVerts);
+ }
+ }
+
+ if(dm)
+ dm->release(dm);
+
+ *deformmats= defmats;
+ *deformcos= deformedVerts;
+}
+
/* ******************* GLSL ******************** */
void DM_add_tangent_layer(DerivedMesh *dm)
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 08b57ba18a3..3bfdbdc4fc9 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -424,7 +424,8 @@ bPoseChannel *verify_pose_channel(bPose *pose, const char *name)
BLI_strncpy(chan->name, name, sizeof(chan->name));
/* init vars to prevent math errors */
- chan->quat[0] = chan->rotAxis[1]= 1.0f;
+ unit_qt(chan->quat);
+ unit_axis_angle(chan->rotAxis, &chan->rotAngle);
chan->size[0] = chan->size[1] = chan->size[2] = 1.0f;
chan->limitmin[0]= chan->limitmin[1]= chan->limitmin[2]= -180.0f;
@@ -1041,7 +1042,6 @@ void extract_pose_from_pose(bPose *pose, const bPose *src)
void rest_pose(bPose *pose)
{
bPoseChannel *pchan;
- int i;
if (!pose)
return;
@@ -1050,16 +1050,12 @@ void rest_pose(bPose *pose)
memset(pose->cyclic_offset, 0, sizeof(pose->cyclic_offset));
for (pchan=pose->chanbase.first; pchan; pchan= pchan->next) {
- for (i=0; i<3; i++) {
- pchan->loc[i]= 0.0f;
- pchan->quat[i+1]= 0.0f;
- pchan->eul[i]= 0.0f;
- pchan->size[i]= 1.0f;
- pchan->rotAxis[i]= 0.0f;
- }
- pchan->quat[0]= pchan->rotAxis[1]= 1.0f;
- pchan->rotAngle= 0.0f;
-
+ zero_v3(pchan->loc);
+ zero_v3(pchan->eul);
+ unit_qt(pchan->quat);
+ unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+ pchan->size[0]= pchan->size[1]= pchan->size[2]= 1.0f;
+
pchan->flag &= ~(POSE_LOC|POSE_ROT|POSE_SIZE);
}
}
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index 68a949ed25a..ab1da04e683 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -1156,7 +1156,7 @@ static void face_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, floa
dm->release(dm);
}
-static void new_particle_duplilist(ListBase *lb, ID *UNUSED(id), Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated)
+static void new_particle_duplilist(ListBase *lb, ID *id, Scene *scene, Object *par, float par_space_mat[][4], ParticleSystem *psys, int level, int animated)
{
GroupObject *go;
Object *ob=0, **oblist=0, obcopy, *obcopylist=0;
@@ -1375,7 +1375,7 @@ static void new_particle_duplilist(ListBase *lb, ID *UNUSED(id), Scene *scene, O
/* Normal particles and cached hair live in global space so we need to
* remove the real emitter's transformation before 2nd order duplication.
*/
- if(par_space_mat)
+ if(par_space_mat && GS(id->name) != ID_GR)
mul_m4_m4m4(mat, pamat, psys->imat);
else
copy_m4_m4(mat, pamat);
@@ -1391,7 +1391,7 @@ static void new_particle_duplilist(ListBase *lb, ID *UNUSED(id), Scene *scene, O
if(part->draw & PART_DRAW_GLOBAL_OB)
VECADD(mat[3], mat[3], vec);
- dob= new_dupli_object(lb, ob, mat, ob->lay, counter, OB_DUPLIPARTS, animated);
+ dob= new_dupli_object(lb, ob, mat, ob->lay, counter, GS(id->name) == ID_GR ? OB_DUPLIGROUP : OB_DUPLIPARTS, animated);
copy_m4_m4(dob->omat, oldobmat);
if(G.rendering)
psys_get_dupli_texture(par, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 1a219939b77..14c4b6f97ab 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -1401,13 +1401,6 @@ void where_is_armature_bone(Bone *bone, Bone *prevbone)
VECCOPY(bone->arm_mat[3], bone->head);
}
- /* head */
- VECCOPY(bone->arm_head, bone->arm_mat[3]);
- /* tail is in current local coord system */
- VECCOPY(vec, bone->arm_mat[1]);
- mul_v3_fl(vec, bone->length);
- add_v3_v3v3(bone->arm_tail, bone->arm_head, vec);
-
/* and the kiddies */
prevbone= bone;
for(bone= bone->childbase.first; bone; bone= bone->next) {
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index a78d2ecaaa2..b1931ebe0a7 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -907,7 +907,13 @@ static void brush_apply_pressure(BrushPainter *painter, Brush *brush, float pres
void brush_jitter_pos(Brush *brush, float *pos, float *jitterpos)
{
- if(brush->jitter){
+ int use_jitter= brush->jitter != 0;
+
+ /* jitter-ed brush gives wierd and unpredictable result for this
+ kinds of stroke, so manyally disable jitter usage (sergey) */
+ use_jitter&= (brush->flag & (BRUSH_RESTORE_MESH|BRUSH_ANCHORED)) == 0;
+
+ if(use_jitter){
float rand_pos[2];
const int radius= brush_size(brush);
const int diameter= 2*radius;
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 71e704fe6c8..932be711938 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -76,6 +76,7 @@ typedef struct {
/* Cached */
struct PBVH *pbvh;
int pbvh_draw;
+
/* Mesh connectivity */
struct ListBase *fmap;
struct IndexNode *fmap_mem;
@@ -222,6 +223,17 @@ static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
cddm->pbvh_draw = can_pbvh_draw(ob, dm);
BLI_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert,
me->totface, me->totvert);
+
+ if(ob->sculpt->modifiers_active) {
+ float (*vertCos)[3];
+ int totvert;
+
+ totvert= dm->getNumVerts(dm);
+ vertCos= MEM_callocN(3*totvert*sizeof(float), "cdDM_getPBVH vertCos");
+ dm->getVertCos(dm, vertCos);
+ BLI_pbvh_apply_vertCos(cddm->pbvh, vertCos);
+ MEM_freeN(vertCos);
+ }
}
return cddm->pbvh;
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 71c3e76c207..cedf4e93247 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -2452,7 +2452,9 @@ void DAG_id_tag_update(ID *id, short flag)
}
}
else {
- BLI_assert(!"invalid flag for this 'idtype'");
+ /* disable because this is called on various ID types automatically.
+ * where printing warning is not useful. for now just ignore */
+ /* BLI_assert(!"invalid flag for this 'idtype'"); */
}
}
}
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index c67abc47e6f..2a3052d10c9 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -92,8 +92,10 @@ MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *
return NULL;
}
-/* used for applying scale on mdisps layer and syncing subdivide levels when joining objects */
-static MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob)
+/* used for applying scale on mdisps layer and syncing subdivide levels when joining objects
+ use_first - return first multires modifier if all multires'es are disabled
+*/
+MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, int use_first)
{
ModifierData *md;
MultiresModifierData *mmd= NULL, *firstmmd= NULL;
@@ -111,7 +113,7 @@ static MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob)
}
}
- if(!mmd) {
+ if(!mmd && use_first) {
/* active multires have not been found
try to use first one */
return firstmmd;
@@ -1568,8 +1570,8 @@ void multires_load_old(Object *ob, Mesh *me)
static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob)
{
- MultiresModifierData *mmd= get_multires_modifier(scene, ob);
- MultiresModifierData *to_mmd= get_multires_modifier(scene, to_ob);
+ MultiresModifierData *mmd= get_multires_modifier(scene, ob, 1);
+ MultiresModifierData *to_mmd= get_multires_modifier(scene, to_ob, 1);
if(!mmd) {
/* object could have MDISP even when there is no multires modifier
@@ -1599,7 +1601,7 @@ void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
int *gridOffset;
int i, /*numGrids,*/ gridSize, dGridSize, dSkip, totvert;
float (*vertCos)[3] = NULL;
- MultiresModifierData *mmd= get_multires_modifier(scene, ob);
+ MultiresModifierData *mmd= get_multires_modifier(scene, ob, 1);
MultiresModifierData high_mmd;
CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
@@ -1725,7 +1727,7 @@ void multires_topology_changed(Scene *scene, Object *ob)
Mesh *me= (Mesh*)ob->data;
MDisps *mdisp= NULL, *cur= NULL;
int i, grid= 0, corners;
- MultiresModifierData *mmd= get_multires_modifier(scene, ob);
+ MultiresModifierData *mmd= get_multires_modifier(scene, ob, 1);
if(mmd)
multires_set_tot_mdisps(me, mmd->totlvl);
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 90e61be3356..860ced6de0b 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -59,11 +59,9 @@
#include "BLI_pbvh.h"
#include "BLI_utildefines.h"
-
-
#include "BKE_main.h"
#include "BKE_global.h"
-
+#include "BKE_idprop.h"
#include "BKE_armature.h"
#include "BKE_action.h"
#include "BKE_bullet.h"
@@ -248,6 +246,13 @@ void free_sculptsession(Object *ob)
if(ss->layer_co)
MEM_freeN(ss->layer_co);
+ if(ss->orig_cos)
+ MEM_freeN(ss->orig_cos);
+ if(ss->deform_cos)
+ MEM_freeN(ss->deform_cos);
+ if(ss->deform_imats)
+ MEM_freeN(ss->deform_imats);
+
MEM_freeN(ss);
ob->sculpt = NULL;
@@ -1018,10 +1023,13 @@ Object *add_only_object(int type, const char *name)
* but rotations default to quaternions
*/
ob->rotmode= ROT_MODE_EUL;
- /* axis-angle must not have a 0,0,0 axis, so set y-axis as default... */
- ob->rotAxis[1]= ob->drotAxis[1]= 1.0f;
- /* quaternions should be 1,0,0,0 by default.... */
- ob->quat[0]= ob->dquat[0]= 1.0f;
+
+ unit_axis_angle(ob->rotAxis, &ob->rotAngle);
+ unit_axis_angle(ob->drotAxis, &ob->drotAngle);
+
+ unit_qt(ob->quat);
+ unit_qt(ob->dquat);
+
/* rotation locks should be 4D for 4 component rotations by default... */
ob->protectflag = OB_LOCK_ROT4D;
@@ -1608,7 +1616,17 @@ void object_make_proxy(Object *ob, Object *target, Object *gob)
armature_set_id_extern(ob);
}
-
+
+ /* copy IDProperties */
+ if(ob->id.properties) {
+ IDP_FreeProperty(ob->id.properties);
+ MEM_freeN(ob->id.properties);
+ ob->id.properties= NULL;
+ }
+ if(target->id.properties) {
+ ob->id.properties= IDP_CopyProperty(target->id.properties);
+ }
+
/* copy drawtype info */
ob->dt= target->dt;
}
@@ -1696,8 +1714,13 @@ void object_mat3_to_rot(Object *ob, float mat[][3], short use_compat)
{
switch(ob->rotmode) {
case ROT_MODE_QUAT:
- mat3_to_quat(ob->quat, mat);
- sub_v4_v4(ob->quat, ob->dquat);
+ {
+ float dquat[4];
+ mat3_to_quat(ob->quat, mat);
+ normalize_qt_qt(dquat, ob->dquat);
+ invert_qt(dquat);
+ mul_qt_qtqt(ob->quat, dquat, ob->quat);
+ }
break;
case ROT_MODE_AXISANGLE:
mat3_to_axis_angle(ob->rotAxis, &ob->rotAngle, mat);
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 11ea82803eb..f6b97dcb78e 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -1194,12 +1194,12 @@ static void mvert_to_particle(ParticleKey *key, MVert *mvert, HairKey *hkey)
key->time = hkey->time;
}
-static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, float frs_sec, ParticleInterpolationData *pind, ParticleKey *result)
+static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData *pa, float t, ParticleInterpolationData *pind, ParticleKey *result)
{
PTCacheEditPoint *point = pind->epoint;
ParticleKey keys[4];
int point_vel = (point && point->keys->vel);
- float real_t, dfra, keytime;
+ float real_t, dfra, keytime, invdt;
/* billboards wont fill in all of these, so start cleared */
memset(keys, 0, sizeof(keys));
@@ -1338,11 +1338,12 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
dfra = keys[2].time - keys[1].time;
keytime = (real_t - keys[1].time) / dfra;
+ invdt = dfra * 0.04f * psys->part->timetweak;
/* convert velocity to timestep size */
if(pind->keyed || pind->cache || point_vel){
- mul_v3_fl(keys[1].vel, dfra / frs_sec);
- mul_v3_fl(keys[2].vel, dfra / frs_sec);
+ mul_v3_fl(keys[1].vel, invdt);
+ mul_v3_fl(keys[2].vel, invdt);
interp_qt_qtqt(result->rot,keys[1].rot,keys[2].rot,keytime);
}
@@ -1353,7 +1354,7 @@ static void do_particle_interpolation(ParticleSystem *psys, int p, ParticleData
/* the velocity needs to be converted back from cubic interpolation */
if(pind->keyed || pind->cache || point_vel)
- mul_v3_fl(result->vel, frs_sec / dfra);
+ mul_v3_fl(result->vel, 1.f/invdt);
}
/************************************************/
/* Particles on a dm */
@@ -2954,7 +2955,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
time = (float)k / (float)steps;
t = birthtime + time * (dietime - birthtime);
result.time = -t;
- do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, &result);
+ do_particle_interpolation(psys, p, pa, t, &pind, &result);
copy_v3_v3(ca->co, result.co);
/* dynamic hair is in object space */
@@ -3133,7 +3134,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
time = (float)k / (float)steps;
t = birthtime + time * (dietime - birthtime);
result.time = -t;
- do_particle_interpolation(psys, i, pa, t, frs_sec, &pind, &result);
+ do_particle_interpolation(psys, i, pa, t, &pind, &result);
copy_v3_v3(ca->co, result.co);
/* non-hair points are already in global space */
@@ -3954,7 +3955,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
ParticleThreadContext ctx; /* fake thread context for child modifiers */
ParticleInterpolationData pind;
- float t, frs_sec = sim->scene->r.frs_sec;
+ float t;
float co[3], orco[3];
float hairmat[4][4];
int totpart = psys->totpart;
@@ -3982,7 +3983,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
* account when subdividing for instance */
pind.dm = psys_in_edit_mode(sim->scene, psys) ? NULL : psys->hair_out_dm;
init_particle_interpolation(sim->ob, psys, pa, &pind);
- do_particle_interpolation(psys, p, pa, t, frs_sec, &pind, state);
+ do_particle_interpolation(psys, p, pa, t, &pind, state);
if(!keyed && !cached) {
if((pa->flag & PARS_REKEY)==0) {
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index a0948e61708..4d3a908edb0 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -137,9 +137,9 @@ static int tot_particles(ParticleSystem *psys, PTCacheID *pid)
if(pid && psys->pointcache->flag & PTCACHE_EXTERNAL)
return pid->cache->totpoint;
else if(psys->part->distr == PART_DISTR_GRID && psys->part->from != PART_FROM_VERT)
- return psys->part->grid_res * psys->part->grid_res * psys->part->grid_res;
+ return psys->part->grid_res * psys->part->grid_res * psys->part->grid_res - psys->totunexist;
else
- return psys->part->totpart;
+ return psys->part->totpart - psys->totunexist;
}
void psys_reset(ParticleSystem *psys, int mode)
@@ -439,9 +439,14 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
size[(axis+1)%3] = MIN2(size[(axis+1)%3],res);
size[(axis+2)%3] = MIN2(size[(axis+2)%3],res);
- min[0]+=d/2.0f;
- min[1]+=d/2.0f;
- min[2]+=d/2.0f;
+ size[0] = MAX2(size[0], 1);
+ size[1] = MAX2(size[1], 1);
+ size[2] = MAX2(size[2], 1);
+
+ /* no full offset for flat/thin objects */
+ min[0]+= d < delta[0] ? d/2.f : delta[0]/2.f;
+ min[1]+= d < delta[1] ? d/2.f : delta[1]/2.f;
+ min[2]+= d < delta[2] ? d/2.f : delta[2]/2.f;
for(i=0,p=0,pa=psys->particles; i<res; i++){
for(j=0; j<res; j++){
@@ -497,7 +502,7 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
pa=psys->particles + a1*a1mul + a2*a2mul;
VECCOPY(co1,pa->fuv);
- co1[a]-=d/2.0f;
+ co1[a]-= d < delta[a] ? d/2.f : delta[a]/2.f;
VECCOPY(co2,co1);
co2[a]+=delta[a] + 0.001f*d;
co1[a]-=0.001f*d;
@@ -553,6 +558,18 @@ static void distribute_particles_in_grid(DerivedMesh *dm, ParticleSystem *psys)
}
}
}
+
+ if(psys->part->grid_rand > 0.f) {
+ float rfac = d * psys->part->grid_rand;
+ for(p=0,pa=psys->particles; p<psys->totpart; p++,pa++){
+ if(pa->flag & PARS_UNEXIST)
+ continue;
+
+ pa->fuv[0] += rfac * (PSYS_FRAND(p + 31) - 0.5f);
+ pa->fuv[1] += rfac * (PSYS_FRAND(p + 32) - 0.5f);
+ pa->fuv[2] += rfac * (PSYS_FRAND(p + 33) - 0.5f);
+ }
+ }
}
/* modified copy from rayshade.c */
@@ -1554,8 +1571,51 @@ static void initialize_all_particles(ParticleSimulationData *sim)
ParticleSystem *psys = sim->psys;
PARTICLE_P;
- LOOP_PARTICLES
+ psys->totunexist = 0;
+
+ LOOP_PARTICLES {
initialize_particle(sim, pa, p);
+ if(pa->flag & PARS_UNEXIST)
+ psys->totunexist++;
+ }
+
+ /* Free unexisting particles. */
+ if(psys->totpart && psys->totunexist == psys->totpart) {
+ if(psys->particles->boid)
+ MEM_freeN(psys->particles->boid);
+
+ MEM_freeN(psys->particles);
+ psys->particles = NULL;
+ psys->totpart = psys->totunexist = 0;
+ }
+
+ if(psys->totunexist) {
+ int newtotpart = psys->totpart - psys->totunexist;
+ ParticleData *npa, *newpars;
+
+ npa = newpars = MEM_callocN(newtotpart * sizeof(ParticleData), "particles");
+
+ for(p=0, pa=psys->particles; p<newtotpart; p++, pa++, npa++) {
+ while(pa->flag & PARS_UNEXIST)
+ pa++;
+
+ memcpy(npa, pa, sizeof(ParticleData));
+ }
+
+ if(psys->particles->boid)
+ MEM_freeN(psys->particles->boid);
+ MEM_freeN(psys->particles);
+ psys->particles = newpars;
+ psys->totpart -= psys->totunexist;
+
+ if(psys->particles->boid) {
+ BoidParticle *newboids = MEM_callocN(psys->totpart * sizeof(BoidParticle), "boid particles");
+
+ LOOP_PARTICLES
+ pa->boid = newboids++;
+
+ }
+ }
if(psys->part->type != PART_FLUID) {
#if 0 // XXX old animation system
@@ -4091,6 +4151,9 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys)
if(psys->recalc & PSYS_RECALC_TYPE)
psys_changed_type(&sim);
+ if(psys->recalc & PSYS_RECALC_RESET)
+ psys->totunexist = 0;
+
/* setup necessary physics type dependent additional data if it doesn't yet exist */
psys_prepare_physics(&sim);
diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c
index e623c095ac7..044e1350be1 100644
--- a/source/blender/blenkernel/intern/report.c
+++ b/source/blender/blenkernel/intern/report.c
@@ -124,7 +124,7 @@ void BKE_reportf(ReportList *reports, ReportType type, const char *format, ...)
Report *report;
va_list args;
- if(!reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
+ if(G.background || !reports || ((reports->flag & RPT_PRINT) && (type >= reports->printlevel))) {
va_start(args, format);
vprintf(format, args);
va_end(args);
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index fe6d834cb70..3c58b97a0c0 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -381,6 +381,7 @@ Scene *add_scene(const char *name)
sce->r.fg_stamp[3]= 1.0f;
sce->r.bg_stamp[0]= sce->r.bg_stamp[1]= sce->r.bg_stamp[2]= 0.0f;
sce->r.bg_stamp[3]= 0.25f;
+ sce->r.raytrace_options = R_RAYTRACE_USE_INSTANCES;
sce->r.seq_prev_type= OB_SOLID;
sce->r.seq_rend_type= OB_SOLID;
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index beda03e2257..6aca23b8011 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -3541,6 +3541,7 @@ static Sequence *seq_dupli(struct Scene *scene, struct Scene *scene_to, Sequence
if (seq->strip->proxy) {
seqn->strip->proxy = MEM_dupallocN(seq->strip->proxy);
+ seqn->strip->proxy->anim = 0;
}
if (seq->strip->color_balance) {
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index e75dc27c7b5..a2d3016099d 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -70,8 +70,6 @@ static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v);
static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e);
static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f);
-static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm);
-
///
static void *arena_alloc(CCGAllocatorHDL a, int numBytes) {
@@ -1150,7 +1148,7 @@ static void ccgDM_drawVerts(DerivedMesh *dm) {
static void ccgdm_pbvh_update(CCGDerivedMesh *ccgdm)
{
- if(ccgdm->pbvh && ccgDM_use_grid_pbvh(ccgdm)) {
+ if(ccgdm->pbvh) {
CCGFace **faces;
int totface;
@@ -2240,28 +2238,10 @@ static ListBase *ccgDM_getFaceMap(Object *ob, DerivedMesh *dm)
return ccgdm->fmap;
}
-static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm)
-{
- ModifierData *md;
- MultiresModifierData *mmd= ccgdm->multires.mmd;
-
- /* in sync with sculpt mode, only use multires grid pbvh if we are
- the last enabled modifier in the stack, otherwise we use the base
- mesh */
- if(!mmd)
- return 0;
-
- for(md=mmd->modifier.next; md; md= md->next)
- if(modifier_isEnabled(mmd->modifier.scene, md, eModifierMode_Realtime))
- return 0;
-
- return 1;
-}
-
static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
{
CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
- int gridSize, numGrids, grid_pbvh;
+ int gridSize, numGrids;
if(!ob) {
ccgdm->pbvh= NULL;
@@ -2271,21 +2251,8 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
if(!ob->sculpt)
return NULL;
- grid_pbvh = ccgDM_use_grid_pbvh(ccgdm);
-
- if(ob->sculpt->pbvh) {
- if(grid_pbvh) {
- /* pbvh's grids, gridadj and gridfaces points to data inside ccgdm
- but this can be freed on ccgdm release, this updates the pointers
- when the ccgdm gets remade, the assumption is that the topology
- does not change. */
- ccgdm_create_grids(dm);
- BLI_pbvh_grids_update(ob->sculpt->pbvh, ccgdm->gridData, ccgdm->gridAdjacency, (void**)ccgdm->gridFaces);
- }
-
+ if(ob->sculpt->pbvh)
ccgdm->pbvh = ob->sculpt->pbvh;
- ccgdm->pbvh_draw = grid_pbvh;
- }
if(ccgdm->pbvh)
return ccgdm->pbvh;
@@ -2293,25 +2260,14 @@ static struct PBVH *ccgDM_getPBVH(Object *ob, DerivedMesh *dm)
/* no pbvh exists yet, we need to create one. only in case of multires
we build a pbvh over the modified mesh, in other cases the base mesh
is being sculpted, so we build a pbvh from that. */
- if(grid_pbvh) {
- ccgdm_create_grids(dm);
-
- gridSize = ccgDM_getGridSize(dm);
- numGrids = ccgDM_getNumGrids(dm);
+ ccgdm_create_grids(dm);
- ob->sculpt->pbvh= ccgdm->pbvh = BLI_pbvh_new();
- BLI_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency,
- numGrids, gridSize, (void**)ccgdm->gridFaces);
- ccgdm->pbvh_draw = 1;
- }
- else if(ob->type == OB_MESH) {
- Mesh *me= ob->data;
+ gridSize = ccgDM_getGridSize(dm);
+ numGrids = ccgDM_getNumGrids(dm);
- ob->sculpt->pbvh= ccgdm->pbvh = BLI_pbvh_new();
- BLI_pbvh_build_mesh(ccgdm->pbvh, me->mface, me->mvert,
- me->totface, me->totvert);
- ccgdm->pbvh_draw = 0;
- }
+ ob->sculpt->pbvh= ccgdm->pbvh = BLI_pbvh_new();
+ BLI_pbvh_build_grids(ccgdm->pbvh, ccgdm->gridData, ccgdm->gridAdjacency,
+ numGrids, gridSize, (void**)ccgdm->gridFaces);
return ccgdm->pbvh;
}
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index 701786e4b72..8f939e5dc61 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -120,6 +120,8 @@ int isect_aabb_aabb_v3(float min1[3], float max1[3], float min2[3], float max2[3
int clip_line_plane(float clipco[3], float plane[4], float co[3]);
+void plot_line_v2v2i(int p1[2], int p2[2], int (*callback)(int, int, void *), void *userData);
+
/****************************** Interpolation ********************************/
/* tri or quad, d can be NULL */
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index c3efc64b9d6..7d0b8dfeaf3 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -39,6 +39,7 @@ extern "C" {
/* stored in (w, x, y, z) order */
/* init */
+void unit_axis_angle(float axis[3], float *angle);
void unit_qt(float q[4]);
void copy_qt_qt(float q[4], const float a[4]);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 5a5d518940d..16b8ff8e472 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -84,6 +84,7 @@ MINLINE void madd_v4_v4fl(float r[4], const float a[4], float f);
MINLINE void negate_v3(float r[3]);
MINLINE void negate_v3_v3(float r[3], const float a[3]);
+MINLINE void negate_v4(float r[4]);
MINLINE float dot_v2v2(const float a[2], const float b[2]);
MINLINE float dot_v3v3(const float a[3], const float b[3]);
@@ -122,6 +123,7 @@ void mid_v3_v3v3(float r[3], const float a[3], const float b[3]);
/********************************* Comparison ********************************/
MINLINE int is_zero_v3(const float a[3]);
+MINLINE int is_zero_v4(const float a[4]);
MINLINE int is_one_v3(const float a[3]);
MINLINE int equals_v2v2(const float *v1, const float *v2);
@@ -172,6 +174,8 @@ void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]);
/***************************** Array Functions *******************************/
/* attempted to follow fixed length vertex functions. names could be improved*/
void range_vni(int *array, const int size, const int start);
+void negate_vn(float *array_tar, const int size);
+void negate_vn_vn(float *array_tar, const float *array_src, const int size);
void mul_vn_fl(float *array, const int size, const float f);
void mul_vn_vn_fl(float *array_tar, const float *array_src, const int size, const float f);
void add_vn_vn(float *array_tar, const float *array_src, const int size);
diff --git a/source/blender/blenlib/BLI_pbvh.h b/source/blender/blenlib/BLI_pbvh.h
index 4797aeb2364..f89068c885e 100644
--- a/source/blender/blenlib/BLI_pbvh.h
+++ b/source/blender/blenlib/BLI_pbvh.h
@@ -118,8 +118,6 @@ float BLI_pbvh_node_get_tmin(PBVHNode* node);
void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
void BLI_pbvh_redraw_BB(PBVH *bvh, float bb_min[3], float bb_max[3]);
void BLI_pbvh_get_grid_updates(PBVH *bvh, int clear, void ***gridfaces, int *totface);
-void BLI_pbvh_grids_update(PBVH *bvh, struct DMGridData **grids,
- struct DMGridAdjacency *gridadj, void **gridfaces);
/* vertex deformer */
float (*BLI_pbvh_get_vertCos(struct PBVH *pbvh))[3];
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 15f696e073c..d7a71f8567c 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -1358,6 +1358,71 @@ int clip_line_plane(float p1[3], float p2[3], float plane[4])
}
}
+
+void plot_line_v2v2i(int p1[2], int p2[2], int (*callback)(int, int, void *), void *userData)
+{
+ int x1= p1[0];
+ int y1= p1[1];
+ int x2= p2[0];
+ int y2= p2[1];
+
+ signed char ix;
+ signed char iy;
+
+ // if x1 == x2 or y1 == y2, then it does not matter what we set here
+ int delta_x = (x2 > x1?(ix = 1, x2 - x1):(ix = -1, x1 - x2)) << 1;
+ int delta_y = (y2 > y1?(iy = 1, y2 - y1):(iy = -1, y1 - y2)) << 1;
+
+ if(callback(x1, y1, userData) == 0) {
+ return;
+ }
+
+ if (delta_x >= delta_y) {
+ // error may go below zero
+ int error = delta_y - (delta_x >> 1);
+
+ while (x1 != x2) {
+ if (error >= 0) {
+ if (error || (ix > 0)) {
+ y1 += iy;
+ error -= delta_x;
+ }
+ // else do nothing
+ }
+ // else do nothing
+
+ x1 += ix;
+ error += delta_y;
+
+ if(callback(x1, y1, userData) == 0) {
+ return ;
+ }
+ }
+ }
+ else {
+ // error may go below zero
+ int error = delta_x - (delta_y >> 1);
+
+ while (y1 != y2) {
+ if (error >= 0) {
+ if (error || (iy > 0)) {
+ x1 += ix;
+ error -= delta_y;
+ }
+ // else do nothing
+ }
+ // else do nothing
+
+ y1 += iy;
+ error += delta_x;
+
+ if(callback(x1, y1, userData) == 0) {
+ return;
+ }
+ }
+ }
+}
+
/****************************** Interpolation ********************************/
static float tri_signed_area(float *v1, float *v2, float *v3, int i, int j)
@@ -2566,4 +2631,3 @@ float form_factor_hemi_poly(float p[3], float n[3], float v1[3], float v2[3], fl
return contrib;
}
-
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 77ef825ee34..75134358c31 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -109,6 +109,20 @@ void copy_m4_m3(float m1[][4], float m2[][3]) /* no clear */
}
+void swap_m3m3(float m1[][3], float m2[][3])
+{
+ float t;
+ int i, j;
+
+ for(i = 0; i < 3; i++) {
+ for (j = 0; j < 3; j++) {
+ t = m1[i][j];
+ m1[i][j] = m2[i][j];
+ m2[i][j] = t;
+ }
+ }
+}
+
void swap_m4m4(float m1[][4], float m2[][4])
{
float t;
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 28a37d9675a..2038121e3f2 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -34,7 +34,17 @@
/* used to test is a quat is not normalized */
#define QUAT_EPSILON 0.0001
-void unit_qt(float *q)
+/* convenience, avoids setting Y axis everywhere */
+void unit_axis_angle(float axis[3], float *angle)
+{
+ axis[0]= 0.0f;
+ axis[1]= 1.0f;
+ axis[2]= 0.0f;
+ *angle= 0.0f;
+}
+
+
+void unit_qt(float q[4])
{
q[0]= 1.0f;
q[1]= q[2]= q[3]= 0.0f;
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 37a68cb0fca..bcad7894e86 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -375,6 +375,21 @@ void range_vni(int *array_tar, const int size, const int start)
while(i--) { *(array_pt--) = j--; }
}
+void negate_vn(float *array_tar, const int size)
+{
+ float *array_pt= array_tar + (size-1);
+ int i= size;
+ while(i--) { *(array_pt--) *= -1.0f; }
+}
+
+void negate_vn_vn(float *array_tar, const float *array_src, const int size)
+{
+ float *tar= array_tar + (size-1);
+ const float *src= array_src + (size-1);
+ int i= size;
+ while(i--) { *(tar--) = - *(src--); }
+}
+
void mul_vn_fl(float *array_tar, const int size, const float f)
{
float *array_pt= array_tar + (size-1);
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index 8f00e7b6d0c..ae1b443bc56 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -282,6 +282,14 @@ MINLINE void negate_v3_v3(float r[3], const float a[3])
r[2]= -a[2];
}
+MINLINE void negate_v4(float r[4])
+{
+ r[0]= -r[0];
+ r[1]= -r[1];
+ r[2]= -r[2];
+ r[3]= -r[3];
+}
+
MINLINE float dot_v2v2(const float a[2], const float b[2])
{
return a[0]*b[0] + a[1]*b[1];
@@ -419,11 +427,16 @@ MINLINE void normal_float_to_short_v3(short *out, const float *in)
/********************************* Comparison ********************************/
-MINLINE int is_zero_v3(const float *v)
+MINLINE int is_zero_v3(const float v[3])
{
return (v[0] == 0 && v[1] == 0 && v[2] == 0);
}
+MINLINE int is_zero_v4(const float v[4])
+{
+ return (v[0] == 0 && v[1] == 0 && v[2] == 0 && v[3] == 0);
+}
+
MINLINE int is_one_v3(const float *v)
{
return (v[0] == 1 && v[1] == 1 && v[2] == 1);
diff --git a/source/blender/blenlib/intern/pbvh.c b/source/blender/blenlib/intern/pbvh.c
index 8727fab7086..9be42f9f5fc 100644
--- a/source/blender/blenlib/intern/pbvh.c
+++ b/source/blender/blenlib/intern/pbvh.c
@@ -1475,13 +1475,6 @@ void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3], int smo
}
}
-void BLI_pbvh_grids_update(PBVH *bvh, DMGridData **grids, DMGridAdjacency *gridadj, void **gridfaces)
-{
- bvh->grids= grids;
- bvh->gridadj= gridadj;
- bvh->gridfaces= gridfaces;
-}
-
float (*BLI_pbvh_get_vertCos(PBVH *pbvh))[3]
{
int a;
@@ -1520,13 +1513,22 @@ void BLI_pbvh_apply_vertCos(PBVH *pbvh, float (*vertCos)[3])
}
if (pbvh->verts) {
+ MVert *mvert= pbvh->verts;
/* copy new verts coords */
- for (a= 0; a < pbvh->totvert; ++a) {
- copy_v3_v3(pbvh->verts[a].co, vertCos[a]);
+ for (a= 0; a < pbvh->totvert; ++a, ++mvert) {
+ copy_v3_v3(mvert->co, vertCos[a]);
+ mvert->flag |= ME_VERT_PBVH_UPDATE;
}
/* coordinates are new -- normals should also be updated */
mesh_calc_normals(pbvh->verts, pbvh->totvert, pbvh->faces, pbvh->totprim, NULL);
+
+ for (a= 0; a < pbvh->totnode; ++a)
+ BLI_pbvh_node_mark_update(&pbvh->nodes[a]);
+
+ BLI_pbvh_update(pbvh, PBVH_UpdateBB, NULL);
+ BLI_pbvh_update(pbvh, PBVH_UpdateOriginalBB, NULL);
+
}
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index f8f36fc1703..cc3225c0742 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -5896,6 +5896,23 @@ static int map_223_keybd_code_to_224_keybd_code(int code)
}
}
+static void do_version_bone_head_tail_237(Bone *bone)
+{
+ Bone *child;
+ float vec[3];
+
+ /* head */
+ copy_v3_v3(bone->arm_head, bone->arm_mat[3]);
+
+ /* tail is in current local coord system */
+ copy_v3_v3(vec, bone->arm_mat[1]);
+ mul_v3_fl(vec, bone->length);
+ add_v3_v3v3(bone->arm_tail, bone->arm_head, vec);
+
+ for(child= bone->childbase.first; child; child= child->next)
+ do_version_bone_head_tail_237(child);
+}
+
static void bone_version_238(ListBase *lb)
{
Bone *bone;
@@ -6805,6 +6822,19 @@ static void do_versions_seq_unique_name_all_strips(
}
}
+
+static void do_version_bone_roll_256(Bone *bone)
+{
+ Bone *child;
+ float submat[3][3];
+
+ copy_m3_m4(submat, bone->arm_mat);
+ mat3_to_vec_roll(submat, 0, &bone->arm_roll);
+
+ for(child = bone->childbase.first; child; child = child->next)
+ do_version_bone_roll_256(child);
+}
+
static void do_versions(FileData *fd, Library *lib, Main *main)
{
/* WATCH IT!!!: pointers from libdata have not been converted */
@@ -8114,10 +8144,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
bArmature *arm;
bConstraint *con;
Object *ob;
+ Bone *bone;
// armature recode checks
for(arm= main->armature.first; arm; arm= arm->id.next) {
where_is_armature(arm);
+
+ for(bone= arm->bonebase.first; bone; bone= bone->next)
+ do_version_bone_head_tail_237(bone);
}
for(ob= main->object.first; ob; ob= ob->id.next) {
if(ob->parent) {
@@ -11399,13 +11433,13 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
}
-
- /* put compatibility code here until next subversion bump */
- {
- /* Fix for sample line scope initializing with no height */
+ if (main->versionfile < 256) {
bScreen *sc;
ScrArea *sa;
+ Key *key;
+
+ /* Fix for sample line scope initializing with no height */
for(sc= main->screen.first; sc; sc= sc->id.next) {
sa= sc->areabase.first;
while(sa) {
@@ -11420,10 +11454,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
sa= sa->next;
}
}
- }
-
- {
- Key *key;
/* old files could have been saved with slidermin = slidermax = 0.0, but the UI in
* 2.4x would never reveal this to users as a dummy value always ended up getting used
@@ -11438,6 +11468,43 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
}
+
+ if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 1)) {
+ /* fix for bones that didn't have arm_roll before */
+ bArmature* arm;
+ Bone* bone;
+ Object *ob;
+
+ for (arm = main->armature.first; arm; arm = arm->id.next)
+ for (bone = arm->bonebase.first; bone; bone = bone->next)
+ do_version_bone_roll_256(bone);
+
+ /* fix for objects which have zero dquat's
+ * since this is multiplied with the quat rather then added */
+ for(ob= main->object.first; ob; ob= ob->id.next) {
+ if(is_zero_v4(ob->dquat)) {
+ unit_qt(ob->dquat);
+ }
+ if(is_zero_v3(ob->drotAxis) && ob->drotAngle == 0.0f) {
+ unit_axis_angle(ob->drotAxis, &ob->drotAngle);
+ }
+ }
+ }
+
+ /* put compatibility code here until next subversion bump */
+
+ {
+ bScreen *sc;
+
+ /* redraws flag in SpaceTime has been moved to Screen level */
+ for (sc = main->screen.first; sc; sc= sc->id.next) {
+ if (sc->redraws_flag == 0) {
+ /* just initialise to default? */
+ // XXX: we could also have iterated through areas, and taken them from the first timeline available...
+ sc->redraws_flag = TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN;
+ }
+ }
+ }
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in editors/interface/resources.c! */
diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h
index 114c2839d49..029a74f15b5 100644
--- a/source/blender/collada/DocumentImporter.h
+++ b/source/blender/collada/DocumentImporter.h
@@ -50,7 +50,7 @@ struct bContext;
class DocumentImporter : COLLADAFW::IWriter
{
public:
- //! Enumeration to keep denote the stage of import
+ //! Enumeration to denote the stage of import
enum ImportStage {
General, //!< First pass to collect all data except controller
Controller, //!< Second pass to collect controller data
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 65444f20c31..a4de5923715 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -1230,7 +1230,7 @@ void ANIM_OT_channels_visibility_set (wmOperatorType *ot)
/* api callbacks */
ot->exec= animchannels_visibility_set_exec;
- ot->poll= ED_operator_ipo_active;
+ ot->poll= ED_operator_graphedit_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -1303,7 +1303,7 @@ void ANIM_OT_channels_visibility_toggle (wmOperatorType *ot)
/* api callbacks */
ot->exec= animchannels_visibility_toggle_exec;
- ot->poll= ED_operator_ipo_active;
+ ot->poll= ED_operator_graphedit_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 04f81dd62f2..c63b2ea8a20 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -814,7 +814,7 @@ bAnimListElem *make_new_animlistelem (void *data, short datatype, void *owner, s
/* ----------------------------------------- */
/* NOTE: when this function returns true, the F-Curve is to be skipped */
-static int skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode)
+static int skip_fcurve_selected_data (bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode)
{
if (GS(owner_id->name) == ID_OB) {
Object *ob= (Object *)owner_id;
@@ -2597,7 +2597,7 @@ static short animdata_filter_dopesheet_summary (bAnimContext *ac, ListBase *anim
/* dopesheet summary
* - only for drawing and/or selecting keyframes in channels, but not for real editing
- * - only useful for DopeSheet Editor, where the summary is useful
+ * - only useful for DopeSheet/Action/etc. editors where it is actually useful
*/
// TODO: we should really check if some other prohibited filters are also active, but that can be for later
if ((filter_mode & ANIMFILTER_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) {
@@ -2698,9 +2698,12 @@ int ANIM_animdata_filter (bAnimContext *ac, ListBase *anim_data, int filter_mode
switch (datatype) {
case ANIMCONT_ACTION: /* 'Action Editor' */
{
+ SpaceAction *saction = (SpaceAction *)ac->sa->spacedata.first;
+ bDopeSheet *ads = (saction)? &saction->ads : NULL;
+
/* the check for the DopeSheet summary is included here since the summary works here too */
if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items))
- items += animdata_filter_action(ac, anim_data, NULL, data, filter_mode, NULL, ANIMTYPE_NONE, (ID *)obact);
+ items += animdata_filter_action(ac, anim_data, ads, data, filter_mode, NULL, ANIMTYPE_NONE, (ID *)obact);
}
break;
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index e1a3d8d2fa0..58dc5008959 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -403,6 +403,19 @@ static int ed_markers_poll_selected_markers(bContext *C)
/* check if some marker is selected */
return ED_markers_get_first_selected(markers) != NULL;
}
+
+/* special poll() which checks if there are any markers at all first */
+static int ed_markers_poll_markers_exist(bContext *C)
+{
+ ListBase *markers = ED_context_get_markers(C);
+
+ /* first things first: markers can only exist in timeline views */
+ if (ED_operator_animview_active(C) == 0)
+ return 0;
+
+ /* list of markers must exist, as well as some markers in it! */
+ return (markers && markers->first);
+}
/* ------------------------ */
@@ -1011,7 +1024,7 @@ static void MARKER_OT_select(wmOperatorType *ot)
/* api callbacks */
ot->invoke= ed_marker_select_invoke_wrapper;
- ot->poll= ED_operator_animview_active;
+ ot->poll= ed_markers_poll_markers_exist;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -1098,7 +1111,7 @@ static void MARKER_OT_select_border(wmOperatorType *ot)
ot->invoke= ed_marker_select_border_invoke_wrapper;
ot->modal= WM_border_select_modal;
- ot->poll= ED_operator_animview_active;
+ ot->poll= ed_markers_poll_markers_exist;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -1152,7 +1165,7 @@ static void MARKER_OT_select_all(wmOperatorType *ot)
/* api callbacks */
ot->exec= ed_marker_select_all_exec;
ot->invoke = ed_markers_opwrap_invoke;
- ot->poll= ED_operator_animview_active;
+ ot->poll= ed_markers_poll_markers_exist;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -1219,12 +1232,12 @@ static int ed_marker_rename_exec(bContext *C, wmOperator *op)
{
TimeMarker *marker= ED_markers_get_first_selected(ED_context_get_markers(C));
- if(marker) {
+ if (marker) {
RNA_string_get(op->ptr, "name", marker->name);
-
+
WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
-
+
return OPERATOR_FINISHED;
}
else {
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 543153464ea..dd7020cecab 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -503,11 +503,18 @@ void draw_keyframe_shape (float x, float y, float xscale, float hsize, short sel
case BEZT_KEYTYPE_EXTREME: /* redish frames for now */
{
- if (sel) glColor4f(95.0f, 0.5f, 0.5f, alpha);
+ if (sel) glColor4f(0.95f, 0.5f, 0.5f, alpha);
else glColor4f(0.91f, 0.70f, 0.80f, alpha);
}
break;
+ case BEZT_KEYTYPE_JITTER: /* greenish frames for now? */
+ {
+ if (sel) glColor4f(0.38f, 0.75f, 0.26f, alpha);
+ else glColor4f(0.58f, 0.90f, 0.46f, alpha);
+ }
+ break;
+
case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames for now */
default:
{
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index ca056b61efa..e92f903eb0d 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -1014,6 +1014,13 @@ static short set_keytype_extreme(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
return 0;
}
+static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
+{
+ if (bezt->f2 & SELECT)
+ BEZKEYTYPE(bezt)= BEZT_KEYTYPE_JITTER;
+ return 0;
+}
+
/* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */
KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
{
@@ -1024,6 +1031,9 @@ KeyframeEditFunc ANIM_editkeyframes_keytype(short code)
case BEZT_KEYTYPE_EXTREME: /* extreme keyframe */
return set_keytype_extreme;
+ case BEZT_KEYTYPE_JITTER: /* jitter keyframe */
+ return set_keytype_jitter;
+
case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */
default:
return set_keytype_keyframe;
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index b779250995e..d535481d154 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -88,15 +88,15 @@ short ANIM_get_keyframing_flags (Scene *scene, short incl_mode)
/* standard flags */
{
/* visual keying */
- if (IS_AUTOKEY_FLAG(AUTOMATKEY))
+ if (IS_AUTOKEY_FLAG(scene, AUTOMATKEY))
flag |= INSERTKEY_MATRIX;
/* only needed */
- if (IS_AUTOKEY_FLAG(INSERTNEEDED))
+ if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED))
flag |= INSERTKEY_NEEDED;
/* default F-Curve color mode - RGB from XYZ indices */
- if (IS_AUTOKEY_FLAG(XYZ2RGB))
+ if (IS_AUTOKEY_FLAG(scene, XYZ2RGB))
flag |= INSERTKEY_XYZ2RGB;
}
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index 24bd5b3ec5e..2df7d21e907 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -308,7 +308,7 @@ static int add_keyingset_button_exec (bContext *C, wmOperator *op)
keyingflag |= ANIM_get_keyframing_flags(scene, 0);
- if (IS_AUTOKEY_FLAG(XYZ2RGB))
+ if (IS_AUTOKEY_FLAG(scene, XYZ2RGB))
keyingflag |= INSERTKEY_XYZ2RGB;
/* call the API func, and set the active keyingset index */
@@ -680,9 +680,9 @@ KeyingSet *ANIM_get_keyingset_for_autokeying(Scene *scene, const char *tranformK
* - use the active KeyingSet if defined (and user wants to use it for all autokeying),
* or otherwise key transforms only
*/
- if (IS_AUTOKEY_FLAG(ONLYKEYINGSET) && (scene->active_keyingset))
+ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (scene->active_keyingset))
return ANIM_scene_get_active_keyingset(scene);
- else if (IS_AUTOKEY_FLAG(INSERTAVAIL))
+ else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL))
return ANIM_builtin_keyingset_get_named(NULL, "Available");
else
return ANIM_builtin_keyingset_get_named(NULL, tranformKSName);
diff --git a/source/blender/editors/armature/editarmature.c b/source/blender/editors/armature/editarmature.c
index 3a7e10698cf..4fc5064cef0 100644
--- a/source/blender/editors/armature/editarmature.c
+++ b/source/blender/editors/armature/editarmature.c
@@ -246,11 +246,6 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
EditBone *eBoneAct= NULL;
EditBone *eBoneTest= NULL;
Bone *curBone;
- float delta[3];
- float premat[3][3];
- float postmat[3][3];
- float imat[3][3];
- float difmat[3][3];
for (curBone=bones->first; curBone; curBone=curBone->next) {
eBone= MEM_callocN(sizeof(EditBone), "make_editbone");
@@ -291,20 +286,8 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone
}
copy_v3_v3(eBone->head, curBone->arm_head);
- copy_v3_v3(eBone->tail, curBone->arm_tail);
-
- eBone->roll= 0.0f;
-
- /* roll fixing */
- sub_v3_v3v3(delta, eBone->tail, eBone->head);
- vec_roll_to_mat3(delta, 0.0f, postmat);
-
- copy_m3_m4(premat, curBone->arm_mat);
-
- invert_m3_m3(imat, postmat);
- mul_m3_m3m3(difmat, imat, premat);
-
- eBone->roll = (float)atan2(difmat[2][0], difmat[2][2]);
+ copy_v3_v3(eBone->tail, curBone->arm_tail);
+ eBone->roll = curBone->arm_roll;
/* rest of stuff copy */
eBone->length= curBone->length;
@@ -420,8 +403,10 @@ void ED_armature_from_edit(Object *obedit)
eBone->temp= newBone; /* Associate the real Bones with the EditBones */
BLI_strncpy(newBone->name, eBone->name, sizeof(newBone->name));
- memcpy(newBone->head, eBone->head, sizeof(newBone->head));
- memcpy(newBone->tail, eBone->tail, sizeof(newBone->tail));
+ copy_v3_v3(newBone->arm_head, eBone->head);
+ copy_v3_v3(newBone->arm_tail, eBone->tail);
+ newBone->arm_roll = eBone->roll;
+
newBone->flag= eBone->flag;
if (eBone == arm->act_edbone) {
@@ -456,7 +441,6 @@ void ED_armature_from_edit(Object *obedit)
BLI_addtail(&newBone->parent->childbase, newBone);
{
- float M_boneRest[3][3];
float M_parentRest[3][3];
float iM_parentRest[3][3];
float delta[3];
@@ -465,10 +449,6 @@ void ED_armature_from_edit(Object *obedit)
sub_v3_v3v3(delta, eBone->parent->tail, eBone->parent->head);
vec_roll_to_mat3(delta, eBone->parent->roll, M_parentRest);
- /* Get this bone's matrix (rotation only) */
- sub_v3_v3v3(delta, eBone->tail, eBone->head);
- vec_roll_to_mat3(delta, eBone->roll, M_boneRest);
-
/* Invert the parent matrix */
invert_m3_m3(iM_parentRest, M_parentRest);
@@ -481,8 +461,11 @@ void ED_armature_from_edit(Object *obedit)
}
}
/* ...otherwise add this bone to the armature's bonebase */
- else
+ else {
+ copy_v3_v3(newBone->head, eBone->head);
+ copy_v3_v3(newBone->tail, eBone->tail);
BLI_addtail(&arm->bonebase, newBone);
+ }
}
/* Make a pass through the new armature to fix rolling */
@@ -688,10 +671,11 @@ static int apply_armature_pose2bones_exec (bContext *C, wmOperator *op)
}
/* clear transform values for pchan */
- pchan->loc[0]= pchan->loc[1]= pchan->loc[2]= 0.0f;
- pchan->eul[0]= pchan->eul[1]= pchan->eul[2]= 0.0f;
- pchan->quat[1]= pchan->quat[2]= pchan->quat[3]= 0.0f;
- pchan->quat[0]= pchan->size[0]= pchan->size[1]= pchan->size[2]= 1.0f;
+ zero_v3(pchan->loc);
+ zero_v3(pchan->eul);
+ unit_qt(pchan->quat);
+ unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
+ pchan->size[0]= pchan->size[1]= pchan->size[2]= 1.0f;
/* set anim lock */
curbone->flag |= BONE_UNKEYED;
@@ -5049,11 +5033,10 @@ static void pchan_clear_rot(bPoseChannel *pchan)
}
else if (pchan->rotmode == ROT_MODE_AXISANGLE) {
/* by default, make rotation of 0 radians around y-axis (roll) */
- pchan->rotAxis[0]=pchan->rotAxis[2]=pchan->rotAngle= 0.0f;
- pchan->rotAxis[1]= 1.0f;
+ unit_axis_angle(pchan->rotAxis, &pchan->rotAngle);
}
else {
- pchan->eul[0]= pchan->eul[1]= pchan->eul[2]= 0.0f;
+ zero_v3(pchan->eul);
}
}
}
diff --git a/source/blender/editors/armature/poseobject.c b/source/blender/editors/armature/poseobject.c
index 6c1adcb2ccb..6115f322d08 100644
--- a/source/blender/editors/armature/poseobject.c
+++ b/source/blender/editors/armature/poseobject.c
@@ -932,6 +932,7 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
Object *ob= ED_object_pose_armature(CTX_data_active_object(C));
bPoseChannel *chan, *pchan;
int flip= RNA_boolean_get(op->ptr, "flipped");
+ int selOnly= RNA_boolean_get(op->ptr, "selected_mask");
/* sanity checks */
if ELEM(NULL, ob, ob->pose)
@@ -945,17 +946,28 @@ static int pose_paste_exec (bContext *C, wmOperator *op)
/* Safely merge all of the channels in the buffer pose into any existing pose */
for (chan= g_posebuf->chanbase.first; chan; chan=chan->next) {
if (chan->flag & POSE_KEY) {
- /* get the name - if flipping, we must flip this first */
char name[32];
+ short paste_ok;
+
+ /* get the name - if flipping, we must flip this first */
if (flip)
flip_side_name(name, chan->name, 0); /* 0 = don't strip off number extensions */
else
BLI_strncpy(name, chan->name, sizeof(name));
- /* only copy when channel exists, poses are not meant to add random channels to anymore */
+ /* only copy when:
+ * 1) channel exists - poses are not meant to add random channels to anymore
+ * 2) if selection-masking is on, channel is selected - only selected bones get pasted on, allowing making both sides symmetrical
+ */
pchan= get_pose_channel(ob->pose, name);
- if (pchan) {
+ if (selOnly)
+ paste_ok= ((pchan) && (pchan->bone->flag & BONE_SELECTED));
+ else
+ paste_ok= ((pchan != NULL));
+
+ /* continue? */
+ if (paste_ok) {
/* only loc rot size
* - only copies transform info for the pose
*/
@@ -1098,6 +1110,7 @@ void POSE_OT_paste (wmOperatorType *ot)
/* properties */
RNA_def_boolean(ot->srna, "flipped", 0, "Flipped on X-Axis", "Paste the stored pose flipped on to current pose");
+ RNA_def_boolean(ot->srna, "selected_mask", 0, "On Selected Only", "Only paste the stored post on to selected bones in the current pose");
}
/* ********************************************** */
@@ -1892,11 +1905,8 @@ static int pose_flip_quats_exec (bContext *C, wmOperator *UNUSED(op))
/* only if bone is using quaternion rotation */
if (pchan->rotmode == ROT_MODE_QUAT) {
/* quaternions have 720 degree range */
- pchan->quat[0]= -pchan->quat[0];
- pchan->quat[1]= -pchan->quat[1];
- pchan->quat[2]= -pchan->quat[2];
- pchan->quat[3]= -pchan->quat[3];
-
+ negate_v4(pchan->quat);
+
/* tagging */
if (autokeyframe_cfra_can_key(scene, &ob->id)) {
ListBase dsources = {NULL, NULL};
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 3eaf53b4bcb..0949e3d6214 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -61,6 +61,7 @@
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_animsys.h"
+#include "BKE_action.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -84,7 +85,7 @@ typedef struct {
ListBase nubase;
void *lastsel;
GHash *undoIndex;
- ListBase fcurves;
+ ListBase fcurves, drivers;
} UndoCurve;
/* Definitions needed for shape keys */
@@ -1007,10 +1008,10 @@ static int curve_is_animated(Object *ob)
Curve *cu= (Curve*)ob->data;
AnimData *ad= BKE_animdata_from_id(&cu->id);
- return ad && ad->action;
+ return ad && (ad->action || ad->drivers.first);
}
-static void fcurve_path_rename(char *orig_rna_path, char *rna_path, ListBase *orig_curves, ListBase *curves)
+static void fcurve_path_rename(AnimData *ad, char *orig_rna_path, char *rna_path, ListBase *orig_curves, ListBase *curves)
{
FCurve *fcu, *nfcu, *nextfcu;
int len= strlen(orig_rna_path);
@@ -1025,7 +1026,15 @@ static void fcurve_path_rename(char *orig_rna_path, char *rna_path, ListBase *or
nfcu->rna_path= BLI_sprintfN("%s%s", rna_path, suffix);
BLI_addtail(curves, nfcu);
- BLI_remlink(orig_curves, fcu);
+ if (fcu->grp) {
+ action_groups_remove_channel(ad->action, fcu);
+ action_groups_add_channel(ad->action, fcu->grp, nfcu);
+ }
+ else if (ad->action && &ad->action->curves == orig_curves)
+ BLI_remlink(&ad->action->curves, fcu);
+ else
+ BLI_remlink(&ad->drivers, fcu);
+
free_fcurve(fcu);
MEM_freeN(spath);
@@ -1034,8 +1043,15 @@ static void fcurve_path_rename(char *orig_rna_path, char *rna_path, ListBase *or
}
}
-/* return 0 if animation data wasn't changed, 1 otherwise */
-int ED_curve_updateAnimPaths(Object *obedit)
+static void fcurve_remove(AnimData *ad, ListBase *orig_curves, FCurve *fcu)
+{
+ if(orig_curves==&ad->drivers) BLI_remlink(&ad->drivers, fcu);
+ else action_groups_remove_channel(ad->action, fcu);
+
+ free_fcurve(fcu);
+}
+
+static void curve_rename_fcurves(Object *obedit, ListBase *orig_curves)
{
int nu_index= 0, a, pt_index;
Curve *cu= (Curve*)obedit->data;
@@ -1043,15 +1059,10 @@ int ED_curve_updateAnimPaths(Object *obedit)
Nurb *nu= editnurb->nurbs.first;
CVKeyIndex *keyIndex;
char rna_path[64], orig_rna_path[64];
- ListBase orig_curves= {0, 0};
- ListBase curves= {0, 0};
AnimData *ad= BKE_animdata_from_id(&cu->id);
+ ListBase curves= {0, 0};
FCurve *fcu, *next;
- if(!curve_is_animated(obedit)) return 0;
-
- copy_fcurves(&orig_curves, &ad->action->curves);
-
while(nu) {
if(nu->bezt) {
BezTriple *bezt= nu->bezt;
@@ -1068,14 +1079,14 @@ int ED_curve_updateAnimPaths(Object *obedit)
char handle_path[64], orig_handle_path[64];
sprintf(orig_handle_path, "%s.handle_left", orig_rna_path);
sprintf(handle_path, "%s.handle_right", rna_path);
- fcurve_path_rename(orig_handle_path, handle_path, &orig_curves, &curves);
+ fcurve_path_rename(ad, orig_handle_path, handle_path, orig_curves, &curves);
sprintf(orig_handle_path, "%s.handle_right", orig_rna_path);
sprintf(handle_path, "%s.handle_left", rna_path);
- fcurve_path_rename(orig_handle_path, handle_path, &orig_curves, &curves);
+ fcurve_path_rename(ad, orig_handle_path, handle_path, orig_curves, &curves);
}
- fcurve_path_rename(orig_rna_path, rna_path, &orig_curves, &curves);
+ fcurve_path_rename(ad, orig_rna_path, rna_path, orig_curves, &curves);
keyIndex->nu_index= nu_index;
keyIndex->pt_index= pt_index;
@@ -1094,7 +1105,7 @@ int ED_curve_updateAnimPaths(Object *obedit)
if(keyIndex) {
sprintf(rna_path, "splines[%d].points[%d]", nu_index, pt_index);
sprintf(orig_rna_path, "splines[%d].points[%d]", keyIndex->nu_index, keyIndex->pt_index);
- fcurve_path_rename(orig_rna_path, rna_path, &orig_curves, &curves);
+ fcurve_path_rename(ad, orig_rna_path, rna_path, orig_curves, &curves);
keyIndex->nu_index= nu_index;
keyIndex->pt_index= pt_index;
@@ -1108,27 +1119,64 @@ int ED_curve_updateAnimPaths(Object *obedit)
nu_index++;
}
+ /* remove pathes for removed control points
+ need this to make further step with copying non-cv related curves copying
+ not touching cv's f-cruves */
+ fcu= orig_curves->first;
+ for(fcu= orig_curves->first; fcu; fcu= next) {
+ next= fcu->next;
+
+ if(!strncmp(fcu->rna_path, "splines", 7)) {
+ char *ch= strchr(fcu->rna_path, '.');
+
+ if (ch && (!strncmp(ch, ".bezier_points", 14) || !strncmp(ch, ".points", 8)))
+ fcurve_remove(ad, orig_curves, fcu);
+ }
+ }
+
nu_index= 0;
+ nu= editnurb->nurbs.first;
while(nu) {
+ keyIndex= NULL;
+ if(nu->pntsu) {
+ if(nu->bezt) keyIndex= getCVKeyIndex(editnurb, &nu->bezt[0]);
+ else keyIndex= getCVKeyIndex(editnurb, &nu->bp[0]);
+ }
+
if(keyIndex) {
sprintf(rna_path, "splines[%d]", nu_index);
sprintf(orig_rna_path, "splines[%d]", keyIndex->nu_index);
- fcurve_path_rename(orig_rna_path, rna_path, &ad->action->curves, &curves);
+ fcurve_path_rename(ad, orig_rna_path, rna_path, orig_curves, &curves);
}
+
nu_index++;
+ nu= nu->next;
}
/* the remainders in orig_curves can be copied back (like follow path) */
/* (if it's not path to spline) */
- for(fcu= orig_curves.first; fcu; fcu= next) {
+ for(fcu= orig_curves->first; fcu; fcu= next) {
next= fcu->next;
- if(!strncmp(fcu->rna_path, "splines", 7)) free_fcurve(fcu);
+ if(!strncmp(fcu->rna_path, "splines", 7)) fcurve_remove(ad, orig_curves, fcu);
else BLI_addtail(&curves, fcu);
}
-
- free_fcurves(&ad->action->curves);
- ad->action->curves= curves;
+
+ *orig_curves= curves;
+}
+
+/* return 0 if animation data wasn't changed, 1 otherwise */
+int ED_curve_updateAnimPaths(Object *obedit)
+{
+ Curve *cu= (Curve*)obedit->data;
+ AnimData *ad= BKE_animdata_from_id(&cu->id);
+
+ if(!curve_is_animated(obedit)) return 0;
+
+ if(ad->action)
+ curve_rename_fcurves(obedit, &ad->action->curves);
+
+ curve_rename_fcurves(obedit, &ad->drivers);
return 1;
}
@@ -1176,7 +1224,6 @@ void make_editNurb(Object *obedit)
EditNurb *editnurb= cu->editnurb;
Nurb *nu, *newnu, *nu_act= NULL;
KeyBlock *actkey;
- int is_anim;
if(obedit==NULL) return;
@@ -1184,7 +1231,6 @@ void make_editNurb(Object *obedit)
if (ELEM(obedit->type, OB_CURVE, OB_SURF)) {
actkey= ob_get_keyblock(obedit);
- is_anim= curve_is_animated(obedit);
if(actkey) {
// XXX strcpy(G.editModeTitleExtra, "(Key) ");
@@ -1192,10 +1238,6 @@ void make_editNurb(Object *obedit)
key_to_curve(actkey, cu, &cu->nurb);
}
- if (is_anim) {
- undo_editmode_clear();
- }
-
if(editnurb) {
freeNurblist(&editnurb->nurbs);
free_editNurb_keyIndex(editnurb);
@@ -1221,13 +1263,12 @@ void make_editNurb(Object *obedit)
nu= nu->next;
}
- if(actkey) {
+ if(actkey)
editnurb->shapenr= obedit->shapenr;
- init_editNurb_keyIndex(editnurb, &cu->nurb);
- }
- if(is_anim)
- init_editNurb_keyIndex(editnurb, &cu->nurb);
+ /* animation could be added in editmode even if teher was no animdata i
+ object mode hence we always need CVs index be created */
+ init_editNurb_keyIndex(editnurb, &cu->nurb);
}
}
@@ -6866,9 +6907,14 @@ static void undoCurve_to_editCurve(void *ucu, void *obe)
editnurb->keyindex= dupli_keyIndexHash(undoCurve->undoIndex);
}
- if(ad && ad->action) {
- free_fcurves(&ad->action->curves);
- copy_fcurves(&ad->action->curves, &undoCurve->fcurves);
+ if(ad) {
+ if(ad->action) {
+ free_fcurves(&ad->action->curves);
+ copy_fcurves(&ad->action->curves, &undoCurve->fcurves);
+ }
+
+ free_fcurves(&ad->drivers);
+ copy_fcurves(&ad->drivers, &undoCurve->drivers);
}
/* copy */
@@ -6909,8 +6955,12 @@ static void *editCurve_to_undoCurve(void *obe)
tmpEditnurb.keyindex= undoCurve->undoIndex;
}
- if(ad && ad->action)
- copy_fcurves(&undoCurve->fcurves, &ad->action->curves);
+ if(ad) {
+ if(ad->action)
+ copy_fcurves(&undoCurve->fcurves, &ad->action->curves);
+
+ copy_fcurves(&undoCurve->drivers, &ad->drivers);
+ }
/* copy */
for(nu= nubase->first; nu; nu= nu->next) {
@@ -6942,6 +6992,7 @@ static void free_undoCurve(void *ucv)
BLI_ghash_free(undoCurve->undoIndex, NULL, (GHashValFreeFP)free_cvKeyIndex);
free_fcurves(&undoCurve->fcurves);
+ free_fcurves(&undoCurve->drivers);
MEM_freeN(undoCurve);
}
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index baa6f7d6a25..0ebbe223c3f 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -547,18 +547,25 @@ static void gp_stroke_newfrombuffer (tGPsdata *p)
/* get an array of depths, far depths are blended */
if (gpencil_project_check(p)) {
- short mval[2];
+ short mval[2], mval_prev[2]= {0};
int interp_depth = 0;
int found_depth = 0;
depth_arr= MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points");
-
+
for (i=0, ptc=gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) {
mval[0]= ptc->x; mval[1]= ptc->y;
- if (view_autodist_depth(p->ar, mval, depth_margin, depth_arr+i) == 0)
+
+ if ((view_autodist_depth(p->ar, mval, depth_margin, depth_arr+i) == 0) &&
+ (i && (view_autodist_depth_segment(p->ar, mval, mval_prev, depth_margin + 1, depth_arr+i) == 0))
+ ) {
interp_depth= TRUE;
- else
+ }
+ else {
found_depth= TRUE;
+ }
+
+ VECCOPY2D(mval_prev, mval);
}
if (found_depth == FALSE) {
diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h
index 72e87e2c9bc..3fea3fa03a5 100644
--- a/source/blender/editors/include/ED_keyframing.h
+++ b/source/blender/editors/include/ED_keyframing.h
@@ -259,8 +259,12 @@ short ANIM_paste_driver(struct ReportList *reports, struct ID *id, const char rn
#define IS_AUTOKEY_ON(scene) ((scene) ? (scene->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON))
/* check the mode for auto-keyframing (per scene takes presidence) */
#define IS_AUTOKEY_MODE(scene, mode) ((scene) ? (scene->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : (U.autokey_mode == AUTOKEY_MODE_##mode))
- /* check if a flag is set for auto-keyframing (as userprefs only!) */
-#define IS_AUTOKEY_FLAG(flag) (U.autokey_flag & AUTOKEY_FLAG_##flag)
+ /* check if a flag is set for auto-keyframing (per scene takes presidence) */
+#define IS_AUTOKEY_FLAG(scene, flag) \
+ ((scene)? \
+ ((scene->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || (U.autokey_flag & AUTOKEY_FLAG_##flag)) \
+ : \
+ (U.autokey_flag & AUTOKEY_FLAG_##flag))
/* auto-keyframing feature - checks for whether anything should be done for the current frame */
int autokeyframe_cfra_can_key(struct Scene *scene, struct ID *id);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index a27a792eeee..1ceb2216938 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -137,7 +137,7 @@ int ED_operator_file_active(struct bContext *C);
int ED_operator_action_active(struct bContext *C);
int ED_operator_buttons_active(struct bContext *C);
int ED_operator_node_active(struct bContext *C);
-int ED_operator_ipo_active(struct bContext *C);
+int ED_operator_graphedit_active(struct bContext *C);
int ED_operator_sequencer_active(struct bContext *C);
int ED_operator_image_active(struct bContext *C);
int ED_operator_nla_active(struct bContext *C);
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index f46ab37823b..cac6a1a2d13 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -40,6 +40,7 @@ void ED_operatortypes_sculpt(void);
void sculpt_get_redraw_planes(float planes[4][4], struct ARegion *ar,
struct RegionView3D *rv3d, struct Object *ob);
void ED_sculpt_force_update(struct bContext *C);
+void ED_sculpt_modifiers_changed(struct Object *ob);
/* paint_ops.c */
void ED_operatortypes_paint(void);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index d6fc0797449..4afe2ff10a2 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -136,8 +136,9 @@ int view_autodist(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, s
/* only draw so view_autodist_simple can be called many times after */
int view_autodist_init(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, int mode);
-int view_autodist_simple(struct ARegion *ar, short *mval, float mouse_worldloc[3], int margin, float *force_depth);
-int view_autodist_depth(struct ARegion *ar, short *mval, int margin, float *depth);
+int view_autodist_simple(struct ARegion *ar, short mval[2], float mouse_worldloc[3], int margin, float *force_depth);
+int view_autodist_depth(struct ARegion *ar, short mval[2], int margin, float *depth);
+int view_autodist_depth_segment(struct ARegion *ar, short mval_sta[2], short mval_end[2], int margin, float *depth);
/* select */
#define MAXPICKBUF 10000
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 3a29419074b..52e9a395c4e 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -1511,6 +1511,11 @@ void init_userdef_do_versions(void)
}
}
+ if (bmain->versionfile < 257) {
+ /* clear "AUTOKEY_FLAG_ONLYKEYINGSET" flag from userprefs, so that it doesn't linger around from old configs like a ghost */
+ U.autokey_flag &= ~AUTOKEY_FLAG_ONLYKEYINGSET;
+ }
+
/* GL Texture Garbage Collection (variable abused above!) */
if (U.textimeout == 0) {
U.texcollectrate = 60;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 3c74c38dfb6..245905418ec 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -991,12 +991,12 @@ void UI_view2d_view_ortho(View2D *v2d)
/* XXX ton: this flag set by outliner, for icons */
if(v2d->flag & V2D_PIXELOFS_X) {
- curmasked.xmin= floor(curmasked.xmin) + 0.001f;
- curmasked.xmax= floor(curmasked.xmax) + 0.001f;
+ curmasked.xmin= floor(curmasked.xmin) - 0.001f;
+ curmasked.xmax= floor(curmasked.xmax) - 0.001f;
}
if(v2d->flag & V2D_PIXELOFS_Y) {
- curmasked.ymin= floor(curmasked.ymin) + 0.001f;
- curmasked.ymax= floor(curmasked.ymax) + 0.001f;
+ curmasked.ymin= floor(curmasked.ymin) - 0.001f;
+ curmasked.ymax= floor(curmasked.ymax) - 0.001f;
}
/* set matrix on all appropriate axes */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 3e359101f3a..9e6f8f7f078 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -7150,7 +7150,7 @@ static int sort_faces_exec(bContext *C, wmOperator *op)
if (!v3d) return OPERATOR_CANCELLED;
/* This operator work in Object Mode, not in edit mode.
- * After talk with Cambell we agree that there is no point to port this to EditMesh right now.
+ * After talk with Campbell we agree that there is no point to port this to EditMesh right now.
* so for now, we just exit_editmode and enter_editmode at the end of this function.
*/
ED_object_exit_editmode(C, EM_FREEDATA);
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 344c2c13861..f695f112bc0 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -531,11 +531,20 @@ static bConstraint *edit_constraint_property_get(wmOperator *op, Object *ob, int
bPoseChannel *pchan= get_active_posechannel(ob);
if (pchan)
list = &pchan->constraints;
- else
+ else {
+ //if (G.f & G_DEBUG)
+ //printf("edit_constraint_property_get: No active bone for object '%s'\n", (ob)? ob->id.name+2 : "<None>");
return NULL;
+ }
+ }
+ else {
+ //if (G.f & G_DEBUG)
+ //printf("edit_constraint_property_get: defaulting to getting list in the standard way\n");
+ list = get_active_constraints(ob);
}
con = constraints_findByName(list, constraint_name);
+ printf("constraint found = %p, %s\n", con, (con)?con->name:"<Not found>");
if (con && (type != 0) && (con->type != type))
con = NULL;
@@ -645,8 +654,11 @@ static int childof_set_inverse_exec (bContext *C, wmOperator *op)
bPoseChannel *pchan= NULL;
/* despite 3 layers of checks, we may still not be able to find a constraint */
- if (data == NULL)
+ if (data == NULL) {
+ printf("DEBUG: Child-Of Set Inverse - object = '%s'\n", (ob)? ob->id.name+2 : "<None>");
+ BKE_report(op->reports, RPT_ERROR, "Couldn't find constraint data for Child-Of Set Inverse");
return OPERATOR_CANCELLED;
+ }
/* try to find a pose channel */
// TODO: get from context instead?
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 94955e3c815..0acdc8b61fe 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -1241,9 +1241,9 @@ void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
else if(event==2) { /* rot */
VECCOPY(base->object->rot, ob->rot);
VECCOPY(base->object->drot, ob->drot);
- /* Quats arnt used yet */
- /*VECCOPY(base->object->quat, ob->quat);
- VECCOPY(base->object->dquat, ob->dquat);*/
+
+ QUATCOPY(base->object->quat, ob->quat);
+ QUATCOPY(base->object->dquat, ob->dquat);
}
else if(event==3) { /* size */
VECCOPY(base->object->size, ob->size);
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 1af022c3c6e..024e3e8a020 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -165,24 +165,16 @@ static void object_clear_rot(Object *ob)
} // Duplicated in source/blender/editors/armature/editarmature.c
else {
if (ob->rotmode == ROT_MODE_QUAT) {
- ob->quat[1]=ob->quat[2]=ob->quat[3]= 0.0f;
- ob->quat[0]= 1.0f;
-
- ob->dquat[1]=ob->dquat[2]=ob->dquat[3]= 0.0f;
- ob->dquat[0]= 1.0f;
+ unit_qt(ob->quat);
+ unit_qt(ob->dquat);
}
else if (ob->rotmode == ROT_MODE_AXISANGLE) {
- /* by default, make rotation of 0 radians around y-axis (roll) */
- ob->rotAxis[0]=ob->rotAxis[2]=ob->rotAngle= 0.0f;
- ob->rotAxis[1]= 1.0f;
-
- ob->drotAxis[0]=ob->drotAxis[2]=ob->drotAngle= 0.0f;
- ob->drotAxis[1]= 1.0f;
+ unit_axis_angle(ob->rotAxis, &ob->rotAngle);
+ unit_axis_angle(ob->drotAxis, &ob->drotAngle);
}
else {
- ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0f;
-
- ob->drot[0]= ob->drot[1]= ob->drot[2]= 0.0f;
+ zero_v3(ob->rot);
+ zero_v3(ob->drot);
}
}
}
@@ -532,16 +524,13 @@ static int apply_objects_internal(bContext *C, ReportList *reports, int apply_lo
continue;
if(apply_loc)
- ob->loc[0]= ob->loc[1]= ob->loc[2]= 0.0f;
+ zero_v3(ob->loc);
if(apply_scale)
ob->size[0]= ob->size[1]= ob->size[2]= 1.0f;
if(apply_rot) {
- ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0f;
- ob->quat[1]= ob->quat[2]= ob->quat[3]= 0.0f;
- ob->rotAxis[0]= ob->rotAxis[2]= 0.0f;
- ob->rotAngle= 0.0f;
-
- ob->quat[0]= ob->rotAxis[1]= 1.0f;
+ zero_v3(ob->rot);
+ unit_qt(ob->quat);
+ unit_axis_angle(ob->rotAxis, &ob->rotAngle);
}
where_is_object(scene, ob);
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 376e70f6ea2..65ccadacf3c 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -346,7 +346,7 @@ static short testsplitpoint(ScrArea *sa, char dir, float fac)
}
}
-ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac)
+ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
{
ScrArea *newa=NULL;
ScrVert *sv1, *sv2;
@@ -400,7 +400,8 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac)
}
/* remove double vertices en edges */
- removedouble_scrverts(sc);
+ if(merge)
+ removedouble_scrverts(sc);
removedouble_scredges(sc);
removenotused_scredges(sc);
@@ -417,6 +418,7 @@ bScreen *ED_screen_add(wmWindow *win, Scene *scene, const char *name)
sc= alloc_libblock(&G.main->screen, ID_SCR, name);
sc->scene= scene;
sc->do_refresh= 1;
+ sc->redraws_flag= TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN;
sc->winid= win->winid;
sv1= screen_addvert(sc, 0, 0);
@@ -1611,7 +1613,7 @@ ScrArea *ED_screen_full_toggle(bContext *C, wmWindow *win, ScrArea *sa)
oldscreen->animtimer= NULL;
/* returns the top small area */
- newa= area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f);
+ newa= area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1);
ED_area_newspace(C, newa, SPACE_INFO);
/* use random area when we have no active one, e.g. when the
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index b20daf9a0c8..87b397382a3 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -37,7 +37,7 @@ void area_copy_data (ScrArea *sa1, ScrArea *sa2, int swap_space);
/* screen_edit.c */
ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2);
-ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac);
+ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge);
int screen_area_join(bContext *C, bScreen* scr, ScrArea *sa1, ScrArea *sa2);
int area_getorientation(ScrArea *sa, ScrArea *sb);
void select_connected_scredge(bScreen *sc, ScrEdge *edge);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index d891b025241..b6c92982560 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -222,7 +222,7 @@ int ED_operator_node_active(bContext *C)
}
// XXX rename
-int ED_operator_ipo_active(bContext *C)
+int ED_operator_graphedit_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_IPO);
}
@@ -1169,7 +1169,7 @@ static int area_split_apply(bContext *C, wmOperator *op)
fac= RNA_float_get(op->ptr, "factor");
dir= RNA_enum_get(op->ptr, "direction");
- sd->narea= area_split(sc, sd->sarea, dir, fac);
+ sd->narea= area_split(sc, sd->sarea, dir, fac, 0); /* 0 = no merge */
if(sd->narea) {
ScrVert *sv;
@@ -2695,37 +2695,18 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
sound_stop_scene(scene);
}
else {
- ScrArea *sa= CTX_wm_area(C);
- int refresh= SPACE_TIME;
+ int refresh= SPACE_TIME; /* these settings are currently only available from a menu in the TimeLine */
if (mode == 1) // XXX only play audio forwards!?
sound_play_scene(scene);
- /* timeline gets special treatment since it has it's own menu for determining redraws */
- if ((sa) && (sa->spacetype == SPACE_TIME)) {
- SpaceTime *stime= (SpaceTime *)sa->spacedata.first;
-
- ED_screen_animation_timer(C, stime->redraws, refresh, sync, mode);
-
- /* update region if TIME_REGION was set, to leftmost 3d window */
- ED_screen_animation_timer_update(screen, stime->redraws, refresh);
- }
- else {
- int redraws = TIME_REGION|TIME_ALL_3D_WIN;
-
- /* XXX - would like a better way to deal with this situation - Campbell */
- if ((!sa) || (sa->spacetype == SPACE_SEQ)) {
- redraws |= TIME_SEQ;
- }
-
- ED_screen_animation_timer(C, redraws, refresh, sync, mode);
+ ED_screen_animation_timer(C, screen->redraws_flag, refresh, sync, mode);
+
+ if (screen->animtimer) {
+ wmTimer *wt= screen->animtimer;
+ ScreenAnimData *sad= wt->customdata;
- if(screen->animtimer) {
- wmTimer *wt= screen->animtimer;
- ScreenAnimData *sad= wt->customdata;
-
- sad->ar= CTX_wm_region(C);
- }
+ sad->ar= CTX_wm_region(C);
}
}
@@ -2763,7 +2744,7 @@ static int screen_animation_cancel_exec(bContext *C, wmOperator *UNUSED(op))
{
bScreen *screen= CTX_wm_screen(C);
- if(screen->animtimer) {
+ if (screen->animtimer) {
ScreenAnimData *sad= screen->animtimer->customdata;
Scene *scene= CTX_data_scene(C);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index 58398bd1f5c..0fb3bc34d5b 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -58,6 +58,7 @@
#include "BKE_multires.h"
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "BKE_lattice.h" /* for armature_deform_verts */
#include "BIF_glutil.h"
@@ -91,12 +92,29 @@ void ED_sculpt_force_update(bContext *C)
multires_force_update(ob);
}
+void ED_sculpt_modifiers_changed(Object *ob)
+{
+ SculptSession *ss= ob->sculpt;
+
+ if(!ss->cache) {
+ /* we free pbvh on changes, except during sculpt since it can't deal with
+ changing PVBH node organization, we hope topology does not change in
+ the meantime .. weak */
+ if(ss->pbvh) {
+ BLI_pbvh_free(ss->pbvh);
+ ss->pbvh= NULL;
+ }
+
+ sculpt_free_deformMats(ob->sculpt);
+ }
+}
+
/* Sculpt mode handles multires differently from regular meshes, but only if
it's the last modifier on the stack and it is not on the first level */
struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
{
Mesh *me= (Mesh*)ob->data;
- ModifierData *md, *nmd;
+ ModifierData *md;
if(!CustomData_get_layer(&me->fdata, CD_MDISPS)) {
/* multires can't work without displacement layer */
@@ -107,40 +125,52 @@ struct MultiresModifierData *sculpt_multires_active(Scene *scene, Object *ob)
if(md->type == eModifierType_Multires) {
MultiresModifierData *mmd= (MultiresModifierData*)md;
- /* Check if any of the modifiers after multires are active
- * if not it can use the multires struct */
- for(nmd= md->next; nmd; nmd= nmd->next)
- if(modifier_isEnabled(scene, nmd, eModifierMode_Realtime))
- break;
+ if(!modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ continue;
- if(!nmd && mmd->sculptlvl > 0)
- return mmd;
+ if(mmd->sculptlvl > 0) return mmd;
+ else return NULL;
}
}
return NULL;
}
-/* Checks whether full update mode (slower) needs to be used to work with modifiers */
+/* Check if there are any active modifiers in stack (used for flushing updates at enter/exit sculpt mode) */
+int sculpt_has_active_modifiers(Scene *scene, Object *ob)
+{
+ ModifierData *md;
+
+ md= modifiers_getVirtualModifierList(ob);
+
+ /* exception for shape keys because we can edit those */
+ for(; md; md= md->next) {
+ if(modifier_isEnabled(scene, md, eModifierMode_Realtime))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Checks if there are any supported deformation modifiers active */
int sculpt_modifiers_active(Scene *scene, Object *ob)
{
ModifierData *md;
MultiresModifierData *mmd= sculpt_multires_active(scene, ob);
- /* check if there are any modifiers after what we are sculpting,
- for a multires modifier with a deform modifier in front, we
- do no need to recalculate the modifier stack. note that this
- needs to be in sync with ccgDM_use_grid_pbvh! */
- if(mmd)
- md= mmd->modifier.next;
- else
- md= modifiers_getVirtualModifierList(ob);
-
+ if(mmd) return 0;
+
+ md= modifiers_getVirtualModifierList(ob);
+
/* exception for shape keys because we can edit those */
for(; md; md= md->next) {
- if(modifier_isEnabled(scene, md, eModifierMode_Realtime))
- if(md->type != eModifierType_ShapeKey)
- return 1;
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+
+ if(!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
+ if(md->type==eModifierType_ShapeKey) continue;
+
+ if(mti->type==eModifierTypeType_OnlyDeform && mti->deformMatrices)
+ return 1;
}
return 0;
@@ -890,7 +920,9 @@ static void neighbor_average(SculptSession *ss, float avg[3], const unsigned ver
/* Don't modify corner vertices */
if(ncount==1) {
- copy_v3_v3(avg, ss->mvert[vert].co);
+ if(ss->deform_cos) copy_v3_v3(avg, ss->deform_cos[vert]);
+ else copy_v3_v3(avg, ss->mvert[vert].co);
+
return;
}
@@ -906,7 +938,8 @@ static void neighbor_average(SculptSession *ss, float avg[3], const unsigned ver
for(i=0; i<(f->v4?4:3); ++i) {
if(i != skip && (ncount!=2 || BLI_countlist(&ss->fmap[(&f->v1)[i]]) <= 2)) {
- add_v3_v3(avg, ss->mvert[(&f->v1)[i]].co);
+ if(ss->deform_cos) add_v3_v3(avg, ss->deform_cos[(&f->v1)[i]]);
+ else add_v3_v3(avg, ss->mvert[(&f->v1)[i]].co);
++total;
}
}
@@ -916,8 +949,10 @@ static void neighbor_average(SculptSession *ss, float avg[3], const unsigned ver
if(total>0)
mul_v3_fl(avg, 1.0f / total);
- else
- copy_v3_v3(avg, ss->mvert[vert].co);
+ else {
+ if(ss->deform_cos) copy_v3_v3(avg, ss->deform_cos[vert]);
+ else copy_v3_v3(avg, ss->mvert[vert].co);
+ }
}
static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node, float bstrength)
@@ -2198,9 +2233,8 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
ofs= key_to_vertcos(ob, kb);
/* calculate key coord offsets (from previous location) */
- for (a= 0; a < me->totvert; a++) {
+ for (a= 0; a < me->totvert; a++)
VECSUB(ofs[a], vertCos[a], ofs[a]);
- }
/* apply offsets on other keys */
currkey = me->key->block.first;
@@ -2230,17 +2264,6 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3])
vertcos_to_key(ob, kb, vertCos);
}
-/* copy the modified vertices from bvh to the active key */
-static void sculpt_update_keyblock(SculptSession *ss)
-{
- float (*vertCos)[3]= BLI_pbvh_get_vertCos(ss->pbvh);
-
- if (vertCos) {
- sculpt_vertcos_to_key(ss->ob, ss->kb, vertCos);
- MEM_freeN(vertCos);
- }
-}
-
static void do_brush_action(Sculpt *sd, SculptSession *ss, Brush *brush)
{
SculptSearchSphereData data;
@@ -2326,15 +2349,6 @@ static void do_brush_action(Sculpt *sd, SculptSession *ss, Brush *brush)
}
}
- /* copy the modified vertices from mesh to the active key */
- if(ss->kb)
- mesh_to_key(ss->ob->data, ss->kb);
-
- /* optimization: we could avoid copying new coords to keyblock at each */
- /* stroke step if there are no modifiers due to pbvh is used for displaying */
- /* so to increase speed we'll copy new coords to keyblock when stroke is done */
- if(ss->kb && ss->modifiers_active) sculpt_update_keyblock(ss);
-
MEM_freeN(nodes);
}
}
@@ -2388,6 +2402,59 @@ static void sculpt_combine_proxies(Sculpt *sd, SculptSession *ss)
MEM_freeN(nodes);
}
+/* copy the modified vertices from bvh to the active key */
+static void sculpt_update_keyblock(SculptSession *ss)
+{
+ float (*vertCos)[3];
+
+ /* Keyblock update happens after hadning deformation caused by modifiers,
+ so ss->orig_cos would be updated with new stroke */
+ if(ss->orig_cos) vertCos = ss->orig_cos;
+ else vertCos = BLI_pbvh_get_vertCos(ss->pbvh);
+
+ if (vertCos) {
+ sculpt_vertcos_to_key(ss->ob, ss->kb, vertCos);
+
+ if(vertCos != ss->orig_cos)
+ MEM_freeN(vertCos);
+ }
+}
+
+/* flush displacement from deformed PBVH to original layer */
+static void sculpt_flush_deformation(SculptSession *ss)
+{
+ float (*vertCos)[3];
+
+ vertCos= BLI_pbvh_get_vertCos(ss->pbvh);
+
+ if (vertCos) {
+ Object *ob= ss->ob;
+ Mesh *me= (Mesh*)ob->data;
+ MVert *mvert= me->mvert;
+ int a;
+
+ for(a = 0; a < me->totvert; ++a, ++mvert) {
+ float disp[3], newco[3];
+ sub_v3_v3v3(disp, vertCos[a], ss->deform_cos[a]);
+ mul_m3_v3(ss->deform_imats[a], disp);
+ add_v3_v3v3(newco, disp, ss->orig_cos[a]);
+
+ copy_v3_v3(ss->deform_cos[a], vertCos[a]);
+ copy_v3_v3(ss->orig_cos[a], newco);
+
+ if(!ss->kb)
+ copy_v3_v3(mvert->co, newco);
+ }
+
+ if(ss->kb)
+ sculpt_update_keyblock(ss);
+
+ mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+
+ MEM_freeN(vertCos);
+ }
+}
+
//static int max_overlap_count(Sculpt *sd)
//{
// int count[3];
@@ -2496,6 +2563,9 @@ static void do_symmetrical_brush_actions(Sculpt *sd, SculptSession *ss)
/* hack to fix noise texture tearing mesh */
sculpt_fix_noise_tear(sd, ss);
+ if (ss->modifiers_active)
+ sculpt_flush_deformation(ss);
+
cache->first_time= 0;
}
@@ -2517,6 +2587,17 @@ static void sculpt_update_tex(Sculpt *sd, SculptSession *ss)
}
}
+void sculpt_free_deformMats(SculptSession *ss)
+{
+ if(ss->orig_cos) MEM_freeN(ss->orig_cos);
+ if(ss->deform_cos) MEM_freeN(ss->deform_cos);
+ if(ss->deform_imats) MEM_freeN(ss->deform_imats);
+
+ ss->orig_cos = NULL;
+ ss->deform_cos = NULL;
+ ss->deform_imats = NULL;
+}
+
void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap)
{
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
@@ -2551,6 +2632,23 @@ void sculpt_update_mesh_elements(Scene *scene, Object *ob, int need_fmap)
ss->pbvh = dm->getPBVH(ob, dm);
ss->fmap = (need_fmap && dm->getFaceMap)? dm->getFaceMap(ob, dm): NULL;
+ if(ss->modifiers_active) {
+ if(!ss->orig_cos) {
+ int a;
+
+ sculpt_free_deformMats(ss);
+
+ if(ss->kb) ss->orig_cos = key_to_vertcos(ob, ss->kb);
+ else ss->orig_cos = mesh_getVertexCos(ob->data, NULL);
+
+ sculpt_get_deform_matrices(scene, ob, &ss->deform_imats, &ss->deform_cos);
+ BLI_pbvh_apply_vertCos(ss->pbvh, ss->deform_cos);
+
+ for(a = 0; a < ((Mesh*)ob->data)->totvert; ++a)
+ invert_m3(ss->deform_imats[a]);
+ }
+ } else sculpt_free_deformMats(ss);
+
/* if pbvh is deformed, key block is already applied to it */
if (ss->kb && !BLI_pbvh_isDeformed(ss->pbvh)) {
float (*vertCos)[3]= key_to_vertcos(ob, ss->kb);
@@ -2792,8 +2890,12 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
ss->layer_co= MEM_mallocN(sizeof(float) * 3 * ss->totvert,
"sculpt mesh vertices copy");
- for(i = 0; i < ss->totvert; ++i)
- copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
+ if(ss->deform_cos) memcpy(ss->layer_co, ss->deform_cos, ss->totvert);
+ else {
+ for(i = 0; i < ss->totvert; ++i) {
+ copy_v3_v3(ss->layer_co[i], ss->mvert[i].co);
+ }
+ }
}
}
@@ -2809,7 +2911,7 @@ static void sculpt_update_cache_invariants(bContext* C, Sculpt *sd, SculptSessio
cache->original = 1;
}
- if(ELEM7(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_TUBES))
+ if(ELEM8(brush->sculpt_tool, SCULPT_TOOL_DRAW, SCULPT_TOOL_CREASE, SCULPT_TOOL_BLOB, SCULPT_TOOL_LAYER, SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_TUBES, SCULPT_TOOL_ROTATE))
if(!(brush->flag & BRUSH_ACCUMULATE))
cache->original = 1;
@@ -3214,7 +3316,6 @@ static void sculpt_flush_update(bContext *C)
rcti r;
BLI_pbvh_update(ss->pbvh, PBVH_UpdateBB, NULL);
-
if (sculpt_get_redraw_rect(ar, CTX_wm_region_view3d(C), ob, &r)) {
//rcti tmp;
@@ -3489,7 +3590,7 @@ static int sculpt_toggle_mode(bContext *C, wmOperator *unused)
/* multires in sculpt mode could have different from object mode subdivision level */
flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl;
/* if object has got active modifiers, it's dm could be different in sculpt mode */
- //flush_recalc |= sculpt_modifiers_active(scene, ob);
+ flush_recalc |= sculpt_has_active_modifiers(scene, ob);
if(ob->mode & OB_MODE_SCULPT) {
if(mmd)
@@ -3554,4 +3655,3 @@ void ED_operatortypes_sculpt(void)
WM_operatortype_append(SCULPT_OT_sculptmode_toggle);
WM_operatortype_append(SCULPT_OT_set_persistent_base);
}
-
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index a48d6d8d9c9..76a7349606c 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -61,6 +61,9 @@ void sculpt(Sculpt *sd);
int sculpt_poll(struct bContext *C);
void sculpt_update_mesh_elements(struct Scene *scene, struct Object *ob, int need_fmap);
+/* Deformed mesh sculpt */
+void sculpt_free_deformMats(struct SculptSession *ss);
+
/* Stroke */
struct SculptStroke *sculpt_stroke_new(const int max);
void sculpt_stroke_free(struct SculptStroke *);
@@ -78,6 +81,7 @@ typedef struct SculptUndoNode {
void *node; /* only during push, not valid afterwards! */
float (*co)[3];
+ float (*orig_co)[3];
short (*no)[3];
int totvert;
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index a8fee6ea39d..d136fdaf6e0 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -67,6 +67,12 @@ static void update_cb(PBVHNode *node, void *unused)
BLI_pbvh_node_mark_update(node);
}
+static void sculpt_restore_deformed(SculptSession *ss, SculptUndoNode *unode, int uindex, int oindex, float coord[3])
+{
+ swap_v3_v3(coord, unode->orig_co[uindex]);
+ copy_v3_v3(unode->co[uindex], ss->deform_cos[oindex]);
+}
+
static void sculpt_undo_restore(bContext *C, ListBase *lb)
{
Scene *scene = CTX_data_scene(C);
@@ -117,8 +123,10 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
float (*vertCos)[3];
vertCos= key_to_vertcos(ob, ss->kb);
- for(i=0; i<unode->totvert; i++)
- swap_v3_v3(vertCos[index[i]], unode->co[i]);
+ for(i=0; i<unode->totvert; i++) {
+ if(ss->modifiers_active) sculpt_restore_deformed(ss, unode, i, index[i], vertCos[index[i]]);
+ else swap_v3_v3(vertCos[index[i]], unode->co[i]);
+ }
/* propagate new coords to keyblock */
sculpt_vertcos_to_key(ob, ss->kb, vertCos);
@@ -130,7 +138,8 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
MEM_freeN(vertCos);
} else {
for(i=0; i<unode->totvert; i++) {
- swap_v3_v3(mvert[index[i]].co, unode->co[i]);
+ if(ss->modifiers_active) sculpt_restore_deformed(ss, unode, i, index[i], mvert[index[i]].co);
+ else swap_v3_v3(mvert[index[i]].co, unode->co[i]);
mvert[index[i]].flag |= ME_VERT_PBVH_UPDATE;
}
}
@@ -162,6 +171,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
}
if(update) {
+ int tag_update= 0;
/* we update all nodes still, should be more clever, but also
needs to work correct when exiting/entering sculpt mode and
the nodes get recreated, though in that case it could do all */
@@ -171,7 +181,14 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
if((mmd=sculpt_multires_active(scene, ob)))
multires_mark_as_modified(ob);
- if(ss->modifiers_active || ((Mesh*)ob->data)->id.us > 1)
+ tag_update= ((Mesh*)ob->data)->id.us > 1;
+
+ if(ss->modifiers_active) {
+ sculpt_free_deformMats(ss);
+ tag_update|= 1;
+ }
+
+ if(tag_update)
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
/* for non-PBVH drawing, need to recreate VBOs */
@@ -194,6 +211,8 @@ static void sculpt_undo_free(ListBase *lb)
MEM_freeN(unode->grids);
if(unode->layer_disp)
MEM_freeN(unode->layer_disp);
+ if(unode->orig_co)
+ MEM_freeN(unode->orig_co);
}
}
@@ -255,6 +274,9 @@ SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node)
unode->index= MEM_mapallocN(sizeof(int)*allvert, "SculptUndoNode.index");
}
+ if(ss->modifiers_active)
+ unode->orig_co= MEM_callocN(allvert*sizeof(*unode->orig_co), "undoSculpt orig_cos");
+
BLI_unlock_thread(LOCK_CUSTOM1);
/* copy threaded, hopefully this is the performance critical part */
@@ -266,6 +288,9 @@ SculptUndoNode *sculpt_undo_push_node(SculptSession *ss, PBVHNode *node)
if(vd.no) VECCOPY(unode->no[vd.i], vd.no)
else normal_float_to_short_v3(unode->no[vd.i], vd.fno);
if(vd.vert_indices) unode->index[vd.i]= vd.vert_indices[vd.i];
+
+ if(ss->modifiers_active)
+ copy_v3_v3(unode->orig_co[vd.i], ss->orig_cos[unode->index[vd.i]]);
}
BLI_pbvh_vertex_iter_end;
}
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index c937ebca547..635044fa795 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -762,7 +762,7 @@ void GRAPH_OT_properties(wmOperatorType *ot)
ot->description= "Toggle display properties panel";
ot->exec= graph_properties;
- ot->poll= ED_operator_ipo_active; // xxx
+ ot->poll= ED_operator_graphedit_active;
/* flags */
ot->flag= 0;
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index e688454464c..e21dd46140e 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -182,7 +182,7 @@ void GRAPH_OT_previewrange_set (wmOperatorType *ot)
/* api callbacks */
ot->exec= graphkeys_previewrange_exec;
- ot->poll= ED_operator_ipo_active; // XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier...
+ ot->poll= ED_operator_graphedit_active; // XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier...
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -230,7 +230,7 @@ void GRAPH_OT_view_all (wmOperatorType *ot)
/* api callbacks */
ot->exec= graphkeys_viewall_exec;
- ot->poll= ED_operator_ipo_active; // XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier...
+ ot->poll= ED_operator_graphedit_active; // XXX: unchecked poll to get fsamples working too, but makes modifier damage trickier...
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
@@ -388,7 +388,7 @@ void GRAPH_OT_ghost_curves_clear (wmOperatorType *ot)
/* api callbacks */
ot->exec= graphkeys_clear_ghostcurves_exec;
- ot->poll= ED_operator_ipo_active;
+ ot->poll= ED_operator_graphedit_active;
/* flags */
ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 42f0f35f4e8..efec8dc4259 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -170,7 +170,7 @@ void GRAPH_OT_cursor_set(wmOperatorType *ot)
ot->exec= graphview_cursor_exec;
ot->invoke= graphview_cursor_invoke;
ot->modal= graphview_cursor_modal;
- ot->poll= ED_operator_ipo_active;
+ ot->poll= ED_operator_graphedit_active;
/* flags */
ot->flag= OPTYPE_BLOCKING|OPTYPE_UNDO;
@@ -208,7 +208,7 @@ void GRAPH_OT_view_togglehandles (wmOperatorType *ot)
/* callbacks */
ot->exec= view_toggle_handles_exec;
- ot->poll= ED_operator_ipo_active;
+ ot->poll= ED_operator_graphedit_active;
}
/* ************************** registration - operator types **********************************/
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 5fd86e2ed9a..3932caeeba6 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -390,7 +390,7 @@ static void draw_image_buffer(SpaceImage *sima, ARegion *ar, Scene *scene, Image
sima_draw_alpha_backdrop(x, y, ibuf->x, ibuf->y, zoomx, zoomy, col1, col2);
glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
/* we don't draw floats buffers directly but
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index f5675ebfbe8..a0fda09c92b 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -874,6 +874,8 @@ static void save_image_doit(bContext *C, SpaceImage *sima, Scene *scene, wmOpera
short ok= FALSE;
BLI_path_abs(path, bmain->name);
+ /* old global to ensure a 2nd save goes to same dir */
+ BLI_strncpy(G.ima, path, sizeof(G.ima));
WM_cursor_wait(1);
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 9e615d0d1aa..93ae75d9928 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -3753,7 +3753,7 @@ static void draw_actuator_camera(uiLayout *layout, PointerRNA *ptr)
uiItemR(row, ptr, "height", 0, NULL, ICON_NULL);
uiItemR(row, ptr, "axis", 0, NULL, ICON_NULL);
- row = uiLayoutRow(layout, 0);
+ row = uiLayoutRow(layout, 1);
uiItemR(row, ptr, "min", 0, NULL, ICON_NULL);
uiItemR(row, ptr, "max", 0, NULL, ICON_NULL);
}
@@ -3814,7 +3814,7 @@ static void draw_actuator_constraint(uiLayout *layout, PointerRNA *ptr, bContext
break;
case ACT_CONST_TYPE_ORI:
- uiItemR(layout, ptr, "direction_axis", 0, NULL, ICON_NULL);
+ uiItemR(layout, ptr, "direction_axis_pos", 0, NULL, ICON_NULL);
row=uiLayoutRow(layout, 1);
uiItemR(row, ptr, "damping", UI_ITEM_R_SLIDER , NULL, ICON_NULL);
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 6ade219583a..c615f5cc85f 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -21,6 +21,7 @@
set(INC
../include
+ ../../blenfont
../../blenkernel
../../blenlib
../../imbuf
diff --git a/source/blender/editors/space_node/SConscript b/source/blender/editors/space_node/SConscript
index 636b247d44c..1487a68215e 100644
--- a/source/blender/editors/space_node/SConscript
+++ b/source/blender/editors/space_node/SConscript
@@ -3,7 +3,7 @@ Import ('env')
sources = env.Glob('*.c')
-incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf'
+incs = '../include ../../blenfont ../../blenlib ../../blenkernel ../../makesdna ../../makesrna ../../imbuf'
incs += ' ../../nodes ../../render/extern/include'
incs += ' ../../windowmanager #intern/guardedalloc #extern/glew/include'
defs = []
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 4590cfe7442..aea35e193b8 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -44,6 +44,7 @@
#include "BKE_context.h"
#include "BKE_curve.h"
+#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -54,6 +55,8 @@
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "BLF_api.h"
+
#include "MEM_guardedalloc.h"
@@ -1367,9 +1370,32 @@ void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage)
}
if(ibuf->rect) {
- glPixelZoom(snode->zoom, snode->zoom);
- glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
- glPixelZoom(1.0f, 1.0f);
+ if (snode->flag & SNODE_SHOW_ALPHA) {
+ glPixelZoom(snode->zoom, snode->zoom);
+ /* swap bytes, so alpha is most significant one, then just draw it as luminance int */
+ if(ENDIAN_ORDER == B_ENDIAN)
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
+
+ glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_LUMINANCE, GL_UNSIGNED_INT, ibuf->rect);
+
+ glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
+ glPixelZoom(1.0f, 1.0f);
+ } else if (snode->flag & SNODE_USE_ALPHA) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glPixelZoom(snode->zoom, snode->zoom);
+
+ glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+
+ glPixelZoom(1.0f, 1.0f);
+ glDisable(GL_BLEND);
+ } else {
+ glPixelZoom(snode->zoom, snode->zoom);
+
+ glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+
+ glPixelZoom(1.0f, 1.0f);
+ }
}
glMatrixMode(GL_PROJECTION);
@@ -1382,6 +1408,47 @@ void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage)
}
}
+void draw_nodespace_color_info(ARegion *ar, int channels, int x, int y, char *cp, float *fp)
+{
+ char str[256];
+ int ofs;
+
+ ofs= sprintf(str, "X: %4d Y: %4d ", x, y);
+
+ if(channels==4) {
+ if(cp)
+ ofs+= sprintf(str+ofs, "| R: %3d G: %3d B: %3d A: %3d ", cp[0], cp[1], cp[2], cp[3]);
+ if (fp)
+ ofs+= sprintf(str+ofs, "| R: %.3f G: %.3f B: %.3f A: %.3f ", fp[0], fp[1], fp[2], fp[3]);
+ }
+ else if(channels==1) {
+ if(cp)
+ ofs+= sprintf(str+ofs, "| Val: %3d ", cp[0]);
+ if (fp)
+ ofs+= sprintf(str+ofs, "| Val: %.3f ", fp[0]);
+ }
+ else if(channels==3) {
+ if(cp)
+ ofs+= sprintf(str+ofs, "| R: %3d G: %3d B: %3d ", cp[0], cp[1], cp[2]);
+ if (fp)
+ ofs+= sprintf(str+ofs, "| R: %.3f G: %.3f B: %.3f ", fp[0], fp[1], fp[2]);
+ }
+
+ glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+
+ glColor4f(.0,.0,.0,.25);
+ glRecti(0.0, 0.0, ar->winrct.xmax - ar->winrct.xmin + 1, 20);
+ glDisable(GL_BLEND);
+
+ glColor3ub(255, 255, 255);
+
+ // UI_DrawString(6, 6, str); // works ok but fixed width is nicer.
+ BLF_size(blf_mono_font, 11, 72);
+ BLF_position(blf_mono_font, 6, 6, 0);
+ BLF_draw_ascii(blf_mono_font, str, sizeof(str));
+}
+
#if 0
/* note: needs to be userpref or opengl profile option */
static void draw_nodespace_back_tex(ScrArea *sa, SpaceNode *snode)
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 7de19c6b9e2..de0616f791e 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -616,12 +616,11 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv)
glPixelZoom(xscale, yscale);
glEnable(GL_BLEND);
- glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA ); /* premul graphics */
+ glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); /* premul graphics */
glColor4f(1.0, 1.0, 1.0, 1.0);
glaDrawPixelsTex(prv->xmin, prv->ymin, preview->xsize, preview->ysize, GL_UNSIGNED_BYTE, preview->rect);
- glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glDisable(GL_BLEND);
glPixelZoom(1.0f, 1.0f);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index cf5822d0461..834f3483871 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -53,6 +53,7 @@
#include "BKE_node.h"
#include "BKE_material.h"
#include "BKE_paint.h"
+#include "BKE_screen.h"
#include "BKE_texture.h"
#include "BKE_report.h"
@@ -62,6 +63,7 @@
#include "ED_node.h"
#include "ED_screen.h"
+#include "ED_space_api.h"
#include "ED_render.h"
#include "RNA_access.h"
@@ -73,6 +75,8 @@
#include "UI_interface.h"
#include "UI_view2d.h"
+#include "IMB_imbuf.h"
+
#include "node_intern.h"
#define SOCK_IN 1
@@ -780,6 +784,8 @@ static int snode_bg_viewmove_modal(bContext *C, wmOperator *op, wmEvent *event)
MEM_freeN(nvm);
op->customdata= NULL;
+
+ WM_event_add_notifier(C, NC_SPACE|ND_SPACE_NODE, NULL);
return OPERATOR_FINISHED;
}
@@ -827,6 +833,7 @@ void NODE_OT_backimage_move(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Background Image Move";
+ ot->description = "Move Node backdrop";
ot->idname= "NODE_OT_backimage_move";
/* api callbacks */
@@ -869,6 +876,169 @@ void NODE_OT_backimage_zoom(wmOperatorType *ot)
RNA_def_float(ot->srna, "factor", 1.2f, 0.0f, 10.0f, "Factor", "", 0.0f, 10.0f);
}
+/******************** sample backdrop operator ********************/
+
+typedef struct ImageSampleInfo {
+ ARegionType *art;
+ void *draw_handle;
+ int x, y;
+ int channels;
+ int color_manage;
+
+ char col[4];
+ float colf[4];
+
+ int draw;
+} ImageSampleInfo;
+
+static void sample_draw(const bContext *UNUSED(C), ARegion *ar, void *arg_info)
+{
+ ImageSampleInfo *info= arg_info;
+
+ draw_nodespace_color_info(ar, info->channels, info->x, info->y, info->col, info->colf);
+}
+
+static void sample_apply(bContext *C, wmOperator *op, wmEvent *event)
+{
+ SpaceNode *snode= CTX_wm_space_node(C);
+ ARegion *ar= CTX_wm_region(C);
+ ImageSampleInfo *info= op->customdata;
+ void *lock;
+ Image *ima;
+ ImBuf *ibuf;
+ float fx, fy, bufx, bufy;
+ int mx, my;
+
+ ima= BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
+ ibuf= BKE_image_acquire_ibuf(ima, NULL, &lock);
+ if(!ibuf)
+ return;
+
+ if(!ibuf->rect) {
+ if(info->color_manage)
+ ibuf->profile = IB_PROFILE_LINEAR_RGB;
+ else
+ ibuf->profile = IB_PROFILE_NONE;
+ IMB_rect_from_float(ibuf);
+ }
+
+ mx= event->x - ar->winrct.xmin;
+ my= event->y - ar->winrct.ymin;
+ /* map the mouse coords to the backdrop image space */
+ bufx = ibuf->x * snode->zoom;
+ bufy = ibuf->y * snode->zoom;
+ fx = (bufx > 0.0f ? ((float)mx - 0.5f*ar->winx - snode->xof) / bufx + 0.5f : 0.0f);
+ fy = (bufy > 0.0f ? ((float)my - 0.5f*ar->winy - snode->yof) / bufy + 0.5f : 0.0f);
+
+ if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
+ float *fp;
+ char *cp;
+ int x= (int)(fx*ibuf->x), y= (int)(fy*ibuf->y);
+
+ CLAMP(x, 0, ibuf->x-1);
+ CLAMP(y, 0, ibuf->y-1);
+
+ info->x= x;
+ info->y= y;
+ info->draw= 1;
+ info->channels= ibuf->channels;
+
+ if(ibuf->rect) {
+ cp= (char *)(ibuf->rect + y*ibuf->x + x);
+
+ info->col[0]= cp[0];
+ info->col[1]= cp[1];
+ info->col[2]= cp[2];
+ info->col[3]= cp[3];
+
+ info->colf[0]= (float)cp[0]/255.0f;
+ info->colf[1]= (float)cp[1]/255.0f;
+ info->colf[2]= (float)cp[2]/255.0f;
+ info->colf[3]= (float)cp[3]/255.0f;
+ }
+ if(ibuf->rect_float) {
+ fp= (ibuf->rect_float + (ibuf->channels)*(y*ibuf->x + x));
+
+ info->colf[0]= fp[0];
+ info->colf[1]= fp[1];
+ info->colf[2]= fp[2];
+ info->colf[3]= fp[3];
+ }
+ }
+ else
+ info->draw= 0;
+
+ BKE_image_release_ibuf(ima, lock);
+
+ ED_area_tag_redraw(CTX_wm_area(C));
+}
+
+static void sample_exit(bContext *C, wmOperator *op)
+{
+ ImageSampleInfo *info= op->customdata;
+
+ ED_region_draw_cb_exit(info->art, info->draw_handle);
+ ED_area_tag_redraw(CTX_wm_area(C));
+ MEM_freeN(info);
+}
+
+static int sample_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ SpaceNode *snode= CTX_wm_space_node(C);
+ ARegion *ar= CTX_wm_region(C);
+ ImageSampleInfo *info;
+
+ if(snode->treetype!=NTREE_COMPOSIT || !(snode->flag & SNODE_BACKDRAW))
+ return OPERATOR_CANCELLED;
+
+ info= MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo");
+ info->art= ar->type;
+ info->draw_handle = ED_region_draw_cb_activate(ar->type, sample_draw, info, REGION_DRAW_POST_PIXEL);
+ op->customdata= info;
+
+ sample_apply(C, op, event);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sample_modal(bContext *C, wmOperator *op, wmEvent *event)
+{
+ switch(event->type) {
+ case LEFTMOUSE:
+ case RIGHTMOUSE: // XXX hardcoded
+ sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+ case MOUSEMOVE:
+ sample_apply(C, op, event);
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int sample_cancel(bContext *C, wmOperator *op)
+{
+ sample_exit(C, op);
+ return OPERATOR_CANCELLED;
+}
+
+void NODE_OT_backimage_sample(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name= "Backimage Sample";
+ ot->idname= "NODE_OT_backimage_sample";
+
+ /* api callbacks */
+ ot->invoke= sample_invoke;
+ ot->modal= sample_modal;
+ ot->cancel= sample_cancel;
+ ot->poll= ED_operator_node_active;
+
+ /* flags */
+ ot->flag= OPTYPE_BLOCKING;
+}
/* ********************** size widget operator ******************** */
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index cfe32846124..66bf9310db8 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -71,6 +71,7 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link);
void node_draw_link_bezier(View2D *v2d, SpaceNode *snode, bNodeLink *link, int th_col1, int do_shaded, int th_col2, int do_triple, int th_col3 );
int node_link_bezier_points(View2D *v2d, SpaceNode *snode, bNodeLink *link, float coord_array[][2], int resol);
void draw_nodespace_back_pix(ARegion *ar, SpaceNode *snode, int color_manage);
+void draw_nodespace_color_info(ARegion *ar, int channels, int x, int y, char *cp, float *fp);
void node_buts_group(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr);
@@ -114,8 +115,10 @@ void NODE_OT_show_cyclic_dependencies(struct wmOperatorType *ot);
void NODE_OT_link_viewer(struct wmOperatorType *ot);
void NODE_OT_read_fullsamplelayers(struct wmOperatorType *ot);
void NODE_OT_read_renderlayers(struct wmOperatorType *ot);
+
void NODE_OT_backimage_move(struct wmOperatorType *ot);
void NODE_OT_backimage_zoom(struct wmOperatorType *ot);
+void NODE_OT_backimage_sample(wmOperatorType *ot);
void NODE_OT_add_file(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index 46cd8515f23..781682c9185 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -81,6 +81,7 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_backimage_move);
WM_operatortype_append(NODE_OT_backimage_zoom);
+ WM_operatortype_append(NODE_OT_backimage_sample);
WM_operatortype_append(NODE_OT_add_file);
}
@@ -136,7 +137,7 @@ void node_keymap(struct wmKeyConfig *keyconf)
RNA_float_set(kmi->ptr, "factor", 0.83333f);
kmi= WM_keymap_add_item(keymap, "NODE_OT_backimage_zoom", VKEY, KM_PRESS, KM_ALT, 0);
RNA_float_set(kmi->ptr, "factor", 1.2f);
-
+ WM_keymap_add_item(keymap, "NODE_OT_backimage_sample", ACTIONMOUSE, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "NODE_OT_link_make", FKEY, KM_PRESS, 0, 0);
RNA_boolean_set(WM_keymap_add_item(keymap, "NODE_OT_link_make", FKEY, KM_PRESS, KM_CTRL, 0)->ptr, "replace", 1);
@@ -167,8 +168,8 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_group_ungroup", GKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "NODE_OT_group_edit", TABKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NODE_OT_read_renderlayers", RKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NODE_OT_read_fullsamplelayers", RKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_add_item(keymap, "NODE_OT_read_renderlayers", RKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "NODE_OT_read_fullsamplelayers", RKEY, KM_PRESS, KM_SHIFT, 0);
transform_keymap_for_space(keyconf, keymap, SPACE_NODE);
}
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 7eb0ab67d8e..efb0b173559 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -2576,10 +2576,12 @@ static int line_number_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *even
static int jump_to= 0;
static double last_jump= 0;
+ text_update_character_width(st);
+
if(!st->showlinenrs)
return OPERATOR_PASS_THROUGH;
- if(!(mval[0]>2 && mval[0]<60 && mval[1]>2 && mval[1]<ar->winy-2))
+ if(!(mval[0]>2 && mval[0]<(TXT_OFFSET + TEXTXLOC) && mval[1]>2 && mval[1]<ar->winy-2))
return OPERATOR_PASS_THROUGH;
if(!(event->ascii>='0' && event->ascii<='9'))
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index 8a692a60777..f05cb860d6f 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -569,7 +569,7 @@ static SpaceLink *time_new(const bContext *C)
stime= MEM_callocN(sizeof(SpaceTime), "inittime");
stime->spacetype= SPACE_TIME;
- stime->redraws= TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN;
+ stime->redraws= TIME_ALL_3D_WIN|TIME_ALL_ANIM_WIN; // XXX: depreceated
stime->flag |= TIME_DRAWFRAMES;
/* header */
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index bbb52826de6..bc9c41f3add 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -766,7 +766,7 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, wmEvent *event)
if(rv3d->viewlock) { /* poll should check but in some cases fails, see poll func for details */
viewops_data_free(C, op);
- return OPERATOR_CANCELLED;
+ return OPERATOR_PASS_THROUGH;
}
/* switch from camera view when: */
@@ -828,21 +828,6 @@ static int view3d_camera_active_poll(bContext *C)
return 0;
}
-static int view3d_rotate_poll(bContext *C)
-{
- if (!ED_operator_region_view3d_active(C)) {
- return 0;
- } else {
- RegionView3D *rv3d= CTX_wm_region_view3d(C);
- /* rv3d is null in menus, but it's ok when the menu is clicked on */
- /* XXX of course, this doesn't work with quadview
- * Maybe having exec return PASSTHROUGH would be better than polling here
- * Poll functions are full of problems anyway.
- * */
- return rv3d == NULL || rv3d->viewlock == 0;
- }
-}
-
void VIEW3D_OT_rotate(wmOperatorType *ot)
{
@@ -854,7 +839,7 @@ void VIEW3D_OT_rotate(wmOperatorType *ot)
/* api callbacks */
ot->invoke= viewrotate_invoke;
ot->modal= viewrotate_modal;
- ot->poll= view3d_rotate_poll;
+ ot->poll= ED_operator_region_view3d_active;
/* flags */
ot->flag= OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
@@ -1953,6 +1938,9 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
viewnum = RNA_enum_get(op->ptr, "type");
align_active = RNA_boolean_get(op->ptr, "align_active");
+ /* set this to zero, gets handled in axis_set_view */
+ if(rv3d->viewlock)
+ align_active= 0;
/* Use this to test if we started out with a camera */
@@ -2060,12 +2048,6 @@ static int viewnumpad_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-int region3d_unlocked_poll(bContext *C)
-{
- RegionView3D *rv3d= CTX_wm_region_view3d(C);
- return (rv3d && rv3d->viewlock==0);
-}
-
void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
{
@@ -2076,7 +2058,7 @@ void VIEW3D_OT_viewnumpad(wmOperatorType *ot)
/* api callbacks */
ot->exec= viewnumpad_exec;
- ot->poll= region3d_unlocked_poll;
+ ot->poll= ED_operator_region_view3d_active;
/* flags */
ot->flag= 0;
@@ -2144,7 +2126,7 @@ void VIEW3D_OT_view_orbit(wmOperatorType *ot)
/* api callbacks */
ot->exec= vieworbit_exec;
- ot->poll= view3d_rotate_poll;
+ ot->poll= ED_operator_region_view3d_active;
/* flags */
ot->flag= 0;
@@ -2622,7 +2604,7 @@ void VIEW3D_OT_enable_manipulator(wmOperatorType *ot)
/* ************************* below the line! *********************** */
-static float view_autodist_depth_margin(ARegion *ar, short *mval, int margin)
+static float view_autodist_depth_margin(ARegion *ar, short mval[2], int margin)
{
ViewDepths depth_temp= {0};
rcti rect;
@@ -2721,12 +2703,51 @@ int view_autodist_simple(ARegion *ar, short *mval, float mouse_worldloc[3], int
return 1;
}
-int view_autodist_depth(struct ARegion *ar, short *mval, int margin, float *depth)
+int view_autodist_depth(struct ARegion *ar, short mval[2], int margin, float *depth)
{
*depth= view_autodist_depth_margin(ar, mval, margin);
return (*depth==FLT_MAX) ? 0:1;
+}
+
+static int depth_segment_cb(int x, int y, void *userData)
+{
+ struct { struct ARegion *ar; int margin; float depth; } *data = userData;
+ short mval[2];
+ float depth;
+
+ mval[0]= (short)x;
+ mval[1]= (short)y;
+
+ depth= view_autodist_depth_margin(data->ar, mval, data->margin);
+
+ if(depth != FLT_MAX) {
+ data->depth= depth;
return 0;
+ }
+ else {
+ return 1;
+ }
+}
+
+int view_autodist_depth_segment(struct ARegion *ar, short mval_sta[2], short mval_end[2], int margin, float *depth)
+{
+ struct { struct ARegion *ar; int margin; float depth; } data = {0};
+ int p1[2];
+ int p2[2];
+
+ data.ar= ar;
+ data.margin= margin;
+ data.depth= FLT_MAX;
+
+ VECCOPY2D(p1, mval_sta);
+ VECCOPY2D(p2, mval_end);
+
+ plot_line_v2v2i(p1, p2, depth_segment_cb, &data);
+
+ *depth= data.depth;
+
+ return (*depth==FLT_MAX) ? 0:1;
}
/* ********************* NDOF ************************ */
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 73c07e8ac25..0f1fe2fba07 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -85,7 +85,6 @@ void VIEW3D_OT_drawtype(struct wmOperatorType *ot);
void view3d_boxview_copy(ScrArea *sa, ARegion *ar);
void view3d_persp_mat4(struct RegionView3D *rv3d, float mat[][4]);
-int region3d_unlocked_poll(struct bContext *C);
/* view3d_fly.c */
void view3d_keymap(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 49071af8bdd..7ed85cacc1e 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -477,6 +477,13 @@ static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
+static int region3d_unlocked_poll(bContext *C)
+{
+ RegionView3D *rv3d= CTX_wm_region_view3d(C);
+ return (rv3d && rv3d->viewlock==0);
+}
+
+
void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
{
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 03b03d211d9..86da5e0a4b5 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -827,9 +827,9 @@ static void pose_grab_with_ik_clear(Object *ob)
/* adds the IK to pchan - returns if added */
static short pose_grab_with_ik_add(bPoseChannel *pchan)
{
+ bKinematicConstraint *targetless = NULL;
bKinematicConstraint *data;
bConstraint *con;
- bConstraint *targetless = 0;
/* Sanity check */
if (pchan == NULL)
@@ -838,15 +838,31 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
/* Rule: not if there's already an IK on this channel */
for (con= pchan->constraints.first; con; con= con->next) {
if (con->type==CONSTRAINT_TYPE_KINEMATIC) {
- bKinematicConstraint *data= con->data;
- if(data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]==0)) {
- targetless = con;
+ data= con->data;
+
+ if (data->tar==NULL || (data->tar->type==OB_ARMATURE && data->subtarget[0]=='\0')) {
+ /* make reference to constraint to base things off later (if it's the last targetless constraint encountered) */
+ targetless = (bKinematicConstraint *)con->data;
+
/* but, if this is a targetless IK, we make it auto anyway (for the children loop) */
if (con->enforce!=0.0f) {
- targetless->flag |= CONSTRAINT_IK_AUTO;
- return 0;
+ data->flag |= CONSTRAINT_IK_AUTO;
+
+ /* if no chain length has been specified, just make things obey standard rotation locks too */
+ if (data->rootbone == 0) {
+ for (; pchan; pchan=pchan->parent) {
+ /* here, we set ik-settings for bone from pchan->protectflag */
+ // XXX: careful with quats/axis-angle rotations where we're locking 4d components
+ if (pchan->protectflag & OB_LOCK_ROTX) pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
+ if (pchan->protectflag & OB_LOCK_ROTY) pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
+ if (pchan->protectflag & OB_LOCK_ROTZ) pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
+ }
+ }
+
+ return 0;
}
}
+
if ((con->flag & CONSTRAINT_DISABLE)==0 && (con->enforce!=0.0f))
return 0;
}
@@ -855,22 +871,24 @@ static short pose_grab_with_ik_add(bPoseChannel *pchan)
con = add_pose_constraint(NULL, pchan, "TempConstraint", CONSTRAINT_TYPE_KINEMATIC);
pchan->constflag |= (PCHAN_HAS_IK|PCHAN_HAS_TARGET); /* for draw, but also for detecting while pose solving */
data= con->data;
- if (targetless) { /* if exists use values from last targetless IK-constraint as base */
- *data = *((bKinematicConstraint*)targetless->data);
+ if (targetless) {
+ /* if exists, use values from last targetless (but disabled) IK-constraint as base */
+ *data = *targetless;
}
else
data->flag= CONSTRAINT_IK_TIP;
data->flag |= CONSTRAINT_IK_TEMP|CONSTRAINT_IK_AUTO;
VECCOPY(data->grabtarget, pchan->pose_tail);
- data->rootbone= 1;
+ data->rootbone= 0; /* watch-it! has to be 0 here, since we're still on the same bone for the first time through the loop [#25885] */
/* we only include bones that are part of a continual connected chain */
while (pchan) {
/* here, we set ik-settings for bone from pchan->protectflag */
+ // XXX: careful with quats/axis-angle rotations where we're locking 4d components
if (pchan->protectflag & OB_LOCK_ROTX) pchan->ikflag |= BONE_IK_NO_XDOF_TEMP;
if (pchan->protectflag & OB_LOCK_ROTY) pchan->ikflag |= BONE_IK_NO_YDOF_TEMP;
if (pchan->protectflag & OB_LOCK_ROTZ) pchan->ikflag |= BONE_IK_NO_ZDOF_TEMP;
-
+
/* now we count this pchan as being included */
data->rootbone++;
@@ -4568,13 +4586,13 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
/* add datasource override for the camera object */
ANIM_relative_keyingset_add_source(&dsources, id, NULL, NULL);
- if (IS_AUTOKEY_FLAG(ONLYKEYINGSET) && (active_ks)) {
+ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
/* only insert into active keyingset
* NOTE: we assume here that the active Keying Set does not need to have its iterator overridden spe
*/
ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
}
- else if (IS_AUTOKEY_FLAG(INSERTAVAIL)) {
+ else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
AnimData *adt= ob->adt;
/* only key on available channels */
@@ -4585,7 +4603,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob,
}
}
}
- else if (IS_AUTOKEY_FLAG(INSERTNEEDED)) {
+ else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
short doLoc=0, doRot=0, doScale=0;
/* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
@@ -4682,12 +4700,12 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
ANIM_relative_keyingset_add_source(&dsources, id, &RNA_PoseBone, pchan);
/* only insert into active keyingset? */
- if (IS_AUTOKEY_FLAG(ONLYKEYINGSET) && (active_ks)) {
+ if (IS_AUTOKEY_FLAG(scene, ONLYKEYINGSET) && (active_ks)) {
/* run the active Keying Set on the current datasource */
ANIM_apply_keyingset(C, &dsources, NULL, active_ks, MODIFYKEY_MODE_INSERT, cfra);
}
/* only insert into available channels? */
- else if (IS_AUTOKEY_FLAG(INSERTAVAIL)) {
+ else if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)) {
if (act) {
for (fcu= act->curves.first; fcu; fcu= fcu->next) {
/* only insert keyframes for this F-Curve if it affects the current bone */
@@ -4706,7 +4724,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
}
}
/* only insert keyframe if needed? */
- else if (IS_AUTOKEY_FLAG(INSERTNEEDED)) {
+ else if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
short doLoc=0, doRot=0, doScale=0;
/* filter the conditions when this happens (assume that curarea->spacetype==SPACE_VIE3D) */
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 839e813f1ae..85a7526b7b4 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -269,7 +269,7 @@ static void animrecord_check_state (Scene *scene, ID *id, wmTimer *animtimer)
* - we're not only keying for available channels
* - the option to add new actions for each round is not enabled
*/
- if (IS_AUTOKEY_FLAG(INSERTAVAIL)==0 && (scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA)) {
+ if (IS_AUTOKEY_FLAG(scene, INSERTAVAIL)==0 && (scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA)) {
/* if playback has just looped around, we need to add a new NLA track+strip to allow a clean pass to occur */
if ((sad) && (sad->flag & ANIMPLAY_FLAG_JUMPED)) {
AnimData *adt= BKE_animdata_from_id(id);
diff --git a/source/blender/makesdna/DNA_armature_types.h b/source/blender/makesdna/DNA_armature_types.h
index 108c0883f15..89c2d69b8be 100644
--- a/source/blender/makesdna/DNA_armature_types.h
+++ b/source/blender/makesdna/DNA_armature_types.h
@@ -57,8 +57,9 @@ typedef struct Bone {
int flag;
float arm_head[3];
- float arm_tail[3]; /* head/tail and roll in Armature Space (rest pos) */
+ float arm_tail[3]; /* head/tail in Armature Space (rest pos) */
float arm_mat[4][4]; /* matrix: (bonemat(b)+head(b))*arm_mat(b-1), rest pos*/
+ float arm_roll; /* roll in Armature Space (rest pos) */
float dist, weight; /* dist, weight: for non-deformgroup deforms */
float xwidth, length, zwidth; /* width: for block bones. keep in this order, transform! */
@@ -68,7 +69,7 @@ typedef struct Bone {
float size[3]; /* patch for upward compat, UNUSED! */
int layer; /* layers that bone appears on */
short segments; /* for B-bones */
- short pad[3];
+ short pad[1];
} Bone;
typedef struct bArmature {
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 08d5258f34b..d66246a4136 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -328,7 +328,8 @@ typedef enum eBezTriple_Interpolation {
typedef enum eBezTriple_KeyframeType {
BEZT_KEYTYPE_KEYFRAME = 0, /* default - 'proper' Keyframe */
BEZT_KEYTYPE_EXTREME, /* 'extreme' keyframe */
- BEZT_KEYTYPE_BREAKDOWN /* 'breakdown' keyframe */
+ BEZT_KEYTYPE_BREAKDOWN, /* 'breakdown' keyframe */
+ BEZT_KEYTYPE_JITTER, /* 'jitter' keyframe (for adding 'filler' secondary motion) */
} eBezTriple_KeyframeType;
/* checks if the given BezTriple is selected */
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index f009f3a9eb0..a3a44976fcd 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -168,8 +168,8 @@ typedef struct ParticleSettings {
/* general values */
float sta, end, lifetime, randlife;
- float timetweak, jitfac, eff_hair;
- int totpart, userjit, grid_res;
+ float timetweak, jitfac, eff_hair, grid_rand;
+ int totpart, userjit, grid_res, rt;
/* initial velocity factors */
float normfac, obfac, randfac, partfac, tanfac, tanphase, reactfac;
@@ -247,7 +247,7 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
float imat[4][4]; /* used for duplicators */
float cfra, tree_frame;
int seed, child_seed;
- int flag, totpart, totchild, totcached, totchildcache;
+ int flag, totpart, totunexist, totchild, totcached, totchildcache, rt;
short recalc, target_psys, totkeyed, bakespace;
char bb_uvname[3][32]; /* billboard uv name */
@@ -459,7 +459,7 @@ typedef struct ParticleSystem{ /* note, make sure all (runtime) are NULL's in
#define PSYS_ENABLED 16 /* deprecated */
#define PSYS_HAIR_UPDATED 32 /* signal for updating hair particle mode */
#define PSYS_DRAWING 64
-//#define PSYS_SOFT_BAKE 128
+#define PSYS_USE_IMAT 128
#define PSYS_DELETE 256 /* remove particlesystem as soon as possible */
#define PSYS_HAIR_DONE 512
#define PSYS_KEYED 1024
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 606c69e693e..52d8b2e8dd9 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -54,6 +54,9 @@ typedef struct bScreen {
struct Scene *scene;
struct Scene *newscene; /* temporary when switching */
+ int redraws_flag; /* user-setting for which editors get redrawn during anim playback (used to be time->redraws) */
+ int pad1;
+
short full; /* temp screen for image render display or fileselect */
short temp; /* temp screen in a temp window, don't save (like user prefs) */
short winid; /* winid from WM, starts with 1 */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 9238f52a615..49a4df043fb 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -372,7 +372,7 @@ typedef struct SpaceTime {
ListBase caches;
int cache_display, pad;
- int flag, redraws;
+ int flag, redraws; /* redraws is deprecated... moved to screen */
} SpaceTime;
@@ -405,6 +405,8 @@ typedef struct SpaceNode {
/* snode->flag */
#define SNODE_BACKDRAW 2
#define SNODE_DISPGP 4
+#define SNODE_USE_ALPHA 8
+#define SNODE_SHOW_ALPHA 16
/* snode->texfrom */
#define SNODE_TEX_OBJECT 0
@@ -861,7 +863,7 @@ enum {
/* only keyframes from active/selected channels get shown */
#define TIME_ONLYACTSEL 4
-/* time->redraws */
+/* time->redraws (now screen->redraws_flag) */
#define TIME_REGION 1
#define TIME_ALL_3D_WIN 2
#define TIME_ALL_ANIM_WIN 4
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 6840da9638d..d8ab447b93a 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -492,9 +492,9 @@ extern UserDef U; /* from blenkernel blender.c */
#define AUTOKEY_FLAG_INSERTNEEDED (1<<1)
#define AUTOKEY_FLAG_AUTOMATKEY (1<<2)
#define AUTOKEY_FLAG_XYZ2RGB (1<<3)
- /* U.autokey_flag (strictly autokeying only) */
+
+/* toolsettings->autokey_flag */
#define AUTOKEY_FLAG_ONLYKEYINGSET (1<<6)
- /* toolsettings->autokey_flag */
#define ANIMRECORD_FLAG_WITHNLA (1<<10)
/* transopts */
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index cd14acd520c..c103e74ca34 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -43,7 +43,7 @@
/* gcc 4.1 on mingw was complaining that __int64 was already defined
actually is saw the line below as typedef long long long long...
-Anyhow, since its already defined, its safe to do an ifndef here- Cambpell*/
+Anyhow, since its already defined, its safe to do an ifndef here- Campbell */
#ifdef FREE_WINDOWS
#ifndef __int64
typedef long long __int64;
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 7e3e2bf501c..180b3d5ab47 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -767,8 +767,8 @@ int RNA_property_collection_type_get(PointerRNA *ptr, PropertyRNA *prop, Pointer
/* efficient functions to set properties for arrays */
int RNA_property_collection_raw_array(PointerRNA *ptr, PropertyRNA *prop, PropertyRNA *itemprop, RawArray *array);
-int RNA_property_collection_raw_get(struct ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, char *propname, void *array, RawPropertyType type, int len);
-int RNA_property_collection_raw_set(struct ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, char *propname, void *array, RawPropertyType type, int len);
+int RNA_property_collection_raw_get(struct ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, const char *propname, void *array, RawPropertyType type, int len);
+int RNA_property_collection_raw_set(struct ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, const char *propname, void *array, RawPropertyType type, int len);
int RNA_raw_type_sizeof(RawPropertyType type);
RawPropertyType RNA_property_raw_type(PropertyRNA *prop);
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index d5d9c4c6cb3..1dcb917bc1d 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -1013,7 +1013,7 @@ static char *rna_def_property_lookup_int_func(FILE *f, StructRNA *srna, Property
fprintf(f, " else {\n");
fprintf(f, " while(index-- > 0 && internal->link)\n");
fprintf(f, " internal->link= internal->link->next;\n");
- fprintf(f, " found= 1;\n");
+ fprintf(f, " found= (index == -1 && internal->link);\n");
fprintf(f, " }\n");
}
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index e6802d03ec4..6c09b349d9b 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -2460,7 +2460,7 @@ int RNA_raw_type_sizeof(RawPropertyType type)
}
}
-static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, char *propname, void *inarray, RawPropertyType intype, int inlen, int set)
+static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, const char *propname, void *inarray, RawPropertyType intype, int inlen, int set)
{
StructRNA *ptype;
PointerRNA itemptr;
@@ -2762,12 +2762,12 @@ RawPropertyType RNA_property_raw_type(PropertyRNA *prop)
return prop->rawtype;
}
-int RNA_property_collection_raw_get(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, char *propname, void *array, RawPropertyType type, int len)
+int RNA_property_collection_raw_get(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, const char *propname, void *array, RawPropertyType type, int len)
{
return rna_raw_access(reports, ptr, prop, propname, array, type, len, 0);
}
-int RNA_property_collection_raw_set(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, char *propname, void *array, RawPropertyType type, int len)
+int RNA_property_collection_raw_set(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, const char *propname, void *array, RawPropertyType type, int len)
{
return rna_raw_access(reports, ptr, prop, propname, array, type, len, 1);
}
@@ -3423,12 +3423,19 @@ static char *rna_path_from_ID_to_idpgroup(PointerRNA *ptr)
IDProperty *needle;
BLI_assert(ptr->id.data != NULL);
+
+ /* TODO, Support Bones/PoseBones. no pointers stored to the bones from here, only the ID. See example in [#25746]
+ * unless this is added only way to find this is to also search all bones and pose bones of an armature or object */
RNA_id_pointer_create(ptr->id.data, &id_ptr);
haystack= RNA_struct_idprops(&id_ptr, FALSE);
- needle= ptr->data;
-
- return rna_idp_path(&id_ptr, haystack, needle, NULL);
+ if(haystack) { /* can fail when called on bones */
+ needle= ptr->data;
+ return rna_idp_path(&id_ptr, haystack, needle, NULL);
+ }
+ else {
+ return NULL;
+ }
}
char *RNA_path_from_ID_to_struct(PointerRNA *ptr)
diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c
index 378209bb2e7..46230815178 100644
--- a/source/blender/makesrna/intern/rna_actuator.c
+++ b/source/blender/makesrna/intern/rna_actuator.c
@@ -35,6 +35,8 @@
#include "WM_types.h"
+#include "BLI_utildefines.h"
+
/* Always keep in alphabetical order */
EnumPropertyItem actuator_type_items[] ={
{ACT_ACTION, "ACTION", 0, "Action", ""},
@@ -117,6 +119,29 @@ static void rna_Actuator_type_set(struct PointerRNA *ptr, int value)
}
}
+static void rna_ConstraintActuator_type_set(struct PointerRNA *ptr, int value)
+{
+ bActuator *act= (bActuator *)ptr->data;
+ bConstraintActuator *ca= act->data;
+ if (value != ca->type)
+ {
+ ca->type = value;
+ switch (ca->type) {
+ case ACT_CONST_TYPE_ORI:
+ /* negative axis not supported in the orientation mode */
+ if (ELEM3(ca->mode, ACT_CONST_DIRNX,ACT_CONST_DIRNY, ACT_CONST_DIRNZ))
+ ca->mode = ACT_CONST_NONE;
+ break;
+
+ case ACT_CONST_TYPE_LOC:
+ case ACT_CONST_TYPE_DIST:
+ case ACT_CONST_TYPE_FH:
+ default:
+ break;
+ }
+ }
+}
+
static float rna_ConstraintActuator_limitmin_get(struct PointerRNA *ptr)
{
bActuator *act = (bActuator*)ptr->data;
@@ -284,7 +309,6 @@ static void rna_ConstraintActuator_spring_set(struct PointerRNA *ptr, float valu
*fp = value;
}
-
/* ConstraintActuator uses the same property for Material and Property.
Therefore we need to clear the property when "use_material_detect" mode changes */
static void rna_Actuator_constraint_detect_material_set(struct PointerRNA *ptr, int value)
@@ -324,6 +348,33 @@ static void rna_FcurveActuator_force_set(struct PointerRNA *ptr, int value)
ia->flag &= ~ACT_IPOFORCE;
}
+
+static void rna_ObjectActuator_type_set(struct PointerRNA *ptr, int value)
+{
+ bActuator *act= (bActuator *)ptr->data;
+ bObjectActuator *oa = act->data;
+ if (value != oa->type)
+ {
+ oa->type = value;
+ switch (oa->type) {
+ case ACT_OBJECT_NORMAL:
+ memset(oa, 0, sizeof(bObjectActuator));
+ oa->flag = ACT_FORCE_LOCAL|ACT_TORQUE_LOCAL|ACT_DLOC_LOCAL|ACT_DROT_LOCAL;
+ oa->type = ACT_OBJECT_NORMAL;
+ break;
+
+ case ACT_OBJECT_SERVO:
+ memset(oa, 0, sizeof(bObjectActuator));
+ oa->flag = ACT_LIN_VEL_LOCAL;
+ oa->type = ACT_OBJECT_SERVO;
+ oa->forcerot[0] = 30.0f;
+ oa->forcerot[1] = 0.5f;
+ oa->forcerot[2] = 0.0f;
+ break;
+ }
+ }
+}
+
static void rna_ObjectActuator_integralcoefficient_set(struct PointerRNA *ptr, float value)
{
bActuator *act = (bActuator*)ptr->data;
@@ -591,6 +642,7 @@ static void rna_def_object_actuator(BlenderRNA *brna)
prop= RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, prop_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_ObjectActuator_type_set", NULL);
RNA_def_property_ui_text(prop, "Motion Type", "Specify the motion system");
RNA_def_property_update(prop, NC_LOGIC, NULL);
@@ -1049,6 +1101,14 @@ static void rna_def_constraint_actuator(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_direction_pos_items[] ={
+ {ACT_CONST_NONE, "NONE", 0, "None", ""},
+ {ACT_CONST_DIRPX, "DIRPX", 0, "X axis", ""},
+ {ACT_CONST_DIRPY, "DIRPY", 0, "Y axis", ""},
+ {ACT_CONST_DIRPZ, "DIRPZ", 0, "Z axis", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna= RNA_def_struct(brna, "ConstraintActuator", "Actuator");
RNA_def_struct_ui_text(srna, "Constraint Actuator", "Actuator to handle Constraints");
RNA_def_struct_sdna_from(srna, "bConstraintActuator", "data");
@@ -1056,6 +1116,7 @@ static void rna_def_constraint_actuator(BlenderRNA *brna)
prop= RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "type");
RNA_def_property_enum_items(prop, prop_type_items);
+ RNA_def_property_enum_funcs(prop, NULL, "rna_ConstraintActuator_type_set", NULL);
RNA_def_property_ui_text(prop, "Constraints Mode", "The type of the constraint");
RNA_def_property_update(prop, NC_LOGIC, NULL);
@@ -1090,7 +1151,7 @@ static void rna_def_constraint_actuator(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Max", "");
RNA_def_property_update(prop, NC_LOGIC, NULL);
- prop= RNA_def_property(srna, "damping", PROP_INT, PROP_PERCENTAGE);
+ prop= RNA_def_property(srna, "damping", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "damp");
RNA_def_property_ui_range(prop, 0, 100, 1, 1);
RNA_def_property_ui_text(prop, "Damping", "Damping factor: time constant (in frame) of low pass filter");
@@ -1127,13 +1188,19 @@ static void rna_def_constraint_actuator(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Time", "Maximum activation time in frame, 0 for unlimited");
RNA_def_property_update(prop, NC_LOGIC, NULL);
- prop= RNA_def_property(srna, "damping_rotation", PROP_INT, PROP_PERCENTAGE);
+ prop= RNA_def_property(srna, "damping_rotation", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "rotdamp");
RNA_def_property_ui_range(prop, 0, 100, 1, 1);
RNA_def_property_ui_text(prop, "rotDamp", "Use a different damping for orientation");
RNA_def_property_update(prop, NC_LOGIC, NULL);
/* ACT_CONST_TYPE_ORI */
+ prop= RNA_def_property(srna, "direction_axis_pos", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, prop_direction_pos_items);
+ RNA_def_property_ui_text(prop, "Direction", "Select the axis to be aligned along the reference direction");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
prop= RNA_def_property(srna, "rotation_max", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "maxrot");
RNA_def_property_array(prop, 3);
@@ -1141,16 +1208,16 @@ static void rna_def_constraint_actuator(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Reference Direction", "Reference Direction");
RNA_def_property_update(prop, NC_LOGIC, NULL);
- prop= RNA_def_property(srna, "angle_min", PROP_FLOAT, PROP_NONE);
+ prop= RNA_def_property(srna, "angle_min", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "minloc[0]");
- RNA_def_property_ui_range(prop, 0.0, 180.0, 10, 2);
- RNA_def_property_ui_text(prop, "Min Angle", "Minimum angle (in degree) to maintain with target direction. No correction is done if angle with target direction is between min and max");
+ RNA_def_property_range(prop, 0.0, 180.0);
+ RNA_def_property_ui_text(prop, "Min Angle", "Minimum angle to maintain with target direction. No correction is done if angle with target direction is between min and max");
RNA_def_property_update(prop, NC_LOGIC, NULL);
- prop= RNA_def_property(srna, "angle_max", PROP_FLOAT, PROP_NONE);
+ prop= RNA_def_property(srna, "angle_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "maxloc[0]");
- RNA_def_property_ui_range(prop, 0.0, 180.0, 10, 2);
- RNA_def_property_ui_text(prop, "Max Angle", "Maximum angle (in degree) allowed with target direction. No correction is done if angle with target direction is between min and max");
+ RNA_def_property_range(prop, 0.0, 180.0);
+ RNA_def_property_ui_text(prop, "Max Angle", "Maximum angle allowed with target direction. No correction is done if angle with target direction is between min and max");
RNA_def_property_update(prop, NC_LOGIC, NULL);
/* ACT_CONST_TYPE_FH */
@@ -1160,7 +1227,7 @@ static void rna_def_constraint_actuator(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Distance", "Height of the Fh area");
RNA_def_property_update(prop, NC_LOGIC, NULL);
- prop= RNA_def_property(srna, "spring", PROP_FLOAT, PROP_NONE);
+ prop= RNA_def_property(srna, "spring", PROP_FLOAT, PROP_PERCENTAGE);
RNA_def_property_float_funcs(prop, "rna_ConstraintActuator_spring_get", "rna_ConstraintActuator_spring_set", NULL);
RNA_def_property_ui_range(prop, 0.0, 1.0, 10, 2);
RNA_def_property_ui_text(prop, "Fh", "Spring force within the Fh area");
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 9bed1b5cd5a..680a230c1a6 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -517,6 +517,7 @@ static void rna_def_keyingset_path(BlenderRNA *brna)
RNA_def_property_editable_func(prop, "rna_ksPath_id_editable");
RNA_def_property_pointer_funcs(prop, NULL, NULL, "rna_ksPath_id_typef", NULL);
RNA_def_property_ui_text(prop, "ID-Block", "ID-Block that keyframes for Keying Set should be added to (for Absolute Keying Sets only)");
+ RNA_def_property_update(prop, NC_SCENE|ND_KEYINGSET|NA_EDITED, NULL); // XXX: maybe a bit too noisy
prop= RNA_def_property(srna, "id_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "idtype");
@@ -524,30 +525,36 @@ static void rna_def_keyingset_path(BlenderRNA *brna)
RNA_def_property_enum_default(prop, ID_OB);
RNA_def_property_enum_funcs(prop, NULL, "rna_ksPath_id_type_set", NULL);
RNA_def_property_ui_text(prop, "ID Type", "Type of ID-block that can be used");
+ RNA_def_property_update(prop, NC_SCENE|ND_KEYINGSET|NA_EDITED, NULL); // XXX: maybe a bit too noisy
/* Group */
prop= RNA_def_property(srna, "group", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Group Name", "Name of Action Group to assign setting(s) for this path to");
+ RNA_def_property_update(prop, NC_SCENE|ND_KEYINGSET|NA_EDITED, NULL); // XXX: maybe a bit too noisy
/* Grouping */
prop= RNA_def_property(srna, "group_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "groupmode");
RNA_def_property_enum_items(prop, keyingset_path_grouping_items);
RNA_def_property_ui_text(prop, "Grouping Method", "Method used to define which Group-name to use");
+ RNA_def_property_update(prop, NC_SCENE|ND_KEYINGSET|NA_EDITED, NULL); // XXX: maybe a bit too noisy
/* Path + Array Index */
prop= RNA_def_property(srna, "data_path", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, "rna_ksPath_RnaPath_get", "rna_ksPath_RnaPath_length", "rna_ksPath_RnaPath_set");
RNA_def_property_ui_text(prop, "Data Path", "Path to property setting");
RNA_def_struct_name_property(srna, prop); // XXX this is the best indicator for now...
+ RNA_def_property_update(prop, NC_SCENE|ND_KEYINGSET|NA_EDITED, NULL);
prop= RNA_def_property(srna, "array_index", PROP_INT, PROP_NONE);
RNA_def_property_ui_text(prop, "RNA Array Index", "Index to the specific setting if applicable");
+ RNA_def_property_update(prop, NC_SCENE|ND_KEYINGSET|NA_EDITED, NULL); // XXX: maybe a bit too noisy
/* Flags */
prop= RNA_def_property(srna, "use_entire_array", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", KSP_FLAG_WHOLE_ARRAY);
RNA_def_property_ui_text(prop, "Entire Array", "When an 'array/vector' type is chosen (Location, Rotation, Color, etc.), entire array is to be used");
+ RNA_def_property_update(prop, NC_SCENE|ND_KEYINGSET|NA_EDITED, NULL); // XXX: maybe a bit too noisy
/* Keyframing Settings */
rna_def_common_keying_flags(srna, 0);
@@ -630,6 +637,7 @@ static void rna_def_keyingset(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Name", "");
RNA_def_struct_ui_icon(srna, ICON_KEY_HLT); // TODO: we need a dedicated icon
RNA_def_struct_name_property(srna, prop);
+ RNA_def_property_update(prop, NC_SCENE|ND_KEYINGSET|NA_RENAME, NULL);
/* KeyingSetInfo (Type Info) for Builtin Sets only */
prop= RNA_def_property(srna, "type_info", PROP_POINTER, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 61f6176fb25..3dc52a5c4e2 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -66,12 +66,16 @@ static void rna_Armature_act_bone_set(PointerRNA *ptr, PointerRNA value)
}
else {
if(value.id.data != arm) {
- /* raise an error! */
- }
- else {
- arm->act_bone= value.data;
- arm->act_bone->flag |= BONE_SELECTED;
+ Object *ob = (Object *)value.id.data;
+
+ if(GS(ob->id.name)!=ID_OB || (ob->data != arm)) {
+ printf("ERROR: armature set active bone - new active doesn't come from this armature\n");
+ return;
+ }
}
+
+ arm->act_bone= value.data;
+ arm->act_bone->flag |= BONE_SELECTED;
}
}
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 606dee0aa8b..69e15482bbb 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -62,6 +62,7 @@ EnumPropertyItem beztriple_keyframe_type_items[] = {
{BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", 0, "Keyframe", ""},
{BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", 0, "Breakdown", ""},
{BEZT_KEYTYPE_EXTREME, "EXTREME", 0, "Extreme", ""},
+ {BEZT_KEYTYPE_JITTER, "JITTER", 0, "Jitter", ""},
{0, NULL, 0, NULL, NULL}};
#ifdef RNA_RUNTIME
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 97da3ab4ad9..836faf1e9a9 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -198,7 +198,7 @@ void RNA_api_image(StructRNA *srna)
func= RNA_def_function(srna, "save_render", "rna_Image_save_render");
RNA_def_function_ui_description(func, "Save image to a specific path using a scenes render settings");
RNA_def_function_flag(func, FUNC_USE_CONTEXT|FUNC_USE_REPORTS);
- parm= RNA_def_string(func, "filepath", "", 0, "", "Save path.");
+ parm= RNA_def_string_file_path(func, "filepath", "", 0, "", "Save path.");
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_pointer(func, "scene", "Scene", "", "Scene to take image parameters from");
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index 8fb23e371d1..04e24615ab2 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -534,7 +534,7 @@ void RNA_api_main(StructRNA *srna)
/*
func= RNA_def_function(srna, "add_image", "rna_Main_add_image");
RNA_def_function_ui_description(func, "Add a new image.");
- parm= RNA_def_string(func, "filepath", "", 0, "", "File path to load image from.");
+ parm= RNA_def_string_file_path(func, "filepath", "", 0, "", "File path to load image from.");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm= RNA_def_pointer(func, "image", "Image", "", "New image.");
RNA_def_function_return(func, parm);
@@ -823,7 +823,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop)
func= RNA_def_function(srna, "load", "rna_Main_images_load");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Load a new image into the main database");
- parm= RNA_def_string(func, "filepath", "File Path", 0, "", "path of the file to load.");
+ parm= RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the file to load.");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
parm= RNA_def_pointer(func, "image", "Image", "", "New image datablock.");
@@ -939,7 +939,7 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop)
func= RNA_def_function(srna, "load", "rna_Main_fonts_load");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Load a new font into the main database");
- parm= RNA_def_string(func, "filepath", "File Path", 0, "", "path of the font to load.");
+ parm= RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the font to load.");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
parm= RNA_def_pointer(func, "vfont", "VectorFont", "", "New font datablock.");
@@ -1099,7 +1099,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop)
func= RNA_def_function(srna, "load", "rna_Main_texts_load");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Add a new text to the main database from a file");
- parm= RNA_def_string(func, "filepath", "Path", FILE_MAXDIR + FILE_MAXFILE, "", "path for the datablock.");
+ parm= RNA_def_string_file_path(func, "filepath", "Path", FILE_MAXDIR + FILE_MAXFILE, "", "path for the datablock.");
RNA_def_property_flag(parm, PROP_REQUIRED);
/* return type */
parm= RNA_def_pointer(func, "text", "Text", "", "New text datablock.");
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 1fabdb8d21c..82e2eb96002 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -1289,7 +1289,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop= RNA_def_property(srna, "invert_grid", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_GRID_INVERT);
- RNA_def_property_ui_text(prop, "Invert", "Invert what is considered object and what is not");
+ RNA_def_property_ui_text(prop, "Invert Grid", "Invert what is considered object and what is not");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop= RNA_def_property(srna, "apply_effector_to_children", PROP_BOOLEAN, PROP_NONE);
@@ -1684,11 +1684,17 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop= RNA_def_property(srna, "grid_resolution", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "grid_res");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_range(prop, 1, 46); /* ~100k particles in a cube */
- RNA_def_property_ui_range(prop, 1, 215, 1, 0); /* ~10M particles in a cube */
+ RNA_def_property_range(prop, 1, 250); /* ~15M particles in a cube (ouch!), but could be very usable in a plane */
+ RNA_def_property_ui_range(prop, 1, 50, 1, 0); /* ~100k particles in a cube */
RNA_def_property_ui_text(prop, "Resolution", "The resolution of the particle grid");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
+ prop= RNA_def_property(srna, "grid_random", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "grid_rand");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Grid Randomness", "Add random offset to the grid locations");
+ RNA_def_property_update(prop, 0, "rna_Particle_reset");
+
/* initial velocity factors */
prop= RNA_def_property(srna, "normal_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "normfac");//optional if prop names are the same
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 3d10b4e4ca2..3bd0b32aa86 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -1205,7 +1205,12 @@ static void rna_def_tool_settings(BlenderRNA *brna)
prop= RNA_def_property(srna, "use_record_with_nla", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", ANIMRECORD_FLAG_WITHNLA);
RNA_def_property_ui_text(prop, "Layered", "Add a new NLA Track + Strip for every loop/pass made over the animation to allow non-destructive tweaking");
-
+
+ prop= RNA_def_property(srna, "use_keyframe_insert_keyingset", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_ONLYKEYINGSET);
+ RNA_def_property_ui_text(prop, "Auto Keyframe Insert Keying Set", "Automatic keyframe insertion using active Keying Set only");
+ RNA_def_property_ui_icon(prop, ICON_KEY_HLT, 0); // XXX: we need a dedicated icon
+
/* UV */
prop= RNA_def_property(srna, "uv_select_mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "uv_selectmode");
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index fbba43e5932..31297d8a478 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -101,9 +101,8 @@ void RNA_api_scene_render(StructRNA *srna)
func= RNA_def_function(srna, "frame_path", "rna_SceneRender_get_frame_path");
RNA_def_function_ui_description(func, "Return the absolute path to the filename to be written for a given frame.");
RNA_def_int(func, "frame", INT_MIN, INT_MIN, INT_MAX, "", "Frame number to use, if unset the current frame will be used.", MINAFRAME, MAXFRAME);
- parm= RNA_def_string(func, "filepath", "", FILE_MAX, "File Path", "the resulting filepath from the scenes render settings.");
+ parm= RNA_def_string_file_path(func, "filepath", "", FILE_MAX, "File Path", "the resulting filepath from the scenes render settings.");
RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */
- RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */
RNA_def_function_output(func, parm);
}
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index f3f8db6fb39..02eadbcdaad 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -46,12 +46,12 @@ EnumPropertyItem region_type_items[] = {
#include "ED_screen.h"
-#ifdef RNA_RUNTIME
-
-
#include "WM_api.h"
#include "WM_types.h"
+#ifdef RNA_RUNTIME
+
+
static void rna_Screen_scene_set(PointerRNA *ptr, PointerRNA value)
{
bScreen *sc= (bScreen*)ptr->data;
@@ -74,6 +74,15 @@ static void rna_Screen_scene_update(bContext *C, PointerRNA *ptr)
}
}
+static void rna_Screen_redraw_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bScreen *screen= (bScreen*)ptr->data;
+
+ /* the settings for this are currently only available from a menu in the TimeLine, hence refresh=SPACE_TIME */
+ ED_screen_animation_timer_update(screen, screen->redraws_flag, SPACE_TIME);
+}
+
+
static int rna_Screen_is_animation_playing_get(PointerRNA *ptr)
{
bScreen *sc= (bScreen*)ptr->data;
@@ -189,6 +198,7 @@ static void rna_def_screen(BlenderRNA *brna)
RNA_def_struct_ui_text(srna, "Screen", "Screen datablock, defining the layout of areas in a window");
RNA_def_struct_ui_icon(srna, ICON_SPLITSCREEN);
+ /* pointers */
prop= RNA_def_property(srna, "scene", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE|PROP_NEVER_NULL);
RNA_def_property_pointer_funcs(prop, NULL, "rna_Screen_scene_set", NULL, NULL);
@@ -196,11 +206,13 @@ static void rna_def_screen(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, 0, "rna_Screen_scene_update");
+ /* collections */
prop= RNA_def_property(srna, "areas", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "areabase", NULL);
RNA_def_property_struct_type(prop, "Area");
RNA_def_property_ui_text(prop, "Areas", "Areas the screen is subdivided into");
-
+
+ /* readonly status indicators */
prop= RNA_def_property(srna, "is_animation_playing", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Screen_is_animation_playing_get", NULL);
@@ -210,6 +222,42 @@ static void rna_def_screen(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Screen_fullscreen_get", NULL);
RNA_def_property_ui_text(prop, "Fullscreen", "An area is maximised, filling this screen");
+
+ /* Define Anim Playback Areas */
+ prop= RNA_def_property(srna, "use_play_top_left_3d_editor", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_REGION);
+ RNA_def_property_ui_text(prop, "Top-Left 3D Editor", "");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_Screen_redraw_update");
+
+ prop= RNA_def_property(srna, "use_play_3d_editors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_ALL_3D_WIN);
+ RNA_def_property_ui_text(prop, "All 3D View Editors", "");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_Screen_redraw_update");
+
+ prop= RNA_def_property(srna, "use_play_animation_editors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_ALL_ANIM_WIN);
+ RNA_def_property_ui_text(prop, "Animation Editors", "");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_Screen_redraw_update");
+
+ prop= RNA_def_property(srna, "use_play_properties_editors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_ALL_BUTS_WIN);
+ RNA_def_property_ui_text(prop, "Property Editors", "");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_Screen_redraw_update");
+
+ prop= RNA_def_property(srna, "use_play_image_editors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_ALL_IMAGE_WIN);
+ RNA_def_property_ui_text(prop, "Image Editors", "");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_Screen_redraw_update");
+
+ prop= RNA_def_property(srna, "use_play_sequence_editors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_SEQ);
+ RNA_def_property_ui_text(prop, "Sequencer Editors", "");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_Screen_redraw_update");
+
+ prop= RNA_def_property(srna, "use_play_node_editors", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_NODES);
+ RNA_def_property_ui_text(prop, "Node Editors", "");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_Screen_redraw_update");
}
void RNA_def_screen(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 8b3734a7c46..45622f500df 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -630,16 +630,6 @@ static void rna_ConsoleLine_cursor_index_range(PointerRNA *ptr, int *min, int *m
*max= ci->len;
}
-/* Space Time */
-
-static void rna_SpaceTime_redraw_update(Main *bmain, Scene *scene, PointerRNA *ptr)
-{
- SpaceTime *st= (SpaceTime*)ptr->data;
- bScreen *screen= (bScreen*)ptr->id.data;
-
- ED_screen_animation_timer_update(screen, st->redraws, SPACE_TIME);
-}
-
/* Space Dopesheet */
static void rna_SpaceDopeSheetEditor_action_set(PointerRNA *ptr, PointerRNA value)
@@ -1933,43 +1923,7 @@ static void rna_def_space_time(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "SpaceTime");
RNA_def_struct_ui_text(srna, "Space Timeline Editor", "Timeline editor space data");
- /* Define Anim Playback Areas */
- prop= RNA_def_property(srna, "use_play_top_left_3d_editor", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "redraws", TIME_REGION);
- RNA_def_property_ui_text(prop, "Top-Left 3D Editor", "");
- RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update");
-
- prop= RNA_def_property(srna, "use_play_3d_editors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "redraws", TIME_ALL_3D_WIN);
- RNA_def_property_ui_text(prop, "All 3D View Editors", "");
- RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update");
-
- prop= RNA_def_property(srna, "use_play_animation_editors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "redraws", TIME_ALL_ANIM_WIN);
- RNA_def_property_ui_text(prop, "Animation Editors", "");
- RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update");
-
- prop= RNA_def_property(srna, "use_play_properties_editors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "redraws", TIME_ALL_BUTS_WIN);
- RNA_def_property_ui_text(prop, "Property Editors", "");
- RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update");
-
- prop= RNA_def_property(srna, "use_play_image_editors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "redraws", TIME_ALL_IMAGE_WIN);
- RNA_def_property_ui_text(prop, "Image Editors", "");
- RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update");
-
- prop= RNA_def_property(srna, "use_play_sequence_editors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "redraws", TIME_SEQ);
- RNA_def_property_ui_text(prop, "Sequencer Editors", "");
- RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update");
-
- prop= RNA_def_property(srna, "use_play_node_editors", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "redraws", TIME_NODES);
- RNA_def_property_ui_text(prop, "Node Editors", "");
- RNA_def_property_update(prop, NC_SPACE|ND_SPACE_TIME, "rna_SpaceTime_redraw_update");
-
- /* Other options */
+ /* view settings */
prop= RNA_def_property(srna, "show_only_selected", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", TIME_ONLYACTSEL);
RNA_def_property_ui_text(prop, "Only Selected channels", "Show keyframes for active Object and/or its selected channels only");
@@ -2267,7 +2221,13 @@ static void rna_def_space_node(BlenderRNA *brna)
{SNODE_TEX_WORLD, "WORLD", ICON_WORLD_DATA, "World", "Edit texture nodes from World"},
{SNODE_TEX_BRUSH, "BRUSH", ICON_BRUSH_DATA, "Brush", "Edit texture nodes from Brush"},
{0, NULL, 0, NULL, NULL}};
-
+
+ static EnumPropertyItem backdrop_channels_items[] = {
+ {0, "COLOR", ICON_IMAGE_RGB, "Color", "Draw image with RGB colors"},
+ {SNODE_USE_ALPHA, "COLOR_ALPHA", ICON_IMAGE_RGB_ALPHA, "Color and Alpha", "Draw image with RGB colors and alpha transparency"},
+ {SNODE_SHOW_ALPHA, "ALPHA", ICON_IMAGE_ALPHA, "Alpha", "Draw alpha transparency channel"},
+ {0, NULL, 0, NULL, NULL}};
+
srna= RNA_def_struct(brna, "SpaceNodeEditor", "Space");
RNA_def_struct_sdna(srna, "SpaceNode");
RNA_def_struct_ui_text(srna, "Space Node Editor", "Node editor space data");
@@ -2305,6 +2265,8 @@ static void rna_def_space_node(BlenderRNA *brna)
prop= RNA_def_property(srna, "backdrop_zoom", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "zoom");
+ RNA_def_property_range(prop, 0.01f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.01, 100, 1, 2);
RNA_def_property_ui_text(prop, "Backdrop Zoom", "Backdrop zoom factor");
RNA_def_property_update(prop, NC_SPACE|ND_SPACE_NODE_VIEW, NULL);
@@ -2317,6 +2279,12 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "yof");
RNA_def_property_ui_text(prop, "Backdrop Y", "Backdrop Y offset");
RNA_def_property_update(prop, NC_SPACE|ND_SPACE_NODE_VIEW, NULL);
+
+ prop= RNA_def_property(srna, "backdrop_channels", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
+ RNA_def_property_enum_items(prop, backdrop_channels_items);
+ RNA_def_property_ui_text(prop, "Draw Channels", "Channels of the image to draw");
+ RNA_def_property_update(prop, NC_SPACE|ND_SPACE_NODE_VIEW, NULL);
}
static void rna_def_space_logic(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 90124e5f376..e080b735048 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2185,10 +2185,6 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_INSERTAVAIL);
RNA_def_property_ui_text(prop, "Auto Keyframe Insert Available", "Automatic keyframe insertion in available curves");
- prop= RNA_def_property(srna, "use_keyframe_insert_keyingset", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_ONLYKEYINGSET);
- RNA_def_property_ui_text(prop, "Auto Keyframe Insert Keying Set", "Automatic keyframe insertion using active Keying Set");
-
/* keyframing settings */
prop= RNA_def_property(srna, "use_keyframe_insert_needed", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "autokey_flag", AUTOKEY_FLAG_INSERTNEEDED);
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index d06ec92d4df..ac25987871d 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -34,6 +34,7 @@
#include "DNA_armature_types.h"
#include "DNA_object_types.h"
+#include "DNA_mesh_types.h"
#include "BLI_utildefines.h"
@@ -161,6 +162,19 @@ static void deformMatricesEM(
if(!derivedData) dm->release(dm);
}
+static void deformMatrices(ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData*) md;
+ DerivedMesh *dm = derivedData;
+
+ if(!derivedData) dm = CDDM_from_mesh((Mesh*)ob->data, ob);
+
+ armature_deform_verts(amd->object, ob, dm, vertexCos, defMats, numVerts,
+ amd->deformflag, NULL, amd->defgrp_name);
+
+ if(!derivedData) dm->release(dm);
+}
ModifierTypeInfo modifierType_Armature = {
/* name */ "Armature",
@@ -172,6 +186,7 @@ ModifierTypeInfo modifierType_Armature = {
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ deformMatrices,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ deformMatricesEM,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index f6d497b763f..1fdfe6c192c 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -807,6 +807,7 @@ ModifierTypeInfo modifierType_Array = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index e775d7e4262..effc376943e 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -129,6 +129,7 @@ ModifierTypeInfo modifierType_Bevel = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index 112618a2bd6..c40d6cfb79e 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -139,6 +139,7 @@ ModifierTypeInfo modifierType_Boolean = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 1588d1f44d5..704caf0aff8 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -287,6 +287,7 @@ ModifierTypeInfo modifierType_Build = {
| eModifierTypeFlag_AcceptsCVs,
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index c3400a6541d..17c2ec40b7e 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -619,6 +619,7 @@ ModifierTypeInfo modifierType_Cast = {
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index a0566d32c73..1cb46c0992f 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -196,6 +196,7 @@ ModifierTypeInfo modifierType_Cloth = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index bf324030424..8decb460d6a 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -243,6 +243,7 @@ ModifierTypeInfo modifierType_Collision = {
/* copyData */ 0,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index b1a5965cbe3..c4e41941acc 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -142,6 +142,7 @@ ModifierTypeInfo modifierType_Curve = {
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 7903e1adb47..2f1723cf9bb 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -197,6 +197,7 @@ ModifierTypeInfo modifierType_Decimate = {
/* flags */ eModifierTypeFlag_AcceptsMesh,
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index 931865409cb..919814edf59 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -357,6 +357,7 @@ ModifierTypeInfo modifierType_Displace = {
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 105e4777e87..56138552000 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -1278,6 +1278,7 @@ ModifierTypeInfo modifierType_EdgeSplit = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index e6a3dc49668..a0765b56808 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -895,6 +895,7 @@ ModifierTypeInfo modifierType_Explode = {
/* flags */ eModifierTypeFlag_AcceptsMesh,
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c
index bbb88ba09e3..19111b0cafc 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim.c
@@ -142,6 +142,7 @@ ModifierTypeInfo modifierType_Fluidsim = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index adf19882419..79493d2c549 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -284,6 +284,7 @@ ModifierTypeInfo modifierType_Hook = {
| eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 136998dbc78..c5fb87c8ffc 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -137,6 +137,7 @@ ModifierTypeInfo modifierType_Lattice = {
| eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index 05a7bbecaea..b2f2c86c46d 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -399,6 +399,7 @@ ModifierTypeInfo modifierType_Mask = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 6df57bf372e..61e7f950e0f 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -445,6 +445,7 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index c07bd10d6fa..9546bf1300b 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -338,6 +338,7 @@ ModifierTypeInfo modifierType_Mirror = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index 96dcde12180..10b135aaa77 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -109,6 +109,7 @@ ModifierTypeInfo modifierType_Multires = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c
index cc27d3b659b..c08335d638a 100644
--- a/source/blender/modifiers/intern/MOD_none.c
+++ b/source/blender/modifiers/intern/MOD_none.c
@@ -59,6 +59,7 @@ ModifierTypeInfo modifierType_None = {
/* copyData */ 0,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index f0e7699c292..c36581d9317 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -330,6 +330,7 @@ ModifierTypeInfo modifierType_ParticleInstance = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 9b77a904887..c7638afbbcc 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -229,6 +229,7 @@ ModifierTypeInfo modifierType_ParticleSystem = {
/* copyData */ copyData,
/* deformVerts */ deformVerts,
/* deformVertsEM */ 0 /* deformVertsEM */ ,
+ /* deformMatrices */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
/* applyModifierEM */ 0,
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index 96e1c6c0d01..7e8fad2801e 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -884,6 +884,7 @@ ModifierTypeInfo modifierType_Screw = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index 5466d240dd2..e03783e8eeb 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -64,6 +64,27 @@ static void deformVerts(ModifierData *md, Object *ob,
}
}
+static void deformMatrices(ModifierData *md, Object *ob, DerivedMesh *derivedData,
+ float (*vertexCos)[3], float (*defMats)[3][3], int numVerts)
+{
+ Key *key= ob_get_key(ob);
+ KeyBlock *kb= ob_get_keyblock(ob);
+ float scale[3][3];
+ int a;
+
+ (void)vertexCos; /* unused */
+
+ if(kb && kb->totelem==numVerts && kb!=key->refkey) {
+ if(ob->shapeflag & OB_SHAPE_LOCK) scale_m3_fl(scale, 1);
+ else scale_m3_fl(scale, kb->curval);
+
+ for(a=0; a<numVerts; a++)
+ copy_m3_m3(defMats[a], scale);
+ }
+
+ deformVerts(md, ob, derivedData, vertexCos, numVerts, 0, 0);
+}
+
static void deformVertsEM(ModifierData *md, Object *ob,
struct EditMesh *UNUSED(editData),
DerivedMesh *derivedData,
@@ -87,7 +108,7 @@ static void deformMatricesEM(ModifierData *UNUSED(md), Object *ob,
KeyBlock *kb= ob_get_keyblock(ob);
float scale[3][3];
int a;
-
+
(void)vertexCos; /* unused */
if(kb && kb->totelem==numVerts && kb!=key->refkey) {
@@ -98,7 +119,6 @@ static void deformMatricesEM(ModifierData *UNUSED(md), Object *ob,
}
}
-
ModifierTypeInfo modifierType_ShapeKey = {
/* name */ "ShapeKey",
/* structName */ "ShapeKeyModifierData",
@@ -109,6 +129,7 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* copyData */ 0,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ deformMatrices,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ deformMatricesEM,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index a7de27c0bf6..56a5b4b8577 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -167,6 +167,7 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 003b206f9bc..1c3e40a4193 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -375,6 +375,7 @@ ModifierTypeInfo modifierType_SimpleDeform = {
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index 2edfee7e6e4..0227d2008e5 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -154,6 +154,7 @@ ModifierTypeInfo modifierType_Smoke = {
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index bc04b253cec..7761995a419 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -256,6 +256,7 @@ ModifierTypeInfo modifierType_Smooth = {
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index 24af10fde2b..7322628267c 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -68,6 +68,7 @@ ModifierTypeInfo modifierType_Softbody = {
/* copyData */ 0,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 6485076bde4..4faf955b953 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -651,6 +651,7 @@ ModifierTypeInfo modifierType_Solidify = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 1238c891f33..4ba139305d8 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -133,6 +133,7 @@ ModifierTypeInfo modifierType_Subsurf = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index d68ba84d58b..8d6f6954e18 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -173,6 +173,7 @@ ModifierTypeInfo modifierType_Surface = {
/* copyData */ 0,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 3f43924d6a2..8eaf0d5fbcb 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -413,6 +413,7 @@ ModifierTypeInfo modifierType_UVProject = {
/* copyData */ copyData,
/* deformVerts */ 0,
+ /* deformMatrices */ 0,
/* deformVertsEM */ 0,
/* deformMatricesEM */ 0,
/* applyModifier */ applyModifier,
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 69c9f1165ce..dae9fc471cd 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -452,6 +452,7 @@ ModifierTypeInfo modifierType_Wave = {
| eModifierTypeFlag_SupportsEditmode,
/* copyData */ copyData,
/* deformVerts */ deformVerts,
+ /* deformMatrices */ 0,
/* deformVertsEM */ deformVertsEM,
/* deformMatricesEM */ 0,
/* applyModifier */ 0,
diff --git a/source/blender/python/generic/mathutils.c b/source/blender/python/generic/mathutils.c
index 5b75552ca8d..b3bff5cf67f 100644
--- a/source/blender/python/generic/mathutils.c
+++ b/source/blender/python/generic/mathutils.c
@@ -37,6 +37,8 @@
* - Mathutils.Slerp --> quat.slerp(other, fac)
* - Mathutils.Rand: removed, use pythons random module
* - Mathutils.RotationMatrix(angle, size, axis_flag, axis) --> Mathutils.RotationMatrix(angle, size, axis); merge axis & axis_flag args
+ * - Mathutils.OrthoProjectionMatrix(plane, size, axis) --> Mathutils.OrthoProjectionMatrix(axis, size); merge axis & plane args
+ * - Mathutils.ShearMatrix(plane, factor, size) --> Mathutils.ShearMatrix(plane, size, factor); swap size & factor args, match other constructors.
* - Matrix.scalePart --> Matrix.scale_part
* - Matrix.translationPart --> Matrix.translation_part
* - Matrix.rotationPart --> Matrix.rotation_part
@@ -45,10 +47,24 @@
* - toEuler --> to_euler
* - toQuat --> to_quat
* - Vector.toTrackQuat --> Vector.to_track_quat
+ * - Vector.rotate(axis, angle) --> rotate(other), where other can be Euler/Quaternion/Matrix.
* - Quaternion * Quaternion --> cross product (not dot product)
* - Euler.rotate(angle, axis) --> Euler.rotate_axis(axis, angle)
* - Euler.unique() *removed*, not a standard function only toggled different rotations.
- *
+ * - Matrix.rotation_part() -> to_3x3()
+ * - Matrix.scale_part() -> to_scale()
+ * - Matrix.translation_part() -> to_translation()
+ * - Matrix.resize4x4() -> resize_4x4()
+ * - Euler.to_quat() -> to_quaternion()
+ * - Matrix.to_quat() -> to_quaternion()
+ * resizing nolonger returns the resized value.
+ * - Vector.resize2D -> resize_2d
+ * - Vector.resize3D -> resize_3d
+ * - Vector.resize4D -> resize_4d
+ * added new functions.
+ * - Vector.to_2d()
+ * - Vector.to_3d()
+ * - Vector.to_4d()
* moved into class functions.
* - Mathutils.RotationMatrix -> mathutils.Matrix.Rotation
* - Mathutils.ScaleMatrix -> mathutils.Matrix.Scale
@@ -80,11 +96,12 @@
//-------------------------DOC STRINGS ---------------------------
static char M_Mathutils_doc[] =
-"This module provides access to matrices, eulers, quaternions and vectors.";
-
+"This module provides access to matrices, eulers, quaternions and vectors."
+;
static int mathutils_array_parse_fast(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix)
{
PyObject *value_fast= NULL;
+ PyObject *item;
int i, size;
@@ -106,8 +123,8 @@ static int mathutils_array_parse_fast(float *array, int array_min, int array_max
i= size;
do {
i--;
- if(((array[i]= PyFloat_AsDouble(PySequence_Fast_GET_ITEM(value_fast, i))) == -1.0) && PyErr_Occurred()) {
- PyErr_Format(PyExc_ValueError, "%.200s: sequence index %d is not a float", error_prefix, i);
+ if(((array[i]= PyFloat_AsDouble((item= PySequence_Fast_GET_ITEM(value_fast, i)))) == -1.0) && PyErr_Occurred()) {
+ PyErr_Format(PyExc_ValueError, "%.200s: sequence index %d expected a number, found '%.200s' type, ", error_prefix, i, Py_TYPE(item)->tp_name);
Py_DECREF(value_fast);
return -1;
}
@@ -148,6 +165,49 @@ int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *
}
}
+int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix)
+{
+ if(EulerObject_Check(value)) {
+ if(!BaseMath_ReadCallback((BaseMathObject *)value)) {
+ return -1;
+ }
+ else {
+ eulO_to_mat3(rmat, ((EulerObject *)value)->eul, ((EulerObject *)value)->order);
+ return 0;
+ }
+ }
+ else if (QuaternionObject_Check(value)) {
+ if(!BaseMath_ReadCallback((BaseMathObject *)value)) {
+ return -1;
+ }
+ else {
+ float tquat[4];
+ normalize_qt_qt(tquat, ((QuaternionObject *)value)->quat);
+ quat_to_mat3(rmat, tquat);
+ return 0;
+ }
+ }
+ else if (MatrixObject_Check(value)) {
+ if(!BaseMath_ReadCallback((BaseMathObject *)value)) {
+ return -1;
+ }
+ else if(((MatrixObject *)value)->colSize < 3 || ((MatrixObject *)value)->rowSize < 3) {
+ PyErr_Format(PyExc_ValueError, "%.200s: matrix must have minimum 3x3 dimensions", error_prefix);
+ return -1;
+ }
+ else {
+ matrix_as_3x3(rmat, (MatrixObject *)value);
+ normalize_m3(rmat);
+ return 0;
+ }
+ }
+ else {
+ PyErr_Format(PyExc_TypeError, "%.200s: expected a Euler, Quaternion or Matrix type, found %.200s", error_prefix, Py_TYPE(value)->tp_name);
+ return -1;
+ }
+}
+
+
//----------------------------------MATRIX FUNCTIONS--------------------
diff --git a/source/blender/python/generic/mathutils.h b/source/blender/python/generic/mathutils.h
index 29ef52c77b0..07342f8144b 100644
--- a/source/blender/python/generic/mathutils.h
+++ b/source/blender/python/generic/mathutils.h
@@ -100,5 +100,6 @@ int _BaseMathObject_WriteIndexCallback(BaseMathObject *self, int index);
/* utility func */
int mathutils_array_parse(float *array, int array_min, int array_max, PyObject *value, const char *error_prefix);
+int mathutils_any_to_rotmat(float rmat[3][3], PyObject *value, const char *error_prefix);
#endif /* MATHUTILS_H */
diff --git a/source/blender/python/generic/mathutils_color.c b/source/blender/python/generic/mathutils_color.c
index b8dd059fe3c..af4742e74c6 100644
--- a/source/blender/python/generic/mathutils_color.c
+++ b/source/blender/python/generic/mathutils_color.c
@@ -88,8 +88,8 @@ static char Color_copy_doc[] =
" :return: A copy of the color.\n"
" :rtype: :class:`Color`\n"
"\n"
-" .. note:: use this to get a copy of a wrapped color with no reference to the original data.\n";
-
+" .. note:: use this to get a copy of a wrapped color with no reference to the original data.\n"
+;
static PyObject *Color_copy(ColorObject *self)
{
if(!BaseMath_ReadCallback(self))
@@ -118,48 +118,40 @@ static PyObject *Color_repr(ColorObject * self)
//------------------------tp_richcmpr
//returns -1 execption, 0 false, 1 true
-static PyObject* Color_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+static PyObject* Color_richcmpr(PyObject *a, PyObject *b, int op)
{
- ColorObject *colA = NULL, *colB = NULL;
- int result = 0;
+ PyObject *res;
+ int ok= -1; /* zero is true */
- if(ColorObject_Check(objectA)) {
- colA = (ColorObject*)objectA;
- if(!BaseMath_ReadCallback(colA))
- return NULL;
- }
- if(ColorObject_Check(objectB)) {
- colB = (ColorObject*)objectB;
- if(!BaseMath_ReadCallback(colB))
+ if (ColorObject_Check(a) && ColorObject_Check(b)) {
+ ColorObject *colA= (ColorObject*)a;
+ ColorObject *colB= (ColorObject*)b;
+
+ if(!BaseMath_ReadCallback(colA) || !BaseMath_ReadCallback(colB))
return NULL;
- }
- if (!colA || !colB){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
+ ok= EXPP_VectorsAreEqual(colA->col, colB->col, COLOR_SIZE, 1) ? 0 : -1;
}
- colA = (ColorObject*)objectA;
- colB = (ColorObject*)objectB;
-
- switch (comparison_type){
- case Py_EQ:
- result = EXPP_VectorsAreEqual(colA->col, colB->col, COLOR_SIZE, 1);
- break;
- case Py_NE:
- result = !EXPP_VectorsAreEqual(colA->col, colB->col, COLOR_SIZE, 1);
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
- }
- if (result == 1){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
+
+ switch (op) {
+ case Py_NE:
+ ok = !ok; /* pass through */
+ case Py_EQ:
+ res = ok ? Py_False : Py_True;
+ break;
+
+ case Py_LT:
+ case Py_LE:
+ case Py_GT:
+ case Py_GE:
+ res = Py_NotImplemented;
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
}
+
+ return Py_INCREF(res), res;
}
//---------------------SEQUENCE PROTOCOLS------------------------
@@ -280,7 +272,7 @@ static PyObject *Color_subscript(ColorObject *self, PyObject *item)
return NULL;
if (slicelength <= 0) {
- return PyList_New(0);
+ return PyTuple_New(0);
}
else if (step == 1) {
return Color_slice(self, start, stop);
@@ -461,8 +453,8 @@ static struct PyMethodDef Color_methods[] = {
//------------------PY_OBECT DEFINITION--------------------------
static char color_doc[] =
-"This object gives access to Colors in Blender.";
-
+"This object gives access to Colors in Blender."
+;
PyTypeObject color_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"mathutils.Color", //tp_name
diff --git a/source/blender/python/generic/mathutils_euler.c b/source/blender/python/generic/mathutils_euler.c
index 034a51fb814..8792b154ca6 100644
--- a/source/blender/python/generic/mathutils_euler.c
+++ b/source/blender/python/generic/mathutils_euler.c
@@ -20,7 +20,7 @@
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
- *
+ *
* Contributor(s): Joseph Gilbert
*
* ***** END GPL LICENSE BLOCK *****
@@ -44,7 +44,7 @@
static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *seq= NULL;
- char *order_str= NULL;
+ const char *order_str= NULL;
float eul[EULER_SIZE]= {0.0f, 0.0f, 0.0f};
short order= EULER_ORDER_XYZ;
@@ -72,6 +72,13 @@ static PyObject *Euler_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return newEulerObject(eul, order, Py_NEW, type);
}
+/* internal use, assuem read callback is done */
+static const char *euler_order_str(EulerObject *self)
+{
+ static const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
+ return order[self->order-EULER_ORDER_XYZ];
+}
+
short euler_order_from_string(const char *str, const char *error_prefix)
{
if((str[0] && str[1] && str[2] && str[3]=='\0')) {
@@ -114,67 +121,59 @@ static PyObject *Euler_ToTupleExt(EulerObject *self, int ndigits)
//-----------------------------METHODS----------------------------
//return a quaternion representation of the euler
-static char Euler_ToQuat_doc[] =
-".. method:: to_quat()\n"
+static char Euler_to_quaternion_doc[] =
+".. method:: to_quaternion()\n"
"\n"
" Return a quaternion representation of the euler.\n"
"\n"
" :return: Quaternion representation of the euler.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Euler_ToQuat(EulerObject * self)
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Euler_to_quaternion(EulerObject * self)
{
float quat[4];
if(!BaseMath_ReadCallback(self))
return NULL;
- if(self->order==EULER_ORDER_XYZ) eul_to_quat(quat, self->eul);
- else eulO_to_quat(quat, self->eul, self->order);
+ eulO_to_quat(quat, self->eul, self->order);
return newQuaternionObject(quat, Py_NEW, NULL);
}
//return a matrix representation of the euler
-static char Euler_ToMatrix_doc[] =
+static char Euler_to_matrix_doc[] =
".. method:: to_matrix()\n"
"\n"
" Return a matrix representation of the euler.\n"
"\n"
" :return: A 3x3 roation matrix representation of the euler.\n"
-" :rtype: :class:`Matrix`\n";
-
-static PyObject *Euler_ToMatrix(EulerObject * self)
+" :rtype: :class:`Matrix`\n"
+;
+static PyObject *Euler_to_matrix(EulerObject * self)
{
- float mat[9] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
+ float mat[9];
if(!BaseMath_ReadCallback(self))
return NULL;
- if(self->order==EULER_ORDER_XYZ) eul_to_mat3((float (*)[3])mat, self->eul);
- else eulO_to_mat3((float (*)[3])mat, self->eul, self->order);
+ eulO_to_mat3((float (*)[3])mat, self->eul, self->order);
return newMatrixObject(mat, 3, 3 , Py_NEW, NULL);
}
//sets the euler to 0,0,0
-static char Euler_Zero_doc[] =
+static char Euler_zero_doc[] =
".. method:: zero()\n"
"\n"
" Set all values to zero.\n"
-"\n"
-" :return: an instance of itself\n"
-" :rtype: :class:`Euler`\n";
-
-static PyObject *Euler_Zero(EulerObject * self)
+;
+static PyObject *Euler_zero(EulerObject * self)
{
- self->eul[0] = 0.0;
- self->eul[1] = 0.0;
- self->eul[2] = 0.0;
+ zero_v3(self->eul);
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
+ Py_RETURN_NONE;
}
static char Euler_rotate_axis_doc[] =
@@ -186,13 +185,11 @@ static char Euler_rotate_axis_doc[] =
" :type axis: string\n"
" :arg angle: angle in radians.\n"
" :type angle: float\n"
-" :return: an instance of itself\n"
-" :rtype: :class:`Euler`";
-
+;
static PyObject *Euler_rotate_axis(EulerObject * self, PyObject *args)
{
float angle = 0.0f;
- char *axis;
+ const char *axis;
if(!PyArg_ParseTuple(args, "sf:rotate", &axis, &angle)){
PyErr_SetString(PyExc_TypeError, "euler.rotate(): expected angle (float) and axis (x,y,z)");
@@ -206,46 +203,66 @@ static PyObject *Euler_rotate_axis(EulerObject * self, PyObject *args)
if(!BaseMath_ReadCallback(self))
return NULL;
- if(self->order == EULER_ORDER_XYZ) rotate_eul(self->eul, *axis, angle);
- else rotate_eulO(self->eul, self->order, *axis, angle);
+
+ rotate_eulO(self->eul, self->order, *axis, angle);
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
+
+ Py_RETURN_NONE;
+}
+
+static char Euler_rotate_doc[] =
+".. method:: rotate(other)\n"
+"\n"
+" Rotates the euler a by another mathutils value.\n"
+"\n"
+" :arg other: rotation component of mathutils value\n"
+" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
+;
+static PyObject *Euler_rotate(EulerObject * self, PyObject *value)
+{
+ float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
+
+ if(!BaseMath_ReadCallback(self))
+ return NULL;
+
+ if(mathutils_any_to_rotmat(other_rmat, value, "euler.rotate(value)") == -1)
+ return NULL;
+
+ eulO_to_mat3(self_rmat, self->eul, self->order);
+ mul_m3_m3m3(rmat, self_rmat, other_rmat);
+
+ mat3_to_compatible_eulO(self->eul, self->eul, self->order, rmat);
+
+ (void)BaseMath_WriteCallback(self);
+ Py_RETURN_NONE;
}
-static char Euler_MakeCompatible_doc[] =
+static char Euler_make_compatible_doc[] =
".. method:: make_compatible(other)\n"
"\n"
" Make this euler compatible with another, so interpolating between them works as intended.\n"
"\n"
" :arg other: make compatible with this rotation.\n"
" :type other: :class:`Euler`\n"
-" :return: an instance of itself.\n"
-" :rtype: :class:`Euler`\n"
"\n"
-" .. note:: the order of eulers must match or an exception is raised.\n";
-
-static PyObject *Euler_MakeCompatible(EulerObject * self, EulerObject *value)
+" .. note:: the rotation order is not taken into account for this function.\n"
+;
+static PyObject *Euler_make_compatible(EulerObject * self, PyObject *value)
{
- if(!EulerObject_Check(value)) {
- PyErr_SetString(PyExc_TypeError, "euler.make_compatible(euler): expected a single euler argument");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+ float teul[EULER_SIZE];
+
+ if(!BaseMath_ReadCallback(self))
return NULL;
- if(self->order != value->order) {
- PyErr_SetString(PyExc_ValueError, "euler.make_compatible(euler): rotation orders don't match");
+ if(mathutils_array_parse(teul, EULER_SIZE, EULER_SIZE, value, "euler.make_compatible(other), invalid 'other' arg") == -1)
return NULL;
- }
- compatible_eul(self->eul, value->eul);
+ compatible_eul(self->eul, teul);
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
+
+ Py_RETURN_NONE;
}
//----------------------------Euler.rotate()-----------------------
@@ -259,8 +276,8 @@ static char Euler_copy_doc[] =
" :return: A copy of the euler.\n"
" :rtype: :class:`Euler`\n"
"\n"
-" .. note:: use this to get a copy of a wrapped euler with no reference to the original data.\n";
-
+" .. note:: use this to get a copy of a wrapped euler with no reference to the original data.\n"
+;
static PyObject *Euler_copy(EulerObject *self)
{
if(!BaseMath_ReadCallback(self))
@@ -275,62 +292,52 @@ static PyObject *Euler_copy(EulerObject *self)
static PyObject *Euler_repr(EulerObject * self)
{
PyObject *ret, *tuple;
-
+
if(!BaseMath_ReadCallback(self))
return NULL;
tuple= Euler_ToTupleExt(self, -1);
- ret= PyUnicode_FromFormat("Euler(%R)", tuple);
+ ret= PyUnicode_FromFormat("Euler(%R, '%s')", tuple, euler_order_str(self));
Py_DECREF(tuple);
return ret;
}
-//------------------------tp_richcmpr
-//returns -1 execption, 0 false, 1 true
-static PyObject* Euler_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+static PyObject* Euler_richcmpr(PyObject *a, PyObject *b, int op)
{
- EulerObject *eulA = NULL, *eulB = NULL;
- int result = 0;
+ PyObject *res;
+ int ok= -1; /* zero is true */
- if(EulerObject_Check(objectA)) {
- eulA = (EulerObject*)objectA;
- if(!BaseMath_ReadCallback(eulA))
- return NULL;
- }
- if(EulerObject_Check(objectB)) {
- eulB = (EulerObject*)objectB;
- if(!BaseMath_ReadCallback(eulB))
+ if (EulerObject_Check(a) && EulerObject_Check(b)) {
+ EulerObject *eulA= (EulerObject*)a;
+ EulerObject *eulB= (EulerObject*)b;
+
+ if(!BaseMath_ReadCallback(eulA) || !BaseMath_ReadCallback(eulB))
return NULL;
- }
- if (!eulA || !eulB){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
- }
- eulA = (EulerObject*)objectA;
- eulB = (EulerObject*)objectB;
-
- switch (comparison_type){
- case Py_EQ:
- result = EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1);
- break;
- case Py_NE:
- result = !EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1);
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
+ ok= ((eulA->order == eulB->order) && EXPP_VectorsAreEqual(eulA->eul, eulB->eul, EULER_SIZE, 1)) ? 0 : -1;
}
- if (result == 1){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
+
+ switch (op) {
+ case Py_NE:
+ ok = !ok; /* pass through */
+ case Py_EQ:
+ res = ok ? Py_False : Py_True;
+ break;
+
+ case Py_LT:
+ case Py_LE:
+ case Py_GT:
+ case Py_GE:
+ res = Py_NotImplemented;
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
}
+
+ return Py_INCREF(res), res;
}
//---------------------SEQUENCE PROTOCOLS------------------------
@@ -345,7 +352,7 @@ static int Euler_len(EulerObject *UNUSED(self))
static PyObject *Euler_item(EulerObject * self, int i)
{
if(i<0) i= EULER_SIZE-i;
-
+
if(i < 0 || i >= EULER_SIZE) {
PyErr_SetString(PyExc_IndexError, "euler[attribute]: array index out of range");
return NULL;
@@ -369,12 +376,12 @@ static int Euler_ass_item(EulerObject * self, int i, PyObject *value)
}
if(i<0) i= EULER_SIZE-i;
-
+
if(i < 0 || i >= EULER_SIZE){
PyErr_SetString(PyExc_IndexError, "euler[attribute] = x: array assignment index out of range");
return -1;
}
-
+
self->eul[i] = f;
if(!BaseMath_WriteIndexCallback(self, i))
@@ -451,7 +458,7 @@ static PyObject *Euler_subscript(EulerObject *self, PyObject *item)
return NULL;
if (slicelength <= 0) {
- return PyList_New(0);
+ return PyTuple_New(0);
}
else if (step == 1) {
return Euler_slice(self, start, stop);
@@ -533,17 +540,15 @@ static int Euler_setAxis(EulerObject *self, PyObject *value, void *type)
/* rotation order */
static PyObject *Euler_getOrder(EulerObject *self, void *UNUSED(closure))
{
- const char order[][4] = {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"};
-
if(!BaseMath_ReadCallback(self)) /* can read order too */
return NULL;
- return PyUnicode_FromString(order[self->order-EULER_ORDER_XYZ]);
+ return PyUnicode_FromString(euler_order_str(self));
}
static int Euler_setOrder(EulerObject *self, PyObject *value, void *UNUSED(closure))
{
- char *order_str= _PyUnicode_AsString(value);
+ const char *order_str= _PyUnicode_AsString(value);
short order= euler_order_from_string(order_str, "euler.order");
if(order == -1)
@@ -571,11 +576,12 @@ static PyGetSetDef Euler_getseters[] = {
//-----------------------METHOD DEFINITIONS ----------------------
static struct PyMethodDef Euler_methods[] = {
- {"zero", (PyCFunction) Euler_Zero, METH_NOARGS, Euler_Zero_doc},
- {"to_matrix", (PyCFunction) Euler_ToMatrix, METH_NOARGS, Euler_ToMatrix_doc},
- {"to_quat", (PyCFunction) Euler_ToQuat, METH_NOARGS, Euler_ToQuat_doc},
+ {"zero", (PyCFunction) Euler_zero, METH_NOARGS, Euler_zero_doc},
+ {"to_matrix", (PyCFunction) Euler_to_matrix, METH_NOARGS, Euler_to_matrix_doc},
+ {"to_quaternion", (PyCFunction) Euler_to_quaternion, METH_NOARGS, Euler_to_quaternion_doc},
{"rotate_axis", (PyCFunction) Euler_rotate_axis, METH_VARARGS, Euler_rotate_axis_doc},
- {"make_compatible", (PyCFunction) Euler_MakeCompatible, METH_O, Euler_MakeCompatible_doc},
+ {"rotate", (PyCFunction) Euler_rotate, METH_O, Euler_rotate_doc},
+ {"make_compatible", (PyCFunction) Euler_make_compatible, METH_O, Euler_make_compatible_doc},
{"__copy__", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc},
{"copy", (PyCFunction) Euler_copy, METH_NOARGS, Euler_copy_doc},
{NULL, NULL, 0, NULL}
@@ -583,8 +589,8 @@ static struct PyMethodDef Euler_methods[] = {
//------------------PY_OBECT DEFINITION--------------------------
static char euler_doc[] =
-"This object gives access to Eulers in Blender.";
-
+"This object gives access to Eulers in Blender."
+;
PyTypeObject euler_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"mathutils.Euler", //tp_name
diff --git a/source/blender/python/generic/mathutils_matrix.c b/source/blender/python/generic/mathutils_matrix.c
index 7b13bea60c7..ac30ddcf7f9 100644
--- a/source/blender/python/generic/mathutils_matrix.c
+++ b/source/blender/python/generic/mathutils_matrix.c
@@ -31,7 +31,21 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
-static int Matrix_ass_slice(MatrixObject * self, int begin, int end, PyObject *value);
+#define MATRIX_APPLY_TO_COPY(matrix_meth_noargs, _self) \
+ MatrixObject *ret= (MatrixObject *)Matrix_copy(_self); \
+ PyObject *ret_dummy= matrix_meth_noargs(ret); \
+ if(ret_dummy) { \
+ Py_DECREF(ret_dummy); \
+ return (PyObject *)ret; \
+ } \
+ else { /* error */ \
+ Py_DECREF(ret); \
+ return NULL; \
+ } \
+
+
+static PyObject *Matrix_copy(MatrixObject *self);
+static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value);
/* matrix vector callbacks */
int mathutils_matrix_vector_cb_index= -1;
@@ -147,9 +161,21 @@ static PyObject *Matrix_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL;
}
+/* when a matrix is 4x4 size but initialized as a 3x3, re-assign values for 4x4 */
+static void matrix_3x3_as_4x4(float mat[16])
+{
+ mat[10] = mat[8];
+ mat[9] = mat[7];
+ mat[8] = mat[6];
+ mat[7] = 0.0f;
+ mat[6] = mat[5];
+ mat[5] = mat[4];
+ mat[4] = mat[3];
+ mat[3] = 0.0f;
+}
+
/*-----------------------CLASS-METHODS----------------------------*/
-//----------------------------------mathutils.RotationMatrix() ----------
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
static char C_Matrix_Rotation_doc[] =
".. classmethod:: Rotation(angle, size, axis)\n"
@@ -163,12 +189,12 @@ static char C_Matrix_Rotation_doc[] =
" :arg axis: a string in ['X', 'Y', 'Z'] or a 3D Vector Object (optional when size is 2).\n"
" :type axis: string or :class:`Vector`\n"
" :return: A new rotation matrix.\n"
-" :rtype: :class:`Matrix`\n";
-
+" :rtype: :class:`Matrix`\n"
+;
static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
{
- VectorObject *vec= NULL;
- char *axis= NULL;
+ PyObject *vec= NULL;
+ const char *axis= NULL;
int matSize;
double angle; /* use double because of precision problems at high values */
float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
@@ -179,7 +205,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
return NULL;
}
- if(vec && !VectorObject_Check(vec)) {
+ if(vec && PyUnicode_Check(vec)) {
axis= _PyUnicode_AsString((PyObject *)vec);
if(axis==NULL || axis[0]=='\0' || axis[1]!='\0' || axis[0] < 'X' || axis[0] > 'Z') {
PyErr_SetString(PyExc_TypeError, "mathutils.RotationMatrix(): 3rd argument axis value must be a 3D vector or a string in 'X', 'Y', 'Z'");
@@ -203,23 +229,18 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
return NULL;
}
if((matSize == 3 || matSize == 4) && (axis == NULL) && (vec == NULL)) {
- PyErr_SetString(PyExc_AttributeError, "mathutils.RotationMatrix(): please choose an axis of rotation for 3d and 4d matrices");
+ PyErr_SetString(PyExc_AttributeError, "mathutils.RotationMatrix(): axis of rotation for 3d and 4d matrices is required");
return NULL;
}
- if(vec) {
- if(vec->size != 3) {
- PyErr_SetString(PyExc_AttributeError, "mathutils.RotationMatrix(): the vector axis must be a 3D vector");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec))
- return NULL;
-
- }
/* check for valid vector/axis above */
if(vec) {
- axis_angle_to_mat3( (float (*)[3])mat,vec->vec, angle);
+ float tvec[3];
+
+ if (mathutils_array_parse(tvec, 3, 3, vec, "mathutils.RotationMatrix(angle, size, axis), invalid 'axis' arg") == -1)
+ return NULL;
+
+ axis_angle_to_mat3((float (*)[3])mat, tvec, angle);
}
else if(matSize == 2) {
//2D rotation matrix
@@ -256,15 +277,7 @@ static PyObject *C_Matrix_Rotation(PyObject *cls, PyObject *args)
}
if(matSize == 4) {
- //resize matrix
- mat[10] = mat[8];
- mat[9] = mat[7];
- mat[8] = mat[6];
- mat[7] = 0.0f;
- mat[6] = mat[5];
- mat[5] = mat[4];
- mat[4] = mat[3];
- mat[3] = 0.0f;
+ matrix_3x3_as_4x4(mat);
}
//pass to matrix creation
return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
@@ -279,31 +292,18 @@ static char C_Matrix_Translation_doc[] =
" :arg vector: The translation vector.\n"
" :type vector: :class:`Vector`\n"
" :return: An identity matrix with a translation.\n"
-" :rtype: :class:`Matrix`\n";
-
-static PyObject *C_Matrix_Translation(PyObject *cls, VectorObject * vec)
+" :rtype: :class:`Matrix`\n"
+;
+static PyObject *C_Matrix_Translation(PyObject *cls, PyObject *value)
{
- float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-
- if(!VectorObject_Check(vec)) {
- PyErr_SetString(PyExc_TypeError, "mathutils.Matrix.Translation(): expected vector");
- return NULL;
- }
- if(vec->size != 3 && vec->size != 4) {
- PyErr_SetString(PyExc_TypeError, "mathutils.Matrix.Translation(): vector must be 3D or 4D");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(vec))
+ float mat[16], tvec[3];
+
+ if (mathutils_array_parse(tvec, 3, 4, value, "mathutils.Matrix.Translation(vector), invalid vector arg") == -1)
return NULL;
-
- //create a identity matrix and add translation
- unit_m4((float(*)[4]) mat);
- mat[12] = vec->vec[0];
- mat[13] = vec->vec[1];
- mat[14] = vec->vec[2];
+ /* create a identity matrix and add translation */
+ unit_m4((float(*)[4]) mat);
+ copy_v3_v3(mat + 12, tvec); /* 12, 13, 14 */
return newMatrixObject(mat, 4, 4, Py_NEW, (PyTypeObject *)cls);
}
//----------------------------------mathutils.Matrix.Scale() -------------
@@ -320,32 +320,30 @@ static char C_Matrix_Scale_doc[] =
" :arg axis: Direction to influence scale. (optional).\n"
" :type axis: :class:`Vector`\n"
" :return: A new scale matrix.\n"
-" :rtype: :class:`Matrix`\n";
-
+" :rtype: :class:`Matrix`\n"
+;
static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
{
- VectorObject *vec = NULL;
- float norm = 0.0f, factor;
- int matSize, x;
+ PyObject *vec= NULL;
+ int vec_size;
+ float tvec[3];
+ float factor;
+ int matSize;
float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
- if(!PyArg_ParseTuple(args, "fi|O!:Matrix.Scale", &factor, &matSize, &vector_Type, &vec)) {
+ if(!PyArg_ParseTuple(args, "fi|O!:Matrix.Scale", &factor, &matSize, &vec)) {
return NULL;
}
if(matSize != 2 && matSize != 3 && matSize != 4) {
- PyErr_SetString(PyExc_AttributeError, "mathutils.Matrix.Scale(): can only return a 2x2 3x3 or 4x4 matrix");
+ PyErr_SetString(PyExc_AttributeError, "Matrix.Scale(): can only return a 2x2 3x3 or 4x4 matrix");
return NULL;
}
if(vec) {
- if(vec->size > 2 && matSize == 2) {
- PyErr_SetString(PyExc_AttributeError, "mathutils.Matrix.Scale(): please use 2D vectors when scaling in 2D");
+ vec_size= (matSize == 2 ? 2 : 3);
+ if(mathutils_array_parse(tvec, vec_size, vec_size, vec, "Matrix.Scale(factor, size, axis), invalid 'axis' arg") == -1) {
return NULL;
}
-
- if(!BaseMath_ReadCallback(vec))
- return NULL;
-
}
if(vec == NULL) { //scaling along axis
if(matSize == 2) {
@@ -356,42 +354,37 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
mat[4] = factor;
mat[8] = factor;
}
- } else { //scaling in arbitrary direction
+ }
+ else { //scaling in arbitrary direction
//normalize arbitrary axis
- for(x = 0; x < vec->size; x++) {
- norm += vec->vec[x] * vec->vec[x];
+ float norm = 0.0f;
+ int x;
+ for(x = 0; x < vec_size; x++) {
+ norm += tvec[x] * tvec[x];
}
norm = (float) sqrt(norm);
- for(x = 0; x < vec->size; x++) {
- vec->vec[x] /= norm;
+ for(x = 0; x < vec_size; x++) {
+ tvec[x] /= norm;
}
if(matSize == 2) {
- mat[0] = 1 +((factor - 1) *(vec->vec[0] * vec->vec[0]));
- mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
- mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
- mat[3] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
+ mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0]));
+ mat[1] = ((factor - 1) *(tvec[0] * tvec[1]));
+ mat[2] = ((factor - 1) *(tvec[0] * tvec[1]));
+ mat[3] = 1 + ((factor - 1) *(tvec[1] * tvec[1]));
} else {
- mat[0] = 1 + ((factor - 1) *(vec->vec[0] * vec->vec[0]));
- mat[1] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
- mat[2] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
- mat[3] =((factor - 1) *(vec->vec[0] * vec->vec[1]));
- mat[4] = 1 + ((factor - 1) *(vec->vec[1] * vec->vec[1]));
- mat[5] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
- mat[6] =((factor - 1) *(vec->vec[0] * vec->vec[2]));
- mat[7] =((factor - 1) *(vec->vec[1] * vec->vec[2]));
- mat[8] = 1 + ((factor - 1) *(vec->vec[2] * vec->vec[2]));
+ mat[0] = 1 + ((factor - 1) *(tvec[0] * tvec[0]));
+ mat[1] = ((factor - 1) *(tvec[0] * tvec[1]));
+ mat[2] = ((factor - 1) *(tvec[0] * tvec[2]));
+ mat[3] = ((factor - 1) *(tvec[0] * tvec[1]));
+ mat[4] = 1 + ((factor - 1) *(tvec[1] * tvec[1]));
+ mat[5] = ((factor - 1) *(tvec[1] * tvec[2]));
+ mat[6] = ((factor - 1) *(tvec[0] * tvec[2]));
+ mat[7] = ((factor - 1) *(tvec[1] * tvec[2]));
+ mat[8] = 1 + ((factor - 1) *(tvec[2] * tvec[2]));
}
}
if(matSize == 4) {
- //resize matrix
- mat[10] = mat[8];
- mat[9] = mat[7];
- mat[8] = mat[6];
- mat[7] = 0.0f;
- mat[6] = mat[5];
- mat[5] = mat[4];
- mat[4] = mat[3];
- mat[3] = 0.0f;
+ matrix_3x3_as_4x4(mat);
}
//pass to matrix creation
return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
@@ -399,129 +392,134 @@ static PyObject *C_Matrix_Scale(PyObject *cls, PyObject *args)
//----------------------------------mathutils.Matrix.OrthoProjection() ---
//mat is a 1D array of floats - row[0][0],row[0][1], row[1][0], etc.
static char C_Matrix_OrthoProjection_doc[] =
-".. classmethod:: OrthoProjection(plane, size, axis)\n"
+".. classmethod:: OrthoProjection(axis, size)\n"
"\n"
" Create a matrix to represent an orthographic projection.\n"
"\n"
-" :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ', 'R'], where a single axis is for a 2D matrix and 'R' requires axis is given.\n"
-" :type plane: string\n"
+" :arg axis: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'], where a single axis is for a 2D matrix. Or a vector for an arbitrary axis\n"
+" :type axis: string or :class:`Vector`\n"
" :arg size: The size of the projection matrix to construct [2, 4].\n"
" :type size: int\n"
-" :arg axis: Arbitrary perpendicular plane vector (optional).\n"
-" :type axis: :class:`Vector`\n"
" :return: A new projection matrix.\n"
-" :rtype: :class:`Matrix`\n";
+" :rtype: :class:`Matrix`\n"
+;
static PyObject *C_Matrix_OrthoProjection(PyObject *cls, PyObject *args)
{
- VectorObject *vec = NULL;
- char *plane;
+ PyObject *axis;
+
int matSize, x;
float norm = 0.0f;
float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
-
- if(!PyArg_ParseTuple(args, "si|O!:Matrix.OrthoProjection", &plane, &matSize, &vector_Type, &vec)) {
+
+ if(!PyArg_ParseTuple(args, "Oi:Matrix.OrthoProjection", &axis, &matSize)) {
return NULL;
}
if(matSize != 2 && matSize != 3 && matSize != 4) {
PyErr_SetString(PyExc_AttributeError,"mathutils.Matrix.OrthoProjection(): can only return a 2x2 3x3 or 4x4 matrix");
return NULL;
}
- if(vec) {
- if(vec->size > 2 && matSize == 2) {
- PyErr_SetString(PyExc_AttributeError, "mathutils.Matrix.OrthoProjection(): please use 2D vectors when scaling in 2D");
- return NULL;
+
+ if(PyUnicode_Check(axis)) { //ortho projection onto cardinal plane
+ Py_ssize_t plane_len;
+ const char *plane= _PyUnicode_AsStringAndSize(axis, &plane_len);
+ if(matSize == 2) {
+ if(plane_len == 1 && plane[0]=='X') {
+ mat[0]= 1.0f;
+ }
+ else if (plane_len == 1 && plane[0]=='Y') {
+ mat[3]= 1.0f;
+ }
+ else {
+ PyErr_Format(PyExc_ValueError, "mathutils.Matrix.OrthoProjection(): unknown plane, expected: X, Y, not '%.200s'", plane);
+ return NULL;
+ }
}
-
- if(!BaseMath_ReadCallback(vec))
- return NULL;
-
- }
- if(vec == NULL) { //ortho projection onto cardinal plane
- if((strcmp(plane, "X") == 0) && matSize == 2) {
- mat[0] = 1.0f;
- } else if((strcmp(plane, "Y") == 0) && matSize == 2) {
- mat[3] = 1.0f;
- } else if((strcmp(plane, "XY") == 0) && matSize > 2) {
- mat[0] = 1.0f;
- mat[4] = 1.0f;
- } else if((strcmp(plane, "XZ") == 0) && matSize > 2) {
- mat[0] = 1.0f;
- mat[8] = 1.0f;
- } else if((strcmp(plane, "YZ") == 0) && matSize > 2) {
- mat[4] = 1.0f;
- mat[8] = 1.0f;
- } else {
- PyErr_SetString(PyExc_AttributeError, "mathutils.Matrix.OrthoProjection(): unknown plane - expected: X, Y, XY, XZ, YZ");
+ else {
+ if(plane_len == 2 && plane[0]=='X' && plane[1]=='Y') {
+ mat[0]= 1.0f;
+ mat[4]= 1.0f;
+ }
+ else if (plane_len == 2 && plane[0]=='X' && plane[1]=='Z') {
+ mat[0]= 1.0f;
+ mat[8]= 1.0f;
+ }
+ else if (plane_len == 2 && plane[0]=='Y' && plane[1]=='Z') {
+ mat[4]= 1.0f;
+ mat[8]= 1.0f;
+ }
+ else {
+ PyErr_Format(PyExc_ValueError, "mathutils.Matrix.OrthoProjection(): unknown plane, expected: XY, XZ, YZ, not '%.200s'", plane);
+ return NULL;
+ }
+ }
+ }
+ else {
+ //arbitrary plane
+
+ int vec_size= (matSize == 2 ? 2 : 3);
+ float tvec[4];
+
+ if(mathutils_array_parse(tvec, vec_size, vec_size, axis, "Matrix.OrthoProjection(axis, size), invalid 'axis' arg") == -1) {
return NULL;
}
- } else { //arbitrary plane
+
//normalize arbitrary axis
- for(x = 0; x < vec->size; x++) {
- norm += vec->vec[x] * vec->vec[x];
+ for(x = 0; x < vec_size; x++) {
+ norm += tvec[x] * tvec[x];
}
norm = (float) sqrt(norm);
- for(x = 0; x < vec->size; x++) {
- vec->vec[x] /= norm;
+ for(x = 0; x < vec_size; x++) {
+ tvec[x] /= norm;
}
- if((strcmp(plane, "R") == 0) && matSize == 2) {
- mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
- mat[1] = -(vec->vec[0] * vec->vec[1]);
- mat[2] = -(vec->vec[0] * vec->vec[1]);
- mat[3] = 1 - (vec->vec[1] * vec->vec[1]);
- } else if((strcmp(plane, "R") == 0) && matSize > 2) {
- mat[0] = 1 - (vec->vec[0] * vec->vec[0]);
- mat[1] = -(vec->vec[0] * vec->vec[1]);
- mat[2] = -(vec->vec[0] * vec->vec[2]);
- mat[3] = -(vec->vec[0] * vec->vec[1]);
- mat[4] = 1 - (vec->vec[1] * vec->vec[1]);
- mat[5] = -(vec->vec[1] * vec->vec[2]);
- mat[6] = -(vec->vec[0] * vec->vec[2]);
- mat[7] = -(vec->vec[1] * vec->vec[2]);
- mat[8] = 1 - (vec->vec[2] * vec->vec[2]);
- } else {
- PyErr_SetString(PyExc_AttributeError, "mathutils.Matrix.OrthoProjection(): unknown plane - expected: 'r' expected for axis designation");
- return NULL;
+ if(matSize == 2) {
+ mat[0] = 1 - (tvec[0] * tvec[0]);
+ mat[1] = -(tvec[0] * tvec[1]);
+ mat[2] = -(tvec[0] * tvec[1]);
+ mat[3] = 1 - (tvec[1] * tvec[1]);
+ }
+ else if(matSize > 2) {
+ mat[0] = 1 - (tvec[0] * tvec[0]);
+ mat[1] = -(tvec[0] * tvec[1]);
+ mat[2] = -(tvec[0] * tvec[2]);
+ mat[3] = -(tvec[0] * tvec[1]);
+ mat[4] = 1 - (tvec[1] * tvec[1]);
+ mat[5] = -(tvec[1] * tvec[2]);
+ mat[6] = -(tvec[0] * tvec[2]);
+ mat[7] = -(tvec[1] * tvec[2]);
+ mat[8] = 1 - (tvec[2] * tvec[2]);
}
}
if(matSize == 4) {
- //resize matrix
- mat[10] = mat[8];
- mat[9] = mat[7];
- mat[8] = mat[6];
- mat[7] = 0.0f;
- mat[6] = mat[5];
- mat[5] = mat[4];
- mat[4] = mat[3];
- mat[3] = 0.0f;
+ matrix_3x3_as_4x4(mat);
}
//pass to matrix creation
return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
}
static char C_Matrix_Shear_doc[] =
-".. classmethod:: Shear(plane, factor, size)\n"
+".. classmethod:: Shear(plane, size, factor)\n"
"\n"
" Create a matrix to represent an shear transformation.\n"
"\n"
" :arg plane: Can be any of the following: ['X', 'Y', 'XY', 'XZ', 'YZ'], where a single axis is for a 2D matrix only.\n"
" :type plane: string\n"
-" :arg factor: The factor of shear to apply. For a 3 or 4 *size* matrix pass a pair of floats corrasponding with the *plane* axis.\n"
-" :type factor: float or float pair\n"
" :arg size: The size of the shear matrix to construct [2, 4].\n"
" :type size: int\n"
+" :arg factor: The factor of shear to apply. For a 3 or 4 *size* matrix pass a pair of floats corrasponding with the *plane* axis.\n"
+" :type factor: float or float pair\n"
" :return: A new shear matrix.\n"
" :rtype: :class:`Matrix`\n"
;
static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
{
int matSize;
- char *plane;
+ const char *plane;
PyObject *fac;
float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f};
- if(!PyArg_ParseTuple(args, "sOi:Matrix.Shear", &plane, &fac, &matSize)) {
+ if(!PyArg_ParseTuple(args, "siO:Matrix.Shear", &plane, &matSize, &fac)) {
return NULL;
}
if(matSize != 2 && matSize != 3 && matSize != 4) {
@@ -584,21 +582,13 @@ static PyObject *C_Matrix_Shear(PyObject *cls, PyObject *args)
}
if(matSize == 4) {
- //resize matrix
- mat[10] = mat[8];
- mat[9] = mat[7];
- mat[8] = mat[6];
- mat[7] = 0.0f;
- mat[6] = mat[5];
- mat[5] = mat[4];
- mat[4] = mat[3];
- mat[3] = 0.0f;
+ matrix_3x3_as_4x4(mat);
}
//pass to matrix creation
return newMatrixObject(mat, matSize, matSize, Py_NEW, (PyTypeObject *)cls);
}
-static void matrix_as_3x3(float mat[3][3], MatrixObject *self)
+void matrix_as_3x3(float mat[3][3], MatrixObject *self)
{
copy_v3_v3(mat[0], self->matrix[0]);
copy_v3_v3(mat[1], self->matrix[1]);
@@ -606,7 +596,7 @@ static void matrix_as_3x3(float mat[3][3], MatrixObject *self)
}
/* assumes rowsize == colsize is checked and the read callback has run */
-static float matrix_determinant(MatrixObject * self)
+static float matrix_determinant_internal(MatrixObject *self)
{
if(self->rowSize == 2) {
return determinant_m2(self->matrix[0][0], self->matrix[0][1],
@@ -624,37 +614,37 @@ static float matrix_determinant(MatrixObject * self)
/*-----------------------------METHODS----------------------------*/
-static char Matrix_toQuat_doc[] =
-".. method:: to_quat()\n"
+static char Matrix_to_quaternion_doc[] =
+".. method:: to_quaternion()\n"
"\n"
" Return a quaternion representation of the rotation matrix.\n"
"\n"
" :return: Quaternion representation of the rotation matrix.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Matrix_toQuat(MatrixObject * self)
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Matrix_to_quaternion(MatrixObject *self)
{
float quat[4];
if(!BaseMath_ReadCallback(self))
return NULL;
-
+
/*must be 3-4 cols, 3-4 rows, square matrix*/
if((self->colSize < 3) || (self->rowSize < 3) || (self->colSize != self->rowSize)) {
PyErr_SetString(PyExc_AttributeError, "Matrix.to_quat(): inappropriate matrix size - expects 3x3 or 4x4 matrix");
return NULL;
- }
+ }
if(self->colSize == 3){
mat3_to_quat( quat,(float (*)[3])self->contigPtr);
}else{
mat4_to_quat( quat,(float (*)[4])self->contigPtr);
}
-
+
return newQuaternionObject(quat, Py_NEW, NULL);
}
/*---------------------------Matrix.toEuler() --------------------*/
-static char Matrix_toEuler_doc[] =
+static char Matrix_to_euler_doc[] =
".. method:: to_euler(order, euler_compat)\n"
"\n"
" Return an Euler representation of the rotation matrix (3x3 or 4x4 matrix only).\n"
@@ -664,31 +654,31 @@ static char Matrix_toEuler_doc[] =
" :arg euler_compat: Optional euler argument the new euler will be made compatible with (no axis flipping between them). Useful for converting a series of matrices to animation curves.\n"
" :type euler_compat: :class:`Euler`\n"
" :return: Euler representation of the matrix.\n"
-" :rtype: :class:`Euler`\n";
-
-PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args)
+" :rtype: :class:`Euler`\n"
+;
+static PyObject *Matrix_to_euler(MatrixObject *self, PyObject *args)
{
- char *order_str= NULL;
+ const char *order_str= NULL;
short order= EULER_ORDER_XYZ;
float eul[3], eul_compatf[3];
EulerObject *eul_compat = NULL;
float tmat[3][3];
float (*mat)[3];
-
+
if(!BaseMath_ReadCallback(self))
return NULL;
-
+
if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
return NULL;
-
+
if(eul_compat) {
if(!BaseMath_ReadCallback(eul_compat))
return NULL;
copy_v3_v3(eul_compatf, eul_compat->eul);
}
-
+
/*must be 3-4 cols, 3-4 rows, square matrix*/
if(self->colSize ==3 && self->rowSize ==3) {
mat= (float (*)[3])self->contigPtr;
@@ -718,16 +708,13 @@ PyObject *Matrix_toEuler(MatrixObject * self, PyObject *args)
return newEulerObject(eul, order, Py_NEW, NULL);
}
-/*---------------------------Matrix.resize4x4() ------------------*/
-static char Matrix_Resize4x4_doc[] =
-".. method:: resize4x4()\n"
+
+static char Matrix_resize_4x4_doc[] =
+".. method:: resize_4x4()\n"
"\n"
" Resize the matrix to 4x4.\n"
-"\n"
-" :return: an instance of itself.\n"
-" :rtype: :class:`Matrix`\n";
-
-PyObject *Matrix_Resize4x4(MatrixObject * self)
+;
+static PyObject *Matrix_resize_4x4(MatrixObject *self)
{
int x, first_row_elem, curr_pos, new_pos, blank_columns, blank_rows, index;
@@ -739,10 +726,10 @@ PyObject *Matrix_Resize4x4(MatrixObject * self)
PyErr_SetString(PyExc_TypeError, "cannot resize owned data - make a copy and resize that");
return NULL;
}
-
+
self->contigPtr = PyMem_Realloc(self->contigPtr, (sizeof(float) * 16));
if(self->contigPtr == NULL) {
- PyErr_SetString(PyExc_MemoryError, "matrix.resize4x4(): problem allocating pointer space");
+ PyErr_SetString(PyExc_MemoryError, "matrix.resize_4x4(): problem allocating pointer space");
return NULL;
}
/*set row pointers*/
@@ -774,9 +761,8 @@ PyObject *Matrix_Resize4x4(MatrixObject * self)
}
self->rowSize = 4;
self->colSize = 4;
-
- Py_INCREF(self);
- return (PyObject *)self;
+
+ Py_RETURN_NONE;
}
static char Matrix_to_4x4_doc[] =
@@ -785,8 +771,9 @@ static char Matrix_to_4x4_doc[] =
" Return a 4x4 copy of this matrix.\n"
"\n"
" :return: a new matrix.\n"
-" :rtype: :class:`Matrix`\n";
-PyObject *Matrix_to_4x4(MatrixObject * self)
+" :rtype: :class:`Matrix`\n"
+;
+static PyObject *Matrix_to_4x4(MatrixObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -811,8 +798,9 @@ static char Matrix_to_3x3_doc[] =
" Return a 3x3 copy of this matrix.\n"
"\n"
" :return: a new matrix.\n"
-" :rtype: :class:`Matrix`\n";
-PyObject *Matrix_to_3x3(MatrixObject * self)
+" :rtype: :class:`Matrix`\n"
+;
+static PyObject *Matrix_to_3x3(MatrixObject *self)
{
float mat[3][3];
@@ -829,66 +817,38 @@ PyObject *Matrix_to_3x3(MatrixObject * self)
return newMatrixObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
}
-/*---------------------------Matrix.translationPart() ------------*/
-static char Matrix_TranslationPart_doc[] =
-".. method:: translation_part()\n"
+static char Matrix_to_translation_doc[] =
+".. method:: to_translation()\n"
"\n"
" Return a the translation part of a 4 row matrix.\n"
"\n"
" :return: Return a the translation of a matrix.\n"
" :rtype: :class:`Vector`\n"
;
-PyObject *Matrix_TranslationPart(MatrixObject * self)
+static PyObject *Matrix_to_translation(MatrixObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
-
+
if((self->colSize < 3) || self->rowSize < 4){
- PyErr_SetString(PyExc_AttributeError, "Matrix.translation_part(): inappropriate matrix size");
+ PyErr_SetString(PyExc_AttributeError, "Matrix.to_translation(): inappropriate matrix size");
return NULL;
}
return newVectorObject(self->matrix[3], 3, Py_NEW, NULL);
}
-/*---------------------------Matrix.rotationPart() ---------------*/
-static char Matrix_RotationPart_doc[] =
-".. method:: rotation_part()\n"
-"\n"
-" Return the 3d submatrix corresponding to the linear term of the embedded affine transformation in 3d. This matrix represents rotation and scale.\n"
-"\n"
-" :return: Return the 3d matrix for rotation and scale.\n"
-" :rtype: :class:`Matrix`\n"
-"\n"
-" .. note:: Note that the (4,4) element of a matrix can be used for uniform scaling too.\n";
-PyObject *Matrix_RotationPart(MatrixObject *self)
-{
- float mat[3][3];
-
- if(!BaseMath_ReadCallback(self))
- return NULL;
-
- if((self->colSize < 3) || (self->rowSize < 3)) {
- PyErr_SetString(PyExc_AttributeError, "Matrix.rotation_part(): inappropriate matrix size");
- return NULL;
- }
-
- matrix_as_3x3(mat, self);
-
- return newMatrixObject((float *)mat, 3, 3, Py_NEW, Py_TYPE(self));
-}
-/*---------------------------Matrix.scalePart() --------------------*/
-static char Matrix_scalePart_doc[] =
-".. method:: scale_part()\n"
+static char Matrix_to_scale_doc[] =
+".. method:: to_scale()\n"
"\n"
" Return a the scale part of a 3x3 or 4x4 matrix.\n"
"\n"
" :return: Return a the scale of a matrix.\n"
" :rtype: :class:`Vector`\n"
"\n"
-" .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n";
-
-PyObject *Matrix_scalePart(MatrixObject * self)
+" .. note:: This method does not return negative a scale on any axis because it is not possible to obtain this data from the matrix alone.\n"
+;
+static PyObject *Matrix_to_scale(MatrixObject *self)
{
float rot[3][3];
float mat[3][3];
@@ -899,7 +859,7 @@ PyObject *Matrix_scalePart(MatrixObject * self)
/*must be 3-4 cols, 3-4 rows, square matrix*/
if((self->colSize < 3) || (self->rowSize < 3)) {
- PyErr_SetString(PyExc_AttributeError, "Matrix.scale_part(): inappropriate matrix size, 3x3 minimum size");
+ PyErr_SetString(PyExc_AttributeError, "Matrix.to_scale(): inappropriate matrix size, 3x3 minimum size");
return NULL;
}
@@ -912,7 +872,7 @@ PyObject *Matrix_scalePart(MatrixObject * self)
}
/*---------------------------Matrix.invert() ---------------------*/
-static char Matrix_Invert_doc[] =
+static char Matrix_invert_doc[] =
".. method:: invert()\n"
"\n"
" Set the matrix to its inverse.\n"
@@ -922,11 +882,11 @@ static char Matrix_Invert_doc[] =
"\n"
" .. note:: :exc:`ValueError` exception is raised.\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n";
-
-PyObject *Matrix_Invert(MatrixObject * self)
+" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
+;
+static PyObject *Matrix_invert(MatrixObject *self)
{
-
+
int x, y, z = 0;
float det = 0.0f;
float mat[16] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
@@ -941,7 +901,7 @@ PyObject *Matrix_Invert(MatrixObject * self)
}
/*calculate the determinant*/
- det = matrix_determinant(self);
+ det = matrix_determinant_internal(self);
if(det != 0) {
/*calculate the classical adjoint*/
@@ -967,15 +927,63 @@ PyObject *Matrix_Invert(MatrixObject * self)
}
}
/*transpose
- Matrix_Transpose(self);*/
+ Matrix_transpose(self);*/
} else {
PyErr_SetString(PyExc_ValueError, "matrix does not have an inverse");
return NULL;
}
-
+
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
+ Py_RETURN_NONE;
+}
+
+static char Matrix_inverted_doc[] =
+".. method:: invert()\n"
+"\n"
+" Return an inverted copy of the matrix.\n"
+"\n"
+" :return: the inverted matrix.\n"
+" :rtype: :class:`Matrix`\n"
+"\n"
+" .. note:: :exc:`ValueError` exception is raised.\n"
+;
+static PyObject *Matrix_inverted(MatrixObject *self)
+{
+ MATRIX_APPLY_TO_COPY(Matrix_invert, self);
+}
+
+static char Matrix_rotate_doc[] =
+".. method:: rotate(other)\n"
+"\n"
+" Rotates the matrix a by another mathutils value.\n"
+"\n"
+" :arg other: rotation component of mathutils value\n"
+" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
+"\n"
+" .. note:: If any of the columns are not unit length this may not have desired results.\n"
+;
+static PyObject *Matrix_rotate(MatrixObject *self, PyObject *value)
+{
+ float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
+
+ if(!BaseMath_ReadCallback(self))
+ return NULL;
+
+ if(mathutils_any_to_rotmat(other_rmat, value, "matrix.rotate(value)") == -1)
+ return NULL;
+
+ if(self->colSize != 3 || self->rowSize != 3) {
+ PyErr_SetString(PyExc_ValueError, "Matrix must have 3x3 dimensions");
+ return NULL;
+ }
+
+ matrix_as_3x3(self_rmat, self);
+ mul_m3_m3m3(rmat, self_rmat, other_rmat);
+
+ copy_m3_m3((float (*)[3])(self->contigPtr), rmat);
+
+ (void)BaseMath_WriteCallback(self);
+ Py_RETURN_NONE;
}
/*---------------------------Matrix.decompose() ---------------------*/
@@ -985,8 +993,9 @@ static char Matrix_decompose_doc[] =
" Return the location, rotaion and scale components of this matrix.\n"
"\n"
" :return: loc, rot, scale triple.\n"
-" :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)";
-static PyObject *Matrix_decompose(MatrixObject * self)
+" :rtype: (:class:`Vector`, :class:`Quaternion`, :class:`Vector`)"
+;
+static PyObject *Matrix_decompose(MatrixObject *self)
{
PyObject *ret;
float loc[3];
@@ -1015,7 +1024,7 @@ static PyObject *Matrix_decompose(MatrixObject * self)
-static char Matrix_Lerp_doc[] =
+static char Matrix_lerp_doc[] =
".. function:: lerp(other, factor)\n"
"\n"
" Returns the interpolation of two matricies.\n"
@@ -1025,9 +1034,9 @@ static char Matrix_Lerp_doc[] =
" :arg factor: The interpolation value in [0.0, 1.0].\n"
" :type factor: float\n"
" :return: The interpolated rotation.\n"
-" :rtype: :class:`Matrix`\n";
-
-static PyObject *Matrix_Lerp(MatrixObject *self, PyObject *args)
+" :rtype: :class:`Matrix`\n"
+;
+static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args)
{
MatrixObject *mat2 = NULL;
float fac, mat[MATRIX_MAX_DIM*MATRIX_MAX_DIM];
@@ -1059,7 +1068,7 @@ static PyObject *Matrix_Lerp(MatrixObject *self, PyObject *args)
}
/*---------------------------Matrix.determinant() ----------------*/
-static char Matrix_Determinant_doc[] =
+static char Matrix_determinant_doc[] =
".. method:: determinant()\n"
"\n"
" Return the determinant of a matrix.\n"
@@ -1067,38 +1076,35 @@ static char Matrix_Determinant_doc[] =
" :return: Return a the determinant of a matrix.\n"
" :rtype: float\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n";
-
-PyObject *Matrix_Determinant(MatrixObject * self)
+" .. seealso:: <http://en.wikipedia.org/wiki/Determinant>\n"
+;
+static PyObject *Matrix_determinant(MatrixObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
-
+
if(self->rowSize != self->colSize){
PyErr_SetString(PyExc_AttributeError, "Matrix.determinant: only square matrices are supported");
return NULL;
}
- return PyFloat_FromDouble((double)matrix_determinant(self));
+ return PyFloat_FromDouble((double)matrix_determinant_internal(self));
}
/*---------------------------Matrix.transpose() ------------------*/
-static char Matrix_Transpose_doc[] =
+static char Matrix_transpose_doc[] =
".. method:: transpose()\n"
"\n"
" Set the matrix to its transpose.\n"
"\n"
-" :return: an instance of itself\n"
-" :rtype: :class:`Matrix`\n"
-"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n";
-
-PyObject *Matrix_Transpose(MatrixObject * self)
+" .. seealso:: <http://en.wikipedia.org/wiki/Transpose>\n"
+;
+static PyObject *Matrix_transpose(MatrixObject *self)
{
float t = 0.0f;
if(!BaseMath_ReadCallback(self))
return NULL;
-
+
if(self->rowSize != self->colSize){
PyErr_SetString(PyExc_AttributeError, "Matrix.transpose(d): only square matrices are supported");
return NULL;
@@ -1115,54 +1121,55 @@ PyObject *Matrix_Transpose(MatrixObject * self)
}
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject *)self;
+ Py_RETURN_NONE;
}
+static char Matrix_transposed_doc[] =
+".. method:: transposed()\n"
+"\n"
+" Return a new, transposed matrix.\n"
+"\n"
+" :return: a transposed matrix\n"
+" :rtype: :class:`Matrix`\n"
+;
+static PyObject *Matrix_transposed(MatrixObject *self)
+{
+ MATRIX_APPLY_TO_COPY(Matrix_transpose, self);
+}
/*---------------------------Matrix.zero() -----------------------*/
-static char Matrix_Zero_doc[] =
+static char Matrix_zero_doc[] =
".. method:: zero()\n"
"\n"
" Set all the matrix values to zero.\n"
"\n"
" :return: an instance of itself\n"
-" :rtype: :class:`Matrix`\n";
-
-PyObject *Matrix_Zero(MatrixObject * self)
+" :rtype: :class:`Matrix`\n"
+;
+static PyObject *Matrix_zero(MatrixObject *self)
{
- int row, col;
-
- for(row = 0; row < self->rowSize; row++) {
- for(col = 0; col < self->colSize; col++) {
- self->matrix[row][col] = 0.0f;
- }
- }
-
+ fill_vn(self->contigPtr, self->rowSize * self->colSize, 0.0f);
+
if(!BaseMath_WriteCallback(self))
return NULL;
-
- Py_INCREF(self);
- return (PyObject *)self;
+
+ Py_RETURN_NONE;
}
/*---------------------------Matrix.identity(() ------------------*/
-static char Matrix_Identity_doc[] =
+static char Matrix_identity_doc[] =
".. method:: identity()\n"
"\n"
" Set the matrix to the identity matrix.\n"
"\n"
-" :return: an instance of itself\n"
-" :rtype: :class:`Matrix`\n"
-"\n"
" .. note:: An object with zero location and rotation, a scale of one, will have an identity matrix.\n"
"\n"
-" .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n";
-
-PyObject *Matrix_Identity(MatrixObject * self)
+" .. seealso:: <http://en.wikipedia.org/wiki/Identity_matrix>\n"
+;
+static PyObject *Matrix_identity(MatrixObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
-
+
if(self->rowSize != self->colSize){
PyErr_SetString(PyExc_AttributeError, "Matrix.identity: only square matrices are supported");
return NULL;
@@ -1181,9 +1188,8 @@ PyObject *Matrix_Identity(MatrixObject * self)
if(!BaseMath_WriteCallback(self))
return NULL;
-
- Py_INCREF(self);
- return (PyObject *)self;
+
+ Py_RETURN_NONE;
}
/*---------------------------Matrix.copy() ------------------*/
@@ -1193,19 +1199,19 @@ static char Matrix_copy_doc[] =
" Returns a copy of this matrix.\n"
"\n"
" :return: an instance of itself\n"
-" :rtype: :class:`Matrix`\n";
-
-PyObject *Matrix_copy(MatrixObject *self)
+" :rtype: :class:`Matrix`\n"
+;
+static PyObject *Matrix_copy(MatrixObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
-
+
return (PyObject*)newMatrixObject((float (*))self->contigPtr, self->rowSize, self->colSize, Py_NEW, Py_TYPE(self));
}
/*----------------------------print object (internal)-------------*/
/*print the object to screen*/
-static PyObject *Matrix_repr(MatrixObject * self)
+static PyObject *Matrix_repr(MatrixObject *self)
{
int x, y;
PyObject *rows[MATRIX_MAX_DIM]= {0};
@@ -1237,75 +1243,60 @@ static PyObject *Matrix_repr(MatrixObject * self)
return NULL;
}
-/*------------------------tp_richcmpr*/
-/*returns -1 execption, 0 false, 1 true*/
-static PyObject* Matrix_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+static PyObject* Matrix_richcmpr(PyObject *a, PyObject *b, int op)
{
- MatrixObject *matA = NULL, *matB = NULL;
- int result = 0;
-
- if (!MatrixObject_Check(objectA) || !MatrixObject_Check(objectB)){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
+ PyObject *res;
+ int ok= -1; /* zero is true */
+
+ if (MatrixObject_Check(a) && MatrixObject_Check(b)) {
+ MatrixObject *matA= (MatrixObject*)a;
+ MatrixObject *matB= (MatrixObject*)b;
+
+ if(!BaseMath_ReadCallback(matA) || !BaseMath_ReadCallback(matB))
+ return NULL;
+
+ ok= ( (matA->colSize == matB->colSize) &&
+ (matA->rowSize == matB->rowSize) &&
+ EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr, (matA->rowSize * matA->colSize), 1)
+ ) ? 0 : -1;
}
- matA = (MatrixObject*)objectA;
- matB = (MatrixObject*)objectB;
- if(!BaseMath_ReadCallback(matA) || !BaseMath_ReadCallback(matB))
+ switch (op) {
+ case Py_NE:
+ ok = !ok; /* pass through */
+ case Py_EQ:
+ res = ok ? Py_False : Py_True;
+ break;
+
+ case Py_LT:
+ case Py_LE:
+ case Py_GT:
+ case Py_GE:
+ res = Py_NotImplemented;
+ break;
+ default:
+ PyErr_BadArgument();
return NULL;
-
- if (matA->colSize != matB->colSize || matA->rowSize != matB->rowSize){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
}
- switch (comparison_type){
- case Py_EQ:
- /*contigPtr is basically a really long vector*/
- result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
- (matA->rowSize * matA->colSize), 1);
- break;
- case Py_NE:
- result = EXPP_VectorsAreEqual(matA->contigPtr, matB->contigPtr,
- (matA->rowSize * matA->colSize), 1);
- if (result == 0){
- result = 1;
- }else{
- result = 0;
- }
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
- }
- if (result == 1){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
+ return Py_INCREF(res), res;
}
/*---------------------SEQUENCE PROTOCOLS------------------------
----------------------------len(object)------------------------
sequence length*/
-static int Matrix_len(MatrixObject * self)
+static int Matrix_len(MatrixObject *self)
{
return (self->rowSize);
}
/*----------------------------object[]---------------------------
sequence accessor (get)
the wrapped vector gives direct access to the matrix data*/
-static PyObject *Matrix_item(MatrixObject * self, int i)
+static PyObject *Matrix_item(MatrixObject *self, int i)
{
if(!BaseMath_ReadCallback(self))
return NULL;
-
+
if(i < 0 || i >= self->rowSize) {
PyErr_SetString(PyExc_IndexError, "matrix[attribute]: array index out of range");
return NULL;
@@ -1330,7 +1321,7 @@ static int Matrix_ass_item(MatrixObject *self, int i, PyObject *value)
return -1;
}
- memcpy(self->matrix[i], vec, self->colSize * sizeof(float));
+ memcpy(self->matrix[i], vec, self->colSize *sizeof(float));
(void)BaseMath_WriteCallback(self);
return 0;
@@ -1338,12 +1329,12 @@ static int Matrix_ass_item(MatrixObject *self, int i, PyObject *value)
/*----------------------------object[z:y]------------------------
sequence slice (get)*/
-static PyObject *Matrix_slice(MatrixObject * self, int begin, int end)
+static PyObject *Matrix_slice(MatrixObject *self, int begin, int end)
{
PyObject *tuple;
int count;
-
+
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -1362,13 +1353,13 @@ static PyObject *Matrix_slice(MatrixObject * self, int begin, int end)
}
/*----------------------------object[z:y]------------------------
sequence slice (set)*/
-static int Matrix_ass_slice(MatrixObject * self, int begin, int end, PyObject *value)
+static int Matrix_ass_slice(MatrixObject *self, int begin, int end, PyObject *value)
{
PyObject *value_fast= NULL;
if(!BaseMath_ReadCallback(self))
return -1;
-
+
CLAMP(begin, 0, self->rowSize);
CLAMP(end, 0, self->rowSize);
begin = MIN2(begin,end);
@@ -1410,7 +1401,7 @@ static int Matrix_ass_slice(MatrixObject * self, int begin, int end, PyObject *v
}
/*------------------------NUMERIC PROTOCOLS----------------------
------------------------obj + obj------------------------------*/
-static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
+static PyObject *Matrix_add(PyObject *m1, PyObject *m2)
{
float mat[16];
MatrixObject *mat1 = NULL, *mat2 = NULL;
@@ -1422,10 +1413,10 @@ static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation");
return NULL;
}
-
+
if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2))
return NULL;
-
+
if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation");
return NULL;
@@ -1437,7 +1428,7 @@ static PyObject *Matrix_add(PyObject * m1, PyObject * m2)
}
/*------------------------obj - obj------------------------------
subtraction*/
-static PyObject *Matrix_sub(PyObject * m1, PyObject * m2)
+static PyObject *Matrix_sub(PyObject *m1, PyObject *m2)
{
float mat[16];
MatrixObject *mat1 = NULL, *mat2 = NULL;
@@ -1449,10 +1440,10 @@ static PyObject *Matrix_sub(PyObject * m1, PyObject * m2)
PyErr_SetString(PyExc_AttributeError, "Matrix addition: arguments not valid for this operation");
return NULL;
}
-
+
if(!BaseMath_ReadCallback(mat1) || !BaseMath_ReadCallback(mat2))
return NULL;
-
+
if(mat1->rowSize != mat2->rowSize || mat1->colSize != mat2->colSize){
PyErr_SetString(PyExc_AttributeError, "Matrix addition: matrices must have the same dimensions for this operation");
return NULL;
@@ -1535,8 +1526,8 @@ static PyObject* Matrix_inv(MatrixObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
-
- return Matrix_Invert(self);
+
+ return Matrix_invert(self);
}
/*-----------------PROTOCOL DECLARATIONS--------------------------*/
@@ -1571,7 +1562,7 @@ static PyObject *Matrix_subscript(MatrixObject* self, PyObject* item)
return NULL;
if (slicelength <= 0) {
- return PyList_New(0);
+ return PyTuple_New(0);
}
else if (step == 1) {
return Matrix_slice(self, start, stop);
@@ -1720,24 +1711,36 @@ static PyGetSetDef Matrix_getseters[] = {
/*-----------------------METHOD DEFINITIONS ----------------------*/
static struct PyMethodDef Matrix_methods[] = {
- {"zero", (PyCFunction) Matrix_Zero, METH_NOARGS, Matrix_Zero_doc},
- {"identity", (PyCFunction) Matrix_Identity, METH_NOARGS, Matrix_Identity_doc},
- {"transpose", (PyCFunction) Matrix_Transpose, METH_NOARGS, Matrix_Transpose_doc},
- {"lerp", (PyCFunction) Matrix_Lerp, METH_VARARGS, Matrix_Lerp_doc},
- {"determinant", (PyCFunction) Matrix_Determinant, METH_NOARGS, Matrix_Determinant_doc},
- {"invert", (PyCFunction) Matrix_Invert, METH_NOARGS, Matrix_Invert_doc},
- {"translation_part", (PyCFunction) Matrix_TranslationPart, METH_NOARGS, Matrix_TranslationPart_doc},
- {"rotation_part", (PyCFunction) Matrix_RotationPart, METH_NOARGS, Matrix_RotationPart_doc},
- {"scale_part", (PyCFunction) Matrix_scalePart, METH_NOARGS, Matrix_scalePart_doc},
+ /* derived values */
+ {"determinant", (PyCFunction) Matrix_determinant, METH_NOARGS, Matrix_determinant_doc},
{"decompose", (PyCFunction) Matrix_decompose, METH_NOARGS, Matrix_decompose_doc},
- {"resize4x4", (PyCFunction) Matrix_Resize4x4, METH_NOARGS, Matrix_Resize4x4_doc},
- {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
+
+ /* in place only */
+ {"zero", (PyCFunction) Matrix_zero, METH_NOARGS, Matrix_zero_doc},
+ {"identity", (PyCFunction) Matrix_identity, METH_NOARGS, Matrix_identity_doc},
+
+ /* operate on original or copy */
+ {"transpose", (PyCFunction) Matrix_transpose, METH_NOARGS, Matrix_transpose_doc},
+ {"transposed", (PyCFunction) Matrix_transposed, METH_NOARGS, Matrix_transposed_doc},
+ {"invert", (PyCFunction) Matrix_invert, METH_NOARGS, Matrix_invert_doc},
+ {"inverted", (PyCFunction) Matrix_inverted, METH_NOARGS, Matrix_inverted_doc},
{"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
- {"to_euler", (PyCFunction) Matrix_toEuler, METH_VARARGS, Matrix_toEuler_doc},
- {"to_quat", (PyCFunction) Matrix_toQuat, METH_NOARGS, Matrix_toQuat_doc},
+ // TODO. {"resize_3x3", (PyCFunction) Matrix_resize3x3, METH_NOARGS, Matrix_resize3x3_doc},
+ {"to_4x4", (PyCFunction) Matrix_to_4x4, METH_NOARGS, Matrix_to_4x4_doc},
+ {"resize_4x4", (PyCFunction) Matrix_resize_4x4, METH_NOARGS, Matrix_resize_4x4_doc},
+ {"rotate", (PyCFunction) Matrix_rotate, METH_O, Matrix_rotate_doc},
+
+ /* return converted representation */
+ {"to_euler", (PyCFunction) Matrix_to_euler, METH_VARARGS, Matrix_to_euler_doc},
+ {"to_quaternion", (PyCFunction) Matrix_to_quaternion, METH_NOARGS, Matrix_to_quaternion_doc},
+ {"to_scale", (PyCFunction) Matrix_to_scale, METH_NOARGS, Matrix_to_scale_doc},
+ {"to_translation", (PyCFunction) Matrix_to_translation, METH_NOARGS, Matrix_to_translation_doc},
+
+ /* operation between 2 or more types */
+ {"lerp", (PyCFunction) Matrix_lerp, METH_VARARGS, Matrix_lerp_doc},
{"copy", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
{"__copy__", (PyCFunction) Matrix_copy, METH_NOARGS, Matrix_copy_doc},
-
+
/* class methods */
{"Rotation", (PyCFunction) C_Matrix_Rotation, METH_VARARGS | METH_CLASS, C_Matrix_Rotation_doc},
{"Scale", (PyCFunction) C_Matrix_Scale, METH_VARARGS | METH_CLASS, C_Matrix_Scale_doc},
@@ -1749,8 +1752,8 @@ static struct PyMethodDef Matrix_methods[] = {
/*------------------PY_OBECT DEFINITION--------------------------*/
static char matrix_doc[] =
-"This object gives access to Matrices in Blender.";
-
+"This object gives access to Matrices in Blender."
+;
PyTypeObject matrix_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"mathutils.Matrix", /*tp_name*/
@@ -1832,7 +1835,7 @@ PyObject *newMatrixObject(float *mat, const unsigned short rowSize, const unsign
self->rowSize = rowSize;
self->colSize = colSize;
-
+
/* init callbacks as NULL */
self->cb_user= NULL;
self->cb_type= self->cb_subtype= 0;
@@ -1862,8 +1865,8 @@ PyObject *newMatrixObject(float *mat, const unsigned short rowSize, const unsign
}
}
} else if (rowSize == colSize ) { /*or if no arguments are passed return identity matrix for square matrices */
- Matrix_Identity(self);
- Py_DECREF(self);
+ PyObject *ret_dummy= Matrix_identity(self);
+ Py_DECREF(ret_dummy);
}
self->wrapped = Py_NEW;
}else{ /*bad type*/
diff --git a/source/blender/python/generic/mathutils_matrix.h b/source/blender/python/generic/mathutils_matrix.h
index 4d477818171..125846e1ddd 100644
--- a/source/blender/python/generic/mathutils_matrix.h
+++ b/source/blender/python/generic/mathutils_matrix.h
@@ -55,4 +55,6 @@ PyObject *newMatrixObject_cb(PyObject *user, int rowSize, int colSize, int cb_ty
extern int mathutils_matrix_vector_cb_index;
extern struct Mathutils_Callback mathutils_matrix_vector_cb;
+void matrix_as_3x3(float mat[3][3], MatrixObject *self);
+
#endif /* MATHUTILS_MATRIX_H */
diff --git a/source/blender/python/generic/mathutils_quat.c b/source/blender/python/generic/mathutils_quat.c
index 7507318dfcb..56757ae5d2d 100644
--- a/source/blender/python/generic/mathutils_quat.c
+++ b/source/blender/python/generic/mathutils_quat.c
@@ -20,7 +20,7 @@
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
* All rights reserved.
*
- *
+ *
* Contributor(s): Joseph Gilbert
*
* ***** END GPL LICENSE BLOCK *****
@@ -31,14 +31,26 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#define QUAT_SIZE 4
+#define QUAT_APPLY_TO_COPY(quat_meth_noargs, _self) \
+ QuaternionObject *ret= (QuaternionObject *)Quaternion_copy(_self); \
+ PyObject *ret_dummy= quat_meth_noargs(ret); \
+ if(ret_dummy) { \
+ Py_DECREF(ret_dummy); \
+ return (PyObject *)ret; \
+ } \
+ else { /* error */ \
+ Py_DECREF(ret); \
+ return NULL; \
+ } \
-#define QUAT_SIZE 4
+static PyObject *Quaternion_copy(QuaternionObject *self);
//-----------------------------METHODS------------------------------
/* note: BaseMath_ReadCallback must be called beforehand */
-static PyObject *Quaternion_ToTupleExt(QuaternionObject *self, int ndigits)
+static PyObject *Quaternion_to_tuple_ext(QuaternionObject *self, int ndigits)
{
PyObject *ret;
int i;
@@ -59,7 +71,7 @@ static PyObject *Quaternion_ToTupleExt(QuaternionObject *self, int ndigits)
return ret;
}
-static char Quaternion_ToEuler_doc[] =
+static char Quaternion_to_euler_doc[] =
".. method:: to_euler(order, euler_compat)\n"
"\n"
" Return Euler representation of the quaternion.\n"
@@ -69,19 +81,19 @@ static char Quaternion_ToEuler_doc[] =
" :arg euler_compat: Optional euler argument the new euler will be made compatible with (no axis flipping between them). Useful for converting a series of matrices to animation curves.\n"
" :type euler_compat: :class:`Euler`\n"
" :return: Euler representation of the quaternion.\n"
-" :rtype: :class:`Euler`\n";
-
-static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
+" :rtype: :class:`Euler`\n"
+;
+static PyObject *Quaternion_to_euler(QuaternionObject *self, PyObject *args)
{
float tquat[4];
float eul[3];
- char *order_str= NULL;
+ const char *order_str= NULL;
short order= EULER_ORDER_XYZ;
EulerObject *eul_compat = NULL;
-
+
if(!PyArg_ParseTuple(args, "|sO!:to_euler", &order_str, &euler_Type, &eul_compat))
return NULL;
-
+
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -91,15 +103,15 @@ static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
if(order == -1)
return NULL;
}
-
+
normalize_qt_qt(tquat, self->quat);
if(eul_compat) {
float mat[3][3];
-
+
if(!BaseMath_ReadCallback(eul_compat))
return NULL;
-
+
quat_to_mat3(mat, tquat);
if(order == EULER_ORDER_XYZ) mat3_to_compatible_eul(eul, eul_compat->eul, mat);
@@ -109,19 +121,19 @@ static PyObject *Quaternion_ToEuler(QuaternionObject * self, PyObject *args)
if(order == EULER_ORDER_XYZ) quat_to_eul(eul, tquat);
else quat_to_eulO(eul, order, tquat);
}
-
+
return newEulerObject(eul, order, Py_NEW, NULL);
}
//----------------------------Quaternion.toMatrix()------------------
-static char Quaternion_ToMatrix_doc[] =
+static char Quaternion_to_matrix_doc[] =
".. method:: to_matrix()\n"
"\n"
" Return a matrix representation of the quaternion.\n"
"\n"
" :return: A 3x3 rotation matrix representation of the quaternion.\n"
-" :rtype: :class:`Matrix`\n";
-
-static PyObject *Quaternion_ToMatrix(QuaternionObject * self)
+" :rtype: :class:`Matrix`\n"
+;
+static PyObject *Quaternion_to_matrix(QuaternionObject *self)
{
float mat[9]; /* all values are set */
@@ -133,7 +145,7 @@ static PyObject *Quaternion_ToMatrix(QuaternionObject * self)
}
//----------------------------Quaternion.cross(other)------------------
-static char Quaternion_Cross_doc[] =
+static char Quaternion_cross_doc[] =
".. method:: cross(other)\n"
"\n"
" Return the cross product of this quaternion and another.\n"
@@ -141,26 +153,24 @@ static char Quaternion_Cross_doc[] =
" :arg other: The other quaternion to perform the cross product with.\n"
" :type other: :class:`Quaternion`\n"
" :return: The cross product.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Quaternion_Cross(QuaternionObject *self, QuaternionObject *value)
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_cross(QuaternionObject *self, PyObject *value)
{
- float quat[QUAT_SIZE];
-
- if (!QuaternionObject_Check(value)) {
- PyErr_Format(PyExc_TypeError, "quat.cross(value): expected a quaternion argument, not %.200s", Py_TYPE(value)->tp_name);
+ float quat[QUAT_SIZE], tquat[QUAT_SIZE];
+
+ if(!BaseMath_ReadCallback(self))
return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+
+ if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.cross(other), invalid 'other' arg") == -1)
return NULL;
- mul_qt_qtqt(quat, self->quat, value->quat);
+ mul_qt_qtqt(quat, self->quat, tquat);
return newQuaternionObject(quat, Py_NEW, Py_TYPE(self));
}
//----------------------------Quaternion.dot(other)------------------
-static char Quaternion_Dot_doc[] =
+static char Quaternion_dot_doc[] =
".. method:: dot(other)\n"
"\n"
" Return the dot product of this quaternion and another.\n"
@@ -168,22 +178,22 @@ static char Quaternion_Dot_doc[] =
" :arg other: The other quaternion to perform the dot product with.\n"
" :type other: :class:`Quaternion`\n"
" :return: The dot product.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Quaternion_Dot(QuaternionObject * self, QuaternionObject * value)
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_dot(QuaternionObject *self, PyObject *value)
{
- if (!QuaternionObject_Check(value)) {
- PyErr_Format(PyExc_TypeError, "quat.dot(value): expected a quaternion argument, not %.200s", Py_TYPE(value)->tp_name);
+ float tquat[QUAT_SIZE];
+
+ if(!BaseMath_ReadCallback(self))
return NULL;
- }
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+ if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.dot(other), invalid 'other' arg") == -1)
return NULL;
- return PyFloat_FromDouble(dot_qtqt(self->quat, value->quat));
+ return PyFloat_FromDouble(dot_qtqt(self->quat, tquat));
}
-static char Quaternion_Difference_doc[] =
+static char Quaternion_difference_doc[] =
".. function:: difference(other)\n"
"\n"
" Returns a quaternion representing the rotational difference.\n"
@@ -191,26 +201,24 @@ static char Quaternion_Difference_doc[] =
" :arg other: second quaternion.\n"
" :type other: :class:`Quaternion`\n"
" :return: the rotational difference between the two quat rotations.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Quaternion_Difference(QuaternionObject * self, QuaternionObject * value)
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_difference(QuaternionObject *self, PyObject *value)
{
- float quat[QUAT_SIZE];
+ float tquat[QUAT_SIZE], quat[QUAT_SIZE];
- if (!QuaternionObject_Check(value)) {
- PyErr_Format(PyExc_TypeError, "quat.difference(value): expected a quaternion argument, not %.200s", Py_TYPE(value)->tp_name);
+ if(!BaseMath_ReadCallback(self))
return NULL;
- }
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+ if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.difference(other), invalid 'other' arg") == -1)
return NULL;
- rotation_between_quats_to_quat(quat, self->quat, value->quat);
+ rotation_between_quats_to_quat(quat, self->quat, tquat);
return newQuaternionObject(quat, Py_NEW, Py_TYPE(self));
}
-static char Quaternion_Slerp_doc[] =
+static char Quaternion_slerp_doc[] =
".. function:: slerp(other, factor)\n"
"\n"
" Returns the interpolation of two quaternions.\n"
@@ -220,19 +228,22 @@ static char Quaternion_Slerp_doc[] =
" :arg factor: The interpolation value in [0.0, 1.0].\n"
" :type factor: float\n"
" :return: The interpolated rotation.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Quaternion_Slerp(QuaternionObject *self, PyObject *args)
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_slerp(QuaternionObject *self, PyObject *args)
{
- QuaternionObject *value;
- float quat[QUAT_SIZE], fac;
+ PyObject *value;
+ float tquat[QUAT_SIZE], quat[QUAT_SIZE], fac;
- if(!PyArg_ParseTuple(args, "O!f:slerp", &quaternion_Type, &value, &fac)) {
+ if(!PyArg_ParseTuple(args, "Of:slerp", &value, &fac)) {
PyErr_SetString(PyExc_TypeError, "quat.slerp(): expected Quaternion types and float");
return NULL;
}
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+ if(!BaseMath_ReadCallback(self))
+ return NULL;
+
+ if(mathutils_array_parse(tquat, QUAT_SIZE, QUAT_SIZE, value, "quaternion.slerp(other), invalid 'other' arg") == -1)
return NULL;
if(fac > 1.0f || fac < 0.0f) {
@@ -240,22 +251,49 @@ static PyObject *Quaternion_Slerp(QuaternionObject *self, PyObject *args)
return NULL;
}
- interp_qt_qtqt(quat, self->quat, value->quat, fac);
+ interp_qt_qtqt(quat, self->quat, tquat, fac);
return newQuaternionObject(quat, Py_NEW, Py_TYPE(self));
}
+static char Quaternion_rotate_doc[] =
+".. method:: rotate(other)\n"
+"\n"
+" Rotates the quaternion a by another mathutils value.\n"
+"\n"
+" :arg other: rotation component of mathutils value\n"
+" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
+;
+static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value)
+{
+ float self_rmat[3][3], other_rmat[3][3], rmat[3][3];
+ float tquat[4], length;
+
+ if(!BaseMath_ReadCallback(self))
+ return NULL;
+
+ if(mathutils_any_to_rotmat(other_rmat, value, "quaternion.rotate(value)") == -1)
+ return NULL;
+
+ length= normalize_qt_qt(tquat, self->quat);
+ quat_to_mat3(self_rmat, tquat);
+ mul_m3_m3m3(rmat, self_rmat, other_rmat);
+
+ mat3_to_quat(self->quat, rmat);
+ mul_qt_fl(self->quat, length); /* maintain length after rotating */
+
+ (void)BaseMath_WriteCallback(self);
+ Py_RETURN_NONE;
+}
+
//----------------------------Quaternion.normalize()----------------
//normalize the axis of rotation of [theta,vector]
-static char Quaternion_Normalize_doc[] =
+static char Quaternion_normalize_doc[] =
".. function:: normalize()\n"
"\n"
" Normalize the quaternion.\n"
-"\n"
-" :return: an instance of itself.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Quaternion_Normalize(QuaternionObject * self)
+;
+static PyObject *Quaternion_normalize(QuaternionObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -263,19 +301,28 @@ static PyObject *Quaternion_Normalize(QuaternionObject * self)
normalize_qt(self->quat);
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
}
-//----------------------------Quaternion.inverse()------------------
-static char Quaternion_Inverse_doc[] =
-".. function:: inverse()\n"
+static char Quaternion_normalized_doc[] =
+".. function:: normalized()\n"
"\n"
-" Set the quaternion to its inverse.\n"
+" Return a new normalized quaternion.\n"
"\n"
-" :return: an instance of itself.\n"
-" :rtype: :class:`Quaternion`\n";
+" :return: a normalized copy.\n"
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_normalized(QuaternionObject *self)
+{
+ QUAT_APPLY_TO_COPY(Quaternion_normalize, self);
+}
-static PyObject *Quaternion_Inverse(QuaternionObject * self)
+//----------------------------Quaternion.invert()------------------
+static char Quaternion_invert_doc[] =
+".. function:: invert()\n"
+"\n"
+" Set the quaternion to its inverse.\n"
+;
+static PyObject *Quaternion_invert(QuaternionObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -283,19 +330,31 @@ static PyObject *Quaternion_Inverse(QuaternionObject * self)
invert_qt(self->quat);
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
+}
+static char Quaternion_inverted_doc[] =
+".. function:: inverted()\n"
+"\n"
+" Return a new, inverted quaternion.\n"
+"\n"
+" :return: the inverted value.\n"
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_inverted(QuaternionObject *self)
+{
+ QUAT_APPLY_TO_COPY(Quaternion_invert, self);
}
+
//----------------------------Quaternion.identity()-----------------
-static char Quaternion_Identity_doc[] =
+static char Quaternion_identity_doc[] =
".. function:: identity()\n"
"\n"
" Set the quaternion to an identity quaternion.\n"
"\n"
" :return: an instance of itself.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Quaternion_Identity(QuaternionObject * self)
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_identity(QuaternionObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -303,19 +362,18 @@ static PyObject *Quaternion_Identity(QuaternionObject * self)
unit_qt(self->quat);
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
}
//----------------------------Quaternion.negate()-------------------
-static char Quaternion_Negate_doc[] =
+static char Quaternion_negate_doc[] =
".. function:: negate()\n"
"\n"
" Set the quaternion to its negative.\n"
"\n"
" :return: an instance of itself.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Quaternion_Negate(QuaternionObject * self)
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_negate(QuaternionObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -323,19 +381,15 @@ static PyObject *Quaternion_Negate(QuaternionObject * self)
mul_qt_fl(self->quat, -1.0f);
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
}
//----------------------------Quaternion.conjugate()----------------
-static char Quaternion_Conjugate_doc[] =
+static char Quaternion_conjugate_doc[] =
".. function:: conjugate()\n"
"\n"
" Set the quaternion to its conjugate (negate x, y, z).\n"
-"\n"
-" :return: an instance of itself.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Quaternion_Conjugate(QuaternionObject * self)
+;
+static PyObject *Quaternion_conjugate(QuaternionObject *self)
{
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -343,9 +397,21 @@ static PyObject *Quaternion_Conjugate(QuaternionObject * self)
conjugate_qt(self->quat);
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
}
+static char Quaternion_conjugated_doc[] =
+".. function:: conjugated()\n"
+"\n"
+" Return a new conjugated quaternion.\n"
+"\n"
+" :return: a new quaternion.\n"
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Quaternion_conjugated(QuaternionObject *self)
+{
+ QUAT_APPLY_TO_COPY(Quaternion_conjugate, self);
+}
+
//----------------------------Quaternion.copy()----------------
static char Quaternion_copy_doc[] =
".. function:: copy()\n"
@@ -355,8 +421,8 @@ static char Quaternion_copy_doc[] =
" :return: A copy of the quaternion.\n"
" :rtype: :class:`Quaternion`\n"
"\n"
-" .. note:: use this to get a copy of a wrapped quaternion with no reference to the original data.\n";
-
+" .. note:: use this to get a copy of a wrapped quaternion with no reference to the original data.\n"
+;
static PyObject *Quaternion_copy(QuaternionObject *self)
{
if(!BaseMath_ReadCallback(self))
@@ -367,14 +433,14 @@ static PyObject *Quaternion_copy(QuaternionObject *self)
//----------------------------print object (internal)--------------
//print the object to screen
-static PyObject *Quaternion_repr(QuaternionObject * self)
+static PyObject *Quaternion_repr(QuaternionObject *self)
{
PyObject *ret, *tuple;
-
+
if(!BaseMath_ReadCallback(self))
return NULL;
- tuple= Quaternion_ToTupleExt(self, -1);
+ tuple= Quaternion_to_tuple_ext(self, -1);
ret= PyUnicode_FromFormat("Quaternion(%R)", tuple);
@@ -382,53 +448,40 @@ static PyObject *Quaternion_repr(QuaternionObject * self)
return ret;
}
-//------------------------tp_richcmpr
-//returns -1 execption, 0 false, 1 true
-static PyObject* Quaternion_richcmpr(PyObject *objectA, PyObject *objectB, int comparison_type)
+static PyObject* Quaternion_richcmpr(PyObject *a, PyObject *b, int op)
{
- QuaternionObject *quatA = NULL, *quatB = NULL;
- int result = 0;
+ PyObject *res;
+ int ok= -1; /* zero is true */
- if(QuaternionObject_Check(objectA)) {
- quatA = (QuaternionObject*)objectA;
- if(!BaseMath_ReadCallback(quatA))
- return NULL;
- }
- if(QuaternionObject_Check(objectB)) {
- quatB = (QuaternionObject*)objectB;
- if(!BaseMath_ReadCallback(quatB))
+ if (QuaternionObject_Check(a) && QuaternionObject_Check(b)) {
+ QuaternionObject *quatA= (QuaternionObject *)a;
+ QuaternionObject *quatB= (QuaternionObject *)b;
+
+ if(!BaseMath_ReadCallback(quatA) || !BaseMath_ReadCallback(quatB))
return NULL;
- }
- if (!quatA || !quatB){
- if (comparison_type == Py_NE){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
- }
+ ok= (EXPP_VectorsAreEqual(quatA->quat, quatB->quat, QUAT_SIZE, 1)) ? 0 : -1;
}
- switch (comparison_type){
- case Py_EQ:
- result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, QUAT_SIZE, 1);
- break;
- case Py_NE:
- result = EXPP_VectorsAreEqual(quatA->quat, quatB->quat, QUAT_SIZE, 1);
- if (result == 0){
- result = 1;
- }else{
- result = 0;
- }
- break;
- default:
- printf("The result of the comparison could not be evaluated");
- break;
- }
- if (result == 1){
- Py_RETURN_TRUE;
- }else{
- Py_RETURN_FALSE;
+ switch (op) {
+ case Py_NE:
+ ok = !ok; /* pass through */
+ case Py_EQ:
+ res = ok ? Py_False : Py_True;
+ break;
+
+ case Py_LT:
+ case Py_LE:
+ case Py_GT:
+ case Py_GE:
+ res = Py_NotImplemented;
+ break;
+ default:
+ PyErr_BadArgument();
+ return NULL;
}
+
+ return Py_INCREF(res), res;
}
//---------------------SEQUENCE PROTOCOLS------------------------
@@ -440,7 +493,7 @@ static int Quaternion_len(QuaternionObject *UNUSED(self))
}
//----------------------------object[]---------------------------
//sequence accessor (get)
-static PyObject *Quaternion_item(QuaternionObject * self, int i)
+static PyObject *Quaternion_item(QuaternionObject *self, int i)
{
if(i<0) i= QUAT_SIZE-i;
@@ -457,7 +510,7 @@ static PyObject *Quaternion_item(QuaternionObject * self, int i)
}
//----------------------------object[]-------------------------
//sequence accessor (set)
-static int Quaternion_ass_item(QuaternionObject * self, int i, PyObject * ob)
+static int Quaternion_ass_item(QuaternionObject *self, int i, PyObject *ob)
{
float scalar= (float)PyFloat_AsDouble(ob);
if(scalar==-1.0f && PyErr_Occurred()) { /* parsed item not a number */
@@ -480,7 +533,7 @@ static int Quaternion_ass_item(QuaternionObject * self, int i, PyObject * ob)
}
//----------------------------object[z:y]------------------------
//sequence slice (get)
-static PyObject *Quaternion_slice(QuaternionObject * self, int begin, int end)
+static PyObject *Quaternion_slice(QuaternionObject *self, int begin, int end)
{
PyObject *tuple;
int count;
@@ -502,7 +555,7 @@ static PyObject *Quaternion_slice(QuaternionObject * self, int begin, int end)
}
//----------------------------object[z:y]------------------------
//sequence slice (set)
-static int Quaternion_ass_slice(QuaternionObject * self, int begin, int end, PyObject * seq)
+static int Quaternion_ass_slice(QuaternionObject *self, int begin, int end, PyObject *seq)
{
int i, size;
float quat[QUAT_SIZE];
@@ -517,7 +570,7 @@ static int Quaternion_ass_slice(QuaternionObject * self, int begin, int end, PyO
if((size=mathutils_array_parse(quat, 0, QUAT_SIZE, seq, "mathutils.Quaternion[begin:end] = []")) == -1)
return -1;
-
+
if(size != (end - begin)){
PyErr_SetString(PyExc_TypeError, "quaternion[begin:end] = []: size mismatch in slice assignment");
return -1;
@@ -549,7 +602,7 @@ static PyObject *Quaternion_subscript(QuaternionObject *self, PyObject *item)
return NULL;
if (slicelength <= 0) {
- return PyList_New(0);
+ return PyTuple_New(0);
}
else if (step == 1) {
return Quaternion_slice(self, start, stop);
@@ -598,7 +651,7 @@ static int Quaternion_ass_subscript(QuaternionObject *self, PyObject *item, PyOb
//------------------------NUMERIC PROTOCOLS----------------------
//------------------------obj + obj------------------------------
//addition
-static PyObject *Quaternion_add(PyObject * q1, PyObject * q2)
+static PyObject *Quaternion_add(PyObject *q1, PyObject *q2)
{
float quat[QUAT_SIZE];
QuaternionObject *quat1 = NULL, *quat2 = NULL;
@@ -609,7 +662,7 @@ static PyObject *Quaternion_add(PyObject * q1, PyObject * q2)
}
quat1 = (QuaternionObject*)q1;
quat2 = (QuaternionObject*)q2;
-
+
if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2))
return NULL;
@@ -618,7 +671,7 @@ static PyObject *Quaternion_add(PyObject * q1, PyObject * q2)
}
//------------------------obj - obj------------------------------
//subtraction
-static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2)
+static PyObject *Quaternion_sub(PyObject *q1, PyObject *q2)
{
int x;
float quat[QUAT_SIZE];
@@ -628,10 +681,10 @@ static PyObject *Quaternion_sub(PyObject * q1, PyObject * q2)
PyErr_SetString(PyExc_AttributeError, "Quaternion addition: arguments not valid for this operation");
return NULL;
}
-
+
quat1 = (QuaternionObject*)q1;
quat2 = (QuaternionObject*)q2;
-
+
if(!BaseMath_ReadCallback(quat1) || !BaseMath_ReadCallback(quat2))
return NULL;
@@ -652,7 +705,7 @@ static PyObject *quat_mul_float(QuaternionObject *quat, const float scalar)
//------------------------obj * obj------------------------------
//mulplication
-static PyObject *Quaternion_mul(PyObject * q1, PyObject * q2)
+static PyObject *Quaternion_mul(PyObject *q1, PyObject *q2)
{
float quat[QUAT_SIZE], scalar;
QuaternionObject *quat1 = NULL, *quat2 = NULL;
@@ -748,17 +801,17 @@ static PyNumberMethods Quaternion_NumMethods = {
0, /* nb_index */
};
-static PyObject *Quaternion_getAxis( QuaternionObject * self, void *type )
+static PyObject *Quaternion_getAxis( QuaternionObject *self, void *type )
{
return Quaternion_item(self, GET_INT_FROM_POINTER(type));
}
-static int Quaternion_setAxis( QuaternionObject * self, PyObject * value, void * type )
+static int Quaternion_setAxis( QuaternionObject *self, PyObject *value, void *type )
{
return Quaternion_ass_item(self, GET_INT_FROM_POINTER(type), value);
}
-static PyObject *Quaternion_getMagnitude(QuaternionObject * self, void *UNUSED(closure))
+static PyObject *Quaternion_getMagnitude(QuaternionObject *self, void *UNUSED(closure))
{
if(!BaseMath_ReadCallback(self))
return NULL;
@@ -766,7 +819,7 @@ static PyObject *Quaternion_getMagnitude(QuaternionObject * self, void *UNUSED(c
return PyFloat_FromDouble(sqrt(dot_qtqt(self->quat, self->quat)));
}
-static PyObject *Quaternion_getAngle(QuaternionObject * self, void *UNUSED(closure))
+static PyObject *Quaternion_getAngle(QuaternionObject *self, void *UNUSED(closure))
{
float tquat[4];
@@ -777,11 +830,11 @@ static PyObject *Quaternion_getAngle(QuaternionObject * self, void *UNUSED(closu
return PyFloat_FromDouble(2.0 * (saacos(tquat[0])));
}
-static int Quaternion_setAngle(QuaternionObject * self, PyObject * value, void *UNUSED(closure))
+static int Quaternion_setAngle(QuaternionObject *self, PyObject *value, void *UNUSED(closure))
{
float tquat[4];
float len;
-
+
float axis[3], angle_dummy;
double angle;
@@ -807,7 +860,7 @@ static int Quaternion_setAngle(QuaternionObject * self, PyObject * value, void *
) {
axis[0] = 1.0f;
}
-
+
axis_angle_to_quat(self->quat, axis, angle);
mul_qt_fl(self->quat, len);
@@ -820,7 +873,7 @@ static int Quaternion_setAngle(QuaternionObject * self, PyObject * value, void *
static PyObject *Quaternion_getAxisVec(QuaternionObject *self, void *UNUSED(closure))
{
float tquat[4];
-
+
float axis[3];
float angle;
@@ -848,26 +901,17 @@ static int Quaternion_setAxisVec(QuaternionObject *self, PyObject *value, void *
float axis[3];
float angle;
-
- VectorObject *vec;
-
if(!BaseMath_ReadCallback(self))
return -1;
len= normalize_qt_qt(tquat, self->quat);
- quat_to_axis_angle(axis, &angle, tquat);
+ quat_to_axis_angle(axis, &angle, tquat); /* axis value is unused */
- if(!VectorObject_Check(value)) {
- PyErr_SetString(PyExc_TypeError, "quaternion.axis = value: expected a 3D Vector");
- return -1;
- }
-
- vec= (VectorObject *)value;
- if(!BaseMath_ReadCallback(vec))
+ if (mathutils_array_parse(axis, 3, 3, value, "quat.axis = other") == -1)
return -1;
- axis_angle_to_quat(self->quat, vec->vec, angle);
+ axis_angle_to_quat(self->quat, axis, angle);
mul_qt_fl(self->quat, len);
if(!BaseMath_WriteCallback(self))
@@ -887,7 +931,7 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
PyErr_SetString(PyExc_TypeError, "mathutils.Quaternion(): takes no keyword args");
return NULL;
}
-
+
if(!PyArg_ParseTuple(args, "|Od:mathutils.Quaternion", &seq, &angle))
return NULL;
@@ -912,17 +956,31 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
//-----------------------METHOD DEFINITIONS ----------------------
static struct PyMethodDef Quaternion_methods[] = {
- {"identity", (PyCFunction) Quaternion_Identity, METH_NOARGS, Quaternion_Identity_doc},
- {"negate", (PyCFunction) Quaternion_Negate, METH_NOARGS, Quaternion_Negate_doc},
- {"conjugate", (PyCFunction) Quaternion_Conjugate, METH_NOARGS, Quaternion_Conjugate_doc},
- {"inverse", (PyCFunction) Quaternion_Inverse, METH_NOARGS, Quaternion_Inverse_doc},
- {"normalize", (PyCFunction) Quaternion_Normalize, METH_NOARGS, Quaternion_Normalize_doc},
- {"to_euler", (PyCFunction) Quaternion_ToEuler, METH_VARARGS, Quaternion_ToEuler_doc},
- {"to_matrix", (PyCFunction) Quaternion_ToMatrix, METH_NOARGS, Quaternion_ToMatrix_doc},
- {"cross", (PyCFunction) Quaternion_Cross, METH_O, Quaternion_Cross_doc},
- {"dot", (PyCFunction) Quaternion_Dot, METH_O, Quaternion_Dot_doc},
- {"difference", (PyCFunction) Quaternion_Difference, METH_O, Quaternion_Difference_doc},
- {"slerp", (PyCFunction) Quaternion_Slerp, METH_VARARGS, Quaternion_Slerp_doc},
+ /* in place only */
+ {"identity", (PyCFunction) Quaternion_identity, METH_NOARGS, Quaternion_identity_doc},
+ {"negate", (PyCFunction) Quaternion_negate, METH_NOARGS, Quaternion_negate_doc},
+
+ /* operate on original or copy */
+ {"conjugate", (PyCFunction) Quaternion_conjugate, METH_NOARGS, Quaternion_conjugate_doc},
+ {"conjugated", (PyCFunction) Quaternion_conjugated, METH_NOARGS, Quaternion_conjugated_doc},
+
+ {"invert", (PyCFunction) Quaternion_invert, METH_NOARGS, Quaternion_invert_doc},
+ {"inverted", (PyCFunction) Quaternion_inverted, METH_NOARGS, Quaternion_inverted_doc},
+
+ {"normalize", (PyCFunction) Quaternion_normalize, METH_NOARGS, Quaternion_normalize_doc},
+ {"normalized", (PyCFunction) Quaternion_normalized, METH_NOARGS, Quaternion_normalized_doc},
+
+ /* return converted representation */
+ {"to_euler", (PyCFunction) Quaternion_to_euler, METH_VARARGS, Quaternion_to_euler_doc},
+ {"to_matrix", (PyCFunction) Quaternion_to_matrix, METH_NOARGS, Quaternion_to_matrix_doc},
+
+ /* operation between 2 or more types */
+ {"cross", (PyCFunction) Quaternion_cross, METH_O, Quaternion_cross_doc},
+ {"dot", (PyCFunction) Quaternion_dot, METH_O, Quaternion_dot_doc},
+ {"difference", (PyCFunction) Quaternion_difference, METH_O, Quaternion_difference_doc},
+ {"slerp", (PyCFunction) Quaternion_slerp, METH_VARARGS, Quaternion_slerp_doc},
+ {"rotate", (PyCFunction) Quaternion_rotate, METH_VARARGS, Quaternion_rotate_doc},
+
{"__copy__", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
{"copy", (PyCFunction) Quaternion_copy, METH_NOARGS, Quaternion_copy_doc},
{NULL, NULL, 0, NULL}
@@ -946,8 +1004,8 @@ static PyGetSetDef Quaternion_getseters[] = {
//------------------PY_OBECT DEFINITION--------------------------
static char quaternion_doc[] =
-"This object gives access to Quaternions in Blender.";
-
+"This object gives access to Quaternions in Blender."
+;
PyTypeObject quaternion_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"mathutils.Quaternion", //tp_name
@@ -1005,7 +1063,7 @@ PyTypeObject quaternion_Type = {
PyObject *newQuaternionObject(float *quat, int type, PyTypeObject *base_type)
{
QuaternionObject *self;
-
+
if(base_type) self = (QuaternionObject *)base_type->tp_alloc(base_type, 0);
else self = PyObject_NEW(QuaternionObject, &quaternion_Type);
diff --git a/source/blender/python/generic/mathutils_vector.c b/source/blender/python/generic/mathutils_vector.c
index de6002859d3..da0da6ddba6 100644
--- a/source/blender/python/generic/mathutils_vector.c
+++ b/source/blender/python/generic/mathutils_vector.c
@@ -31,9 +31,20 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#define MAX_DIMENSIONS 4
+#define VEC_APPLY_TO_COPY(vec_meth_noargs, _self) \
+ VectorObject *ret= (VectorObject *)Vector_copy(_self); \
+ PyObject *ret_dummy= vec_meth_noargs(ret); \
+ if(ret_dummy) { \
+ Py_DECREF(ret_dummy); \
+ return (PyObject *)ret; \
+ } \
+ else { /* error */ \
+ Py_DECREF(ret); \
+ return NULL; \
+ } \
-#define MAX_DIMENSIONS 4
/* Swizzle axes get packed into a single value that is used as a closure. Each
axis uses SWIZZLE_BITS_PER_AXIS bits. The first bit (SWIZZLE_VALID_AXIS) is
used as a sentinel: if it is unset, the axis is not valid. */
@@ -41,11 +52,12 @@
#define SWIZZLE_VALID_AXIS 0x4
#define SWIZZLE_AXIS 0x3
-static PyObject *Vector_ToTupleExt(VectorObject *self, int ndigits);
+static PyObject *Vector_copy(VectorObject *self);
+static PyObject *Vector_to_tuple_ext(VectorObject *self, int ndigits);
-//----------------------------------mathutils.Vector() ------------------
-// Supports 2D, 3D, and 4D vector objects both int and float values
-// accepted. Mixed float and int values accepted. Ints are parsed to float
+/* Supports 2D, 3D, and 4D vector objects both int and float values
+ * accepted. Mixed float and int values accepted. Ints are parsed to float
+ */
static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *UNUSED(kwds))
{
float vec[4]= {0.0f, 0.0f, 0.0f, 0.0f};
@@ -66,36 +78,29 @@ static PyObject *Vector_new(PyTypeObject *type, PyObject *args, PyObject *UNUSED
}
/*-----------------------------METHODS---------------------------- */
-static char Vector_Zero_doc[] =
+static char Vector_zero_doc[] =
".. method:: zero()\n"
"\n"
" Set all values to zero.\n"
-"\n"
-" :return: an instance of itself\n"
-" :rtype: :class:`Vector`\n";
-
-static PyObject *Vector_Zero(VectorObject *self)
+;
+static PyObject *Vector_zero(VectorObject *self)
{
fill_vn(self->vec, self->size, 0.0f);
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
}
-/*----------------------------Vector.normalize() ----------------- */
-static char Vector_Normalize_doc[] =
+
+static char Vector_normalize_doc[] =
".. method:: normalize()\n"
"\n"
" Normalize the vector, making the length of the vector always 1.0.\n"
"\n"
-" :return: an instance of itself\n"
-" :rtype: :class:`Vector`\n"
-"\n"
" .. warning:: Normalizing a vector where all values are zero results in all axis having a nan value (not a number).\n"
"\n"
-" .. note:: Normalize works for vectors of all sizes, however 4D Vectors w axis is left untouched.\n";
-
-static PyObject *Vector_Normalize(VectorObject *self)
+" .. note:: Normalize works for vectors of all sizes, however 4D Vectors w axis is left untouched.\n"
+;
+static PyObject *Vector_normalize(VectorObject *self)
{
int i;
float norm = 0.0f;
@@ -112,64 +117,72 @@ static PyObject *Vector_Normalize(VectorObject *self)
}
(void)BaseMath_WriteCallback(self);
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
+}
+static char Vector_normalized_doc[] =
+".. method:: normalized()\n"
+"\n"
+" Return a new, normalized vector.\n"
+"\n"
+" :return: a normalized copy of the vector\n"
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_normalized(VectorObject *self)
+{
+ VEC_APPLY_TO_COPY(Vector_normalize, self);
}
-
-/*----------------------------Vector.resize2D() ------------------ */
-static char Vector_Resize2D_doc[] =
-".. method:: resize2D()\n"
+static char Vector_resize_2d_doc[] =
+".. method:: resize_2d()\n"
"\n"
" Resize the vector to 2D (x, y).\n"
"\n"
" :return: an instance of itself\n"
-" :rtype: :class:`Vector`\n";
-
-static PyObject *Vector_Resize2D(VectorObject *self)
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_resize_2d(VectorObject *self)
{
if(self->wrapped==Py_WRAP) {
- PyErr_SetString(PyExc_TypeError, "vector.resize2D(): cannot resize wrapped data - only python vectors");
+ PyErr_SetString(PyExc_TypeError, "vector.resize_2d(): cannot resize wrapped data - only python vectors");
return NULL;
}
if(self->cb_user) {
- PyErr_SetString(PyExc_TypeError, "vector.resize2D(): cannot resize a vector that has an owner");
+ PyErr_SetString(PyExc_TypeError, "vector.resize_2d(): cannot resize a vector that has an owner");
return NULL;
}
self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 2));
if(self->vec == NULL) {
- PyErr_SetString(PyExc_MemoryError, "vector.resize2D(): problem allocating pointer space");
+ PyErr_SetString(PyExc_MemoryError, "vector.resize_2d(): problem allocating pointer space");
return NULL;
}
self->size = 2;
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
}
-/*----------------------------Vector.resize3D() ------------------ */
-static char Vector_Resize3D_doc[] =
-".. method:: resize3D()\n"
+
+static char Vector_resize_3d_doc[] =
+".. method:: resize_3d()\n"
"\n"
" Resize the vector to 3D (x, y, z).\n"
"\n"
" :return: an instance of itself\n"
-" :rtype: :class:`Vector`\n";
-
-static PyObject *Vector_Resize3D(VectorObject *self)
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_resize_3d(VectorObject *self)
{
if (self->wrapped==Py_WRAP) {
- PyErr_SetString(PyExc_TypeError, "vector.resize3D(): cannot resize wrapped data - only python vectors");
+ PyErr_SetString(PyExc_TypeError, "vector.resize_3d(): cannot resize wrapped data - only python vectors");
return NULL;
}
if(self->cb_user) {
- PyErr_SetString(PyExc_TypeError, "vector.resize3D(): cannot resize a vector that has an owner");
+ PyErr_SetString(PyExc_TypeError, "vector.resize_3d(): cannot resize a vector that has an owner");
return NULL;
}
self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 3));
if(self->vec == NULL) {
- PyErr_SetString(PyExc_MemoryError, "vector.resize3D(): problem allocating pointer space");
+ PyErr_SetString(PyExc_MemoryError, "vector.resize_3d(): problem allocating pointer space");
return NULL;
}
@@ -177,32 +190,31 @@ static PyObject *Vector_Resize3D(VectorObject *self)
self->vec[2] = 0.0f;
self->size = 3;
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
}
-/*----------------------------Vector.resize4D() ------------------ */
-static char Vector_Resize4D_doc[] =
-".. method:: resize4D()\n"
+
+static char Vector_resize_4d_doc[] =
+".. method:: resize_4d()\n"
"\n"
" Resize the vector to 4D (x, y, z, w).\n"
"\n"
" :return: an instance of itself\n"
-" :rtype: :class:`Vector`\n";
-
-static PyObject *Vector_Resize4D(VectorObject *self)
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_resize_4d(VectorObject *self)
{
if(self->wrapped==Py_WRAP) {
- PyErr_SetString(PyExc_TypeError, "vector.resize4D(): cannot resize wrapped data - only python vectors");
+ PyErr_SetString(PyExc_TypeError, "vector.resize_4d(): cannot resize wrapped data - only python vectors");
return NULL;
}
if(self->cb_user) {
- PyErr_SetString(PyExc_TypeError, "vector.resize4D(): cannot resize a vector that has an owner");
+ PyErr_SetString(PyExc_TypeError, "vector.resize_4d(): cannot resize a vector that has an owner");
return NULL;
}
self->vec = PyMem_Realloc(self->vec, (sizeof(float) * 4));
if(self->vec == NULL) {
- PyErr_SetString(PyExc_MemoryError, "vector.resize4D(): problem allocating pointer space");
+ PyErr_SetString(PyExc_MemoryError, "vector.resize_4d(): problem allocating pointer space");
return NULL;
}
if(self->size == 2){
@@ -212,12 +224,61 @@ static PyObject *Vector_Resize4D(VectorObject *self)
self->vec[3] = 1.0f;
}
self->size = 4;
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
}
+static char Vector_to_2d_doc[] =
+".. method:: to_2d()\n"
+"\n"
+" Return a 2d copy of the vector.\n"
+"\n"
+" :return: a new vector\n"
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_to_2d(VectorObject *self)
+{
+ if(!BaseMath_ReadCallback(self))
+ return NULL;
-/*----------------------------Vector.toTuple() ------------------ */
-static char Vector_ToTuple_doc[] =
+ return newVectorObject(self->vec, 2, Py_NEW, Py_TYPE(self));
+}
+static char Vector_to_3d_doc[] =
+".. method:: to_3d()\n"
+"\n"
+" Return a 3d copy of the vector.\n"
+"\n"
+" :return: a new vector\n"
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_to_3d(VectorObject *self)
+{
+ float tvec[3]= {0.0f};
+
+ if(!BaseMath_ReadCallback(self))
+ return NULL;
+
+ memcpy(tvec, self->vec, sizeof(float) * MIN2(self->size, 3));
+ return newVectorObject(tvec, 3, Py_NEW, Py_TYPE(self));
+}
+static char Vector_to_4d_doc[] =
+".. method:: to_4d()\n"
+"\n"
+" Return a 4d copy of the vector.\n"
+"\n"
+" :return: a new vector\n"
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_to_4d(VectorObject *self)
+{
+ float tvec[4]= {0.0f, 0.0f, 0.0f, 1.0f};
+
+ if(!BaseMath_ReadCallback(self))
+ return NULL;
+
+ memcpy(tvec, self->vec, sizeof(float) * MIN2(self->size, 4));
+ return newVectorObject(tvec, 4, Py_NEW, Py_TYPE(self));
+}
+
+static char Vector_to_tuple_doc[] =
".. method:: to_tuple(precision=-1)\n"
"\n"
" Return this vector as a tuple with.\n"
@@ -225,10 +286,10 @@ static char Vector_ToTuple_doc[] =
" :arg precision: The number to round the value to in [-1, 21].\n"
" :type precision: int\n"
" :return: the values of the vector rounded by *precision*\n"
-" :rtype: tuple\n";
-
+" :rtype: tuple\n"
+;
/* note: BaseMath_ReadCallback must be called beforehand */
-static PyObject *Vector_ToTupleExt(VectorObject *self, int ndigits)
+static PyObject *Vector_to_tuple_ext(VectorObject *self, int ndigits)
{
PyObject *ret;
int i;
@@ -249,7 +310,7 @@ static PyObject *Vector_ToTupleExt(VectorObject *self, int ndigits)
return ret;
}
-static PyObject *Vector_ToTuple(VectorObject *self, PyObject *args)
+static PyObject *Vector_to_tuple(VectorObject *self, PyObject *args)
{
int ndigits= 0;
@@ -267,11 +328,10 @@ static PyObject *Vector_ToTuple(VectorObject *self, PyObject *args)
if(!BaseMath_ReadCallback(self))
return NULL;
- return Vector_ToTupleExt(self, ndigits);
+ return Vector_to_tuple_ext(self, ndigits);
}
-/*----------------------------Vector.toTrackQuat(track, up) ---------------------- */
-static char Vector_ToTrackQuat_doc[] =
+static char Vector_to_track_quat_doc[] =
".. method:: to_track_quat(track, up)\n"
"\n"
" Return a quaternion rotation from the vector and the track and up axis.\n"
@@ -281,12 +341,12 @@ static char Vector_ToTrackQuat_doc[] =
" :arg up: Up axis in ['X', 'Y', 'Z'].\n"
" :type up: string\n"
" :return: rotation from the vector and the track and up axis.\n"
-" :rtype: :class:`Quaternion`\n";
-
-static PyObject *Vector_ToTrackQuat(VectorObject *self, PyObject *args )
+" :rtype: :class:`Quaternion`\n"
+;
+static PyObject *Vector_to_track_quat(VectorObject *self, PyObject *args )
{
float vec[3], quat[4];
- char *strack, *sup;
+ const char *strack, *sup;
short track = 2, up = 1;
if(!PyArg_ParseTuple( args, "|ss:to_track_quat", &strack, &sup))
@@ -385,11 +445,11 @@ static PyObject *Vector_ToTrackQuat(VectorObject *self, PyObject *args )
return newQuaternionObject(quat, Py_NEW, NULL);
}
-/*----------------------------Vector.reflect(mirror) ----------------------
- return a reflected vector on the mirror normal
- vec - ((2 * DotVecs(vec, mirror)) * mirror)
-*/
-static char Vector_Reflect_doc[] =
+/*
+ * Vector.reflect(mirror): return a reflected vector on the mirror normal
+ * vec - ((2 * DotVecs(vec, mirror)) * mirror)
+ */
+static char Vector_reflect_doc[] =
".. method:: reflect(mirror)\n"
"\n"
" Return the reflection vector from the *mirror* argument.\n"
@@ -397,38 +457,38 @@ static char Vector_Reflect_doc[] =
" :arg mirror: This vector could be a normal from the reflecting surface.\n"
" :type mirror: :class:`Vector`\n"
" :return: The reflected vector matching the size of this vector.\n"
-" :rtype: :class:`Vector`\n";
-
-static PyObject *Vector_Reflect(VectorObject *self, VectorObject *value )
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_reflect(VectorObject *self, PyObject *value)
{
+ int value_size;
float mirror[3], vec[3];
- float reflect[3] = {0.0f, 0.0f, 0.0f};
+ float reflect[3] = {0.0f};
+ float tvec[MAX_DIMENSIONS];
- if (!VectorObject_Check(value)) {
- PyErr_SetString(PyExc_TypeError, "vec.reflect(value): expected a vector argument");
+ if(!BaseMath_ReadCallback(self))
return NULL;
- }
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+ if((value_size= mathutils_array_parse(tvec, 2, 4, value, "vector.reflect(other), invalid 'other' arg")) == -1)
return NULL;
-
- mirror[0] = value->vec[0];
- mirror[1] = value->vec[1];
- if (value->size > 2) mirror[2] = value->vec[2];
+
+ mirror[0] = tvec[0];
+ mirror[1] = tvec[1];
+ if (value_size > 2) mirror[2] = tvec[2];
else mirror[2] = 0.0;
vec[0] = self->vec[0];
vec[1] = self->vec[1];
if (self->size > 2) vec[2] = self->vec[2];
else vec[2] = 0.0;
-
+
normalize_v3(mirror);
reflect_v3_v3v3(reflect, vec, mirror);
-
+
return newVectorObject(reflect, self->size, Py_NEW, Py_TYPE(self));
}
-static char Vector_Cross_doc[] =
+static char Vector_cross_doc[] =
".. method:: cross(other)\n"
"\n"
" Return the cross product of this vector and another.\n"
@@ -438,31 +498,25 @@ static char Vector_Cross_doc[] =
" :return: The cross product.\n"
" :rtype: :class:`Vector`\n"
"\n"
-" .. note:: both vectors must be 3D\n";
-
-static PyObject *Vector_Cross(VectorObject *self, VectorObject *value )
+" .. note:: both vectors must be 3D\n"
+;
+static PyObject *Vector_cross(VectorObject *self, PyObject *value)
{
- VectorObject *vecCross = NULL;
+ VectorObject *ret;
+ float tvec[MAX_DIMENSIONS];
- if (!VectorObject_Check(value)) {
- PyErr_SetString(PyExc_TypeError, "vec.cross(value): expected a vector argument");
- return NULL;
- }
-
- if(self->size != 3 || value->size != 3) {
- PyErr_SetString(PyExc_AttributeError, "vec.cross(value): expects both vectors to be 3D");
+ if(!BaseMath_ReadCallback(self))
return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+
+ if(mathutils_array_parse(tvec, self->size, self->size, value, "vector.cross(other), invalid 'other' arg") == -1)
return NULL;
-
- vecCross = (VectorObject *)newVectorObject(NULL, 3, Py_NEW, Py_TYPE(self));
- cross_v3_v3v3(vecCross->vec, self->vec, value->vec);
- return (PyObject *)vecCross;
+
+ ret= (VectorObject *)newVectorObject(NULL, 3, Py_NEW, Py_TYPE(self));
+ cross_v3_v3v3(ret->vec, self->vec, tvec);
+ return (PyObject *)ret;
}
-static char Vector_Dot_doc[] =
+static char Vector_dot_doc[] =
".. method:: dot(other)\n"
"\n"
" Return the dot product of this vector and another.\n"
@@ -470,29 +524,24 @@ static char Vector_Dot_doc[] =
" :arg other: The other vector to perform the dot product with.\n"
" :type other: :class:`Vector`\n"
" :return: The dot product.\n"
-" :rtype: :class:`Vector`\n";
-
-static PyObject *Vector_Dot(VectorObject *self, VectorObject *value )
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_dot(VectorObject *self, PyObject *value)
{
+ float tvec[MAX_DIMENSIONS];
double dot = 0.0;
int x;
-
- if (!VectorObject_Check(value)) {
- PyErr_SetString(PyExc_TypeError, "vec.dot(value): expected a vector argument");
- return NULL;
- }
-
- if(self->size != value->size) {
- PyErr_SetString(PyExc_AttributeError, "vec.dot(value): expects both vectors to have the same size");
+
+ if(!BaseMath_ReadCallback(self))
return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+
+ if(mathutils_array_parse(tvec, self->size, self->size, value, "vector.dot(other), invalid 'other' arg") == -1)
return NULL;
-
+
for(x = 0; x < self->size; x++) {
- dot += self->vec[x] * value->vec[x];
+ dot += self->vec[x] * tvec[x];
}
+
return PyFloat_FromDouble(dot);
}
@@ -508,36 +557,29 @@ static char Vector_angle_doc[] =
" :return: angle in radians or fallback when given\n"
" :rtype: float\n"
"\n"
-" .. note:: Zero length vectors raise an :exc:`AttributeError`.\n";
+" .. note:: Zero length vectors raise an :exc:`AttributeError`.\n"
+;
static PyObject *Vector_angle(VectorObject *self, PyObject *args)
{
- VectorObject *value;
- double dot = 0.0f, angleRads, test_v1 = 0.0f, test_v2 = 0.0f;
- int x, size;
+ const int size= self->size;
+ float tvec[MAX_DIMENSIONS];
+ PyObject *value;
+ double dot = 0.0f, test_v1 = 0.0f, test_v2 = 0.0f;
+ int x;
PyObject *fallback= NULL;
- if(!PyArg_ParseTuple(args, "O!|O:angle", &vector_Type, &value, &fallback))
+ if(!PyArg_ParseTuple(args, "O|O:angle", &value, &fallback))
return NULL;
- if (!VectorObject_Check(value)) {
- PyErr_SetString(PyExc_TypeError, "vec.angle(value): expected a vector argument");
- return NULL;
- }
-
- if(self->size != value->size) {
- PyErr_SetString(PyExc_AttributeError, "vec.angle(value): expects both vectors to have the same size");
- return NULL;
- }
-
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+ if(!BaseMath_ReadCallback(self))
return NULL;
- //since size is the same
- size = self->size;
+ if(mathutils_array_parse(tvec, size, size, value, "vector.angle(other), invalid 'other' arg") == -1)
+ return NULL;
for(x = 0; x < size; x++) {
test_v1 += self->vec[x] * self->vec[x];
- test_v2 += value->vec[x] * value->vec[x];
+ test_v2 += tvec[x] * tvec[x];
}
if (!test_v1 || !test_v2){
/* avoid exception */
@@ -552,17 +594,15 @@ static PyObject *Vector_angle(VectorObject *self, PyObject *args)
}
//dot product
- for(x = 0; x < size; x++) {
- dot += self->vec[x] * value->vec[x];
+ for(x = 0; x < self->size; x++) {
+ dot += self->vec[x] * tvec[x];
}
dot /= (sqrt(test_v1) * sqrt(test_v2));
- angleRads = (double)saacos(dot);
-
- return PyFloat_FromDouble(angleRads);
+ return PyFloat_FromDouble(saacos(dot));
}
-static char Vector_Difference_doc[] =
+static char Vector_difference_doc[] =
".. function:: difference(other)\n"
"\n"
" Returns a quaternion representing the rotational difference between this vector and another.\n"
@@ -572,34 +612,32 @@ static char Vector_Difference_doc[] =
" :return: the rotational difference between the two vectors.\n"
" :rtype: :class:`Quaternion`\n"
"\n"
-" .. note:: 2D vectors raise an :exc:`AttributeError`.\n";
-
-static PyObject *Vector_Difference(VectorObject *self, VectorObject *value )
+" .. note:: 2D vectors raise an :exc:`AttributeError`.\n"
+;
+static PyObject *Vector_difference(VectorObject *self, PyObject *value)
{
float quat[4], vec_a[3], vec_b[3];
- if (!VectorObject_Check(value)) {
- PyErr_SetString(PyExc_TypeError, "vec.difference(value): expected a vector argument");
+ if(self->size < 3) {
+ PyErr_SetString(PyExc_AttributeError, "vec.difference(value): expects both vectors to be size 3 or 4");
return NULL;
}
- if(self->size < 3 || value->size < 3) {
- PyErr_SetString(PyExc_AttributeError, "vec.difference(value): expects both vectors to be size 3 or 4");
+ if(!BaseMath_ReadCallback(self))
return NULL;
- }
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+ if(mathutils_array_parse(vec_b, 3, MAX_DIMENSIONS, value, "vector.difference(other), invalid 'other' arg") == -1)
return NULL;
normalize_v3_v3(vec_a, self->vec);
- normalize_v3_v3(vec_b, value->vec);
+ normalize_v3(vec_b);
rotation_between_vecs_to_quat(quat, vec_a, vec_b);
return newQuaternionObject(quat, Py_NEW, NULL);
}
-static char Vector_Project_doc[] =
+static char Vector_project_doc[] =
".. function:: project(other)\n"
"\n"
" Return the projection of this vector onto the *other*.\n"
@@ -607,45 +645,39 @@ static char Vector_Project_doc[] =
" :arg other: second vector.\n"
" :type other: :class:`Vector`\n"
" :return: the parallel projection vector\n"
-" :rtype: :class:`Vector`\n";
-
-static PyObject *Vector_Project(VectorObject *self, VectorObject *value)
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_project(VectorObject *self, PyObject *value)
{
- float vec[4];
+ const int size= self->size;
+ float tvec[MAX_DIMENSIONS];
+ float vec[MAX_DIMENSIONS];
double dot = 0.0f, dot2 = 0.0f;
- int x, size;
+ int x;
- if (!VectorObject_Check(value)) {
- PyErr_SetString(PyExc_TypeError, "vec.project(value): expected a vector argument");
+ if(!BaseMath_ReadCallback(self))
return NULL;
- }
- if(self->size != value->size) {
- PyErr_SetString(PyExc_AttributeError, "vec.project(value): expects both vectors to have the same size");
+ if(mathutils_array_parse(tvec, size, size, value, "vector.project(other), invalid 'other' arg") == -1)
return NULL;
- }
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(value))
+ if(!BaseMath_ReadCallback(self))
return NULL;
-
- //since they are the same size
- size = self->size;
-
//get dot products
for(x = 0; x < size; x++) {
- dot += self->vec[x] * value->vec[x];
- dot2 += value->vec[x] * value->vec[x];
+ dot += self->vec[x] * tvec[x];
+ dot2 += tvec[x] * tvec[x];
}
//projection
dot /= dot2;
for(x = 0; x < size; x++) {
- vec[x] = (float)(dot * value->vec[x]);
+ vec[x] = (float)(dot * tvec[x]);
}
return newVectorObject(vec, size, Py_NEW, Py_TYPE(self));
}
-static char Vector_Lerp_doc[] =
+static char Vector_lerp_doc[] =
".. function:: lerp(other, factor)\n"
"\n"
" Returns the interpolation of two vectors.\n"
@@ -655,73 +687,62 @@ static char Vector_Lerp_doc[] =
" :arg factor: The interpolation value in [0.0, 1.0].\n"
" :type factor: float\n"
" :return: The interpolated rotation.\n"
-" :rtype: :class:`Vector`\n";
-
-static PyObject *Vector_Lerp(VectorObject *self, PyObject *args)
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_lerp(VectorObject *self, PyObject *args)
{
- VectorObject *vec2 = NULL;
- float fac, ifac, vec[4];
+ const int size= self->size;
+ PyObject *value= NULL;
+ float fac, ifac;
+ float tvec[MAX_DIMENSIONS], vec[MAX_DIMENSIONS];
int x;
- if(!PyArg_ParseTuple(args, "O!f:lerp", &vector_Type, &vec2, &fac))
+ if(!PyArg_ParseTuple(args, "Of:lerp", &value, &fac))
return NULL;
- if(self->size != vec2->size) {
- PyErr_SetString(PyExc_AttributeError, "vector.lerp(): expects both vector objects to have the same size");
+ if(mathutils_array_parse(tvec, size, size, value, "vector.lerp(other), invalid 'other' arg") == -1)
return NULL;
- }
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(vec2))
+ if(!BaseMath_ReadCallback(self))
return NULL;
ifac= 1.0 - fac;
- for(x = 0; x < self->size; x++) {
- vec[x] = (ifac * self->vec[x]) + (fac * vec2->vec[x]);
+ for(x = 0; x < size; x++) {
+ vec[x] = (ifac * self->vec[x]) + (fac * tvec[x]);
}
- return newVectorObject(vec, self->size, Py_NEW, Py_TYPE(self));
+ return newVectorObject(vec, size, Py_NEW, Py_TYPE(self));
}
-/*---------------------------- Vector.rotate(angle, axis) ----------------------*/
-static char Vector_Rotate_doc[] =
-".. function:: rotate(axis, angle)\n"
+static char Vector_rotate_doc[] =
+".. function:: rotate(other)\n"
"\n"
-" Return vector rotated around axis by angle.\n"
+" Return vector by a rotation value.\n"
"\n"
-" :arg axis: rotation axis.\n"
-" :type axis: :class:`Vector`\n"
-" :arg angle: angle in radians.\n"
-" :type angle: float\n"
-" :return: an instance of itself\n"
-" :rtype: :class:`Vector`\n";
-
-static PyObject *Vector_Rotate(VectorObject *self, PyObject *args)
+" :arg other: rotation component of mathutils value\n"
+" :type other: :class:`Euler`, :class:`Quaternion` or :class:`Matrix`\n"
+;
+static PyObject *Vector_rotate(VectorObject *self, PyObject *value)
{
- VectorObject *axis_vec = NULL;
- float angle, vec[3];
+ float other_rmat[3][3];
- if(!PyArg_ParseTuple(args, "O!f", &vector_Type, &axis_vec, &angle)){
- PyErr_SetString(PyExc_TypeError, "vec.rotate(axis, angle): expected 3D axis (Vector) and angle (float)");
+ if(!BaseMath_ReadCallback(self))
return NULL;
- }
- if(self->size != 3 || axis_vec->size != 3) {
- PyErr_SetString(PyExc_AttributeError, "vec.rotate(axis, angle): expects both vectors to be 3D");
+ if(mathutils_any_to_rotmat(other_rmat, value, "vector.rotate(value)") == -1)
return NULL;
- }
- if(!BaseMath_ReadCallback(self) || !BaseMath_ReadCallback(axis_vec))
+ if(self->size < 3) {
+ PyErr_SetString(PyExc_ValueError, "Vector must be 3D or 4D");
return NULL;
+ }
- rotate_v3_v3v3fl(vec, self->vec, axis_vec->vec, angle);
-
- copy_v3_v3(self->vec, vec);
+ mul_m3_v3(other_rmat, self->vec);
- Py_INCREF(self);
- return (PyObject *)self;
+ (void)BaseMath_WriteCallback(self);
+ Py_RETURN_NONE;
}
-/*----------------------------Vector.copy() -------------------------------------- */
static char Vector_copy_doc[] =
".. function:: copy()\n"
"\n"
@@ -730,8 +751,8 @@ static char Vector_copy_doc[] =
" :return: A copy of the vector.\n"
" :rtype: :class:`Vector`\n"
"\n"
-" .. note:: use this to get a copy of a wrapped vector with no reference to the original data.\n";
-
+" .. note:: use this to get a copy of a wrapped vector with no reference to the original data.\n"
+;
static PyObject *Vector_copy(VectorObject *self)
{
if(!BaseMath_ReadCallback(self))
@@ -740,8 +761,6 @@ static PyObject *Vector_copy(VectorObject *self)
return newVectorObject(self->vec, self->size, Py_NEW, Py_TYPE(self));
}
-/*----------------------------print object (internal)-------------
- print the object to screen */
static PyObject *Vector_repr(VectorObject *self)
{
PyObject *ret, *tuple;
@@ -749,21 +768,19 @@ static PyObject *Vector_repr(VectorObject *self)
if(!BaseMath_ReadCallback(self))
return NULL;
- tuple= Vector_ToTupleExt(self, -1);
+ tuple= Vector_to_tuple_ext(self, -1);
ret= PyUnicode_FromFormat("Vector(%R)", tuple);
Py_DECREF(tuple);
return ret;
}
-/*---------------------SEQUENCE PROTOCOLS------------------------
- ----------------------------len(object)------------------------
- sequence length*/
+/* Sequence Protocol */
+/* sequence length len(vector) */
static int Vector_len(VectorObject *self)
{
return self->size;
}
-/*----------------------------object[]---------------------------
- sequence accessor (get)*/
+/* sequence accessor (get): vector[index] */
static PyObject *Vector_item(VectorObject *self, int i)
{
if(i<0) i= self->size-i;
@@ -778,8 +795,7 @@ static PyObject *Vector_item(VectorObject *self, int i)
return PyFloat_FromDouble(self->vec[i]);
}
-/*----------------------------object[]-------------------------
- sequence accessor (set)*/
+/* sequence accessor (set): vector[index] = value */
static int Vector_ass_item(VectorObject *self, int i, PyObject * ob)
{
float scalar;
@@ -801,8 +817,7 @@ static int Vector_ass_item(VectorObject *self, int i, PyObject * ob)
return 0;
}
-/*----------------------------object[z:y]------------------------
- sequence slice (get) */
+/* sequence slice (get): vector[a:b] */
static PyObject *Vector_slice(VectorObject *self, int begin, int end)
{
PyObject *tuple;
@@ -823,8 +838,7 @@ static PyObject *Vector_slice(VectorObject *self, int begin, int end)
return tuple;
}
-/*----------------------------object[z:y]------------------------
- sequence slice (set) */
+/* sequence slice (set): vector[a:b] = value */
static int Vector_ass_slice(VectorObject *self, int begin, int end,
PyObject * seq)
{
@@ -839,7 +853,7 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end,
begin = MIN2(begin,end);
size = (end - begin);
- if(mathutils_array_parse(vec, size, size, seq, "vector[begin:end] = [...]:") == -1)
+ if(mathutils_array_parse(vec, size, size, seq, "vector[begin:end] = [...]") == -1)
return -1;
/*parsed well - now set in vector*/
@@ -852,9 +866,9 @@ static int Vector_ass_slice(VectorObject *self, int begin, int end,
return 0;
}
-/*------------------------NUMERIC PROTOCOLS----------------------
- ------------------------obj + obj------------------------------
- addition*/
+
+/* Numeric Protocols */
+/* addition: obj + obj */
static PyObject *Vector_add(PyObject * v1, PyObject * v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -881,8 +895,7 @@ static PyObject *Vector_add(PyObject * v1, PyObject * v2)
return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
}
-/* ------------------------obj += obj------------------------------
- addition in place */
+/* addition in-place: obj += obj */
static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -909,8 +922,7 @@ static PyObject *Vector_iadd(PyObject * v1, PyObject * v2)
return v1;
}
-/*------------------------obj - obj------------------------------
- subtraction*/
+/* subtraction: obj - obj */
static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
{
VectorObject *vec1 = NULL, *vec2 = NULL;
@@ -936,8 +948,7 @@ static PyObject *Vector_sub(PyObject * v1, PyObject * v2)
return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
}
-/*------------------------obj -= obj------------------------------
- subtraction*/
+/* subtraction in-place: obj -= obj */
static PyObject *Vector_isub(PyObject * v1, PyObject * v2)
{
VectorObject *vec1= NULL, *vec2= NULL;
@@ -1092,8 +1103,7 @@ static PyObject *Vector_mul(PyObject * v1, PyObject * v2)
return NULL;
}
-/*------------------------obj *= obj------------------------------
- in place mulplication */
+/* mulplication in-place: obj *= obj */
static PyObject *Vector_imul(PyObject * v1, PyObject * v2)
{
VectorObject *vec = (VectorObject *)v1;
@@ -1141,8 +1151,7 @@ static PyObject *Vector_imul(PyObject * v1, PyObject * v2)
return v1;
}
-/*------------------------obj / obj------------------------------
- divide*/
+/* divid: obj / obj */
static PyObject *Vector_div(PyObject * v1, PyObject * v2)
{
int i;
@@ -1174,8 +1183,7 @@ static PyObject *Vector_div(PyObject * v1, PyObject * v2)
return newVectorObject(vec, vec1->size, Py_NEW, Py_TYPE(v1));
}
-/*------------------------obj /= obj------------------------------
- divide*/
+/* divide in-place: obj /= obj */
static PyObject *Vector_idiv(PyObject * v1, PyObject * v2)
{
int i;
@@ -1204,21 +1212,17 @@ static PyObject *Vector_idiv(PyObject * v1, PyObject * v2)
return v1;
}
-/*-------------------------- -obj -------------------------------
+/* -obj
returns the negative of this object*/
static PyObject *Vector_neg(VectorObject *self)
{
- int i;
- float vec[4];
+ float tvec[MAX_DIMENSIONS];
if(!BaseMath_ReadCallback(self))
return NULL;
- for(i = 0; i < self->size; i++){
- vec[i] = -self->vec[i];
- }
-
- return newVectorObject(vec, self->size, Py_NEW, Py_TYPE(self));
+ negate_vn_vn(tvec, self->vec, self->size);
+ return newVectorObject(tvec, self->size, Py_NEW, Py_TYPE(self));
}
/*------------------------vec_magnitude_nosqrt (internal) - for comparing only */
@@ -1234,7 +1238,7 @@ static double vec_magnitude_nosqrt(float *data, int size)
/* warning, line above removed because we are not using the length,
rather the comparing the sizes and for this we do not need the sqrt
for the actual length, the dot must be sqrt'd */
- return (double)dot;
+ return dot;
}
@@ -1349,7 +1353,7 @@ static PyObject *Vector_subscript(VectorObject* self, PyObject* item)
return NULL;
if (slicelength <= 0) {
- return PyList_New(0);
+ return PyTuple_New(0);
}
else if (step == 1) {
return Vector_slice(self, start, stop);
@@ -1444,12 +1448,12 @@ static PyNumberMethods Vector_NumMethods = {
* vector axis, vector.x/y/z/w
*/
-static PyObject *Vector_getAxis(VectorObject *self, void *type )
+static PyObject *Vector_getAxis(VectorObject *self, void *type)
{
return Vector_item(self, GET_INT_FROM_POINTER(type));
}
-static int Vector_setAxis(VectorObject *self, PyObject * value, void * type )
+static int Vector_setAxis(VectorObject *self, PyObject * value, void *type)
{
return Vector_ass_item(self, GET_INT_FROM_POINTER(type), value);
}
@@ -2058,46 +2062,53 @@ static int row_vector_multiplication(float rvec[4], VectorObject* vec, MatrixObj
#endif
/*----------------------------Vector.negate() -------------------- */
-static char Vector_Negate_doc[] =
+static char Vector_negate_doc[] =
".. method:: negate()\n"
"\n"
" Set all values to their negative.\n"
"\n"
" :return: an instance of itself\n"
-" :rtype: :class:`Vector`\n";
-
-static PyObject *Vector_Negate(VectorObject *self)
+" :rtype: :class:`Vector`\n"
+;
+static PyObject *Vector_negate(VectorObject *self)
{
- int i;
if(!BaseMath_ReadCallback(self))
return NULL;
- for(i = 0; i < self->size; i++)
- self->vec[i] = -(self->vec[i]);
-
+ negate_vn(self->vec, self->size);
+
(void)BaseMath_WriteCallback(self); // already checked for error
-
- Py_INCREF(self);
- return (PyObject*)self;
+ Py_RETURN_NONE;
}
static struct PyMethodDef Vector_methods[] = {
- {"zero", (PyCFunction) Vector_Zero, METH_NOARGS, Vector_Zero_doc},
- {"normalize", (PyCFunction) Vector_Normalize, METH_NOARGS, Vector_Normalize_doc},
- {"negate", (PyCFunction) Vector_Negate, METH_NOARGS, Vector_Negate_doc},
- {"resize2D", (PyCFunction) Vector_Resize2D, METH_NOARGS, Vector_Resize2D_doc},
- {"resize3D", (PyCFunction) Vector_Resize3D, METH_NOARGS, Vector_Resize3D_doc},
- {"resize4D", (PyCFunction) Vector_Resize4D, METH_NOARGS, Vector_Resize4D_doc},
- {"to_tuple", (PyCFunction) Vector_ToTuple, METH_VARARGS, Vector_ToTuple_doc},
- {"to_track_quat", ( PyCFunction ) Vector_ToTrackQuat, METH_VARARGS, Vector_ToTrackQuat_doc},
- {"reflect", ( PyCFunction ) Vector_Reflect, METH_O, Vector_Reflect_doc},
- {"cross", ( PyCFunction ) Vector_Cross, METH_O, Vector_Cross_doc},
- {"dot", ( PyCFunction ) Vector_Dot, METH_O, Vector_Dot_doc},
- {"angle", ( PyCFunction ) Vector_angle, METH_VARARGS, Vector_angle_doc},
- {"difference", ( PyCFunction ) Vector_Difference, METH_O, Vector_Difference_doc},
- {"project", ( PyCFunction ) Vector_Project, METH_O, Vector_Project_doc},
- {"lerp", ( PyCFunction ) Vector_Lerp, METH_VARARGS, Vector_Lerp_doc},
- {"rotate", ( PyCFunction ) Vector_Rotate, METH_VARARGS, Vector_Rotate_doc},
+ /* in place only */
+ {"zero", (PyCFunction) Vector_zero, METH_NOARGS, Vector_zero_doc},
+ {"negate", (PyCFunction) Vector_negate, METH_NOARGS, Vector_negate_doc},
+
+ /* operate on original or copy */
+ {"normalize", (PyCFunction) Vector_normalize, METH_NOARGS, Vector_normalize_doc},
+ {"normalized", (PyCFunction) Vector_normalized, METH_NOARGS, Vector_normalized_doc},
+
+ {"to_2d", (PyCFunction) Vector_to_2d, METH_NOARGS, Vector_to_2d_doc},
+ {"resize_2d", (PyCFunction) Vector_resize_2d, METH_NOARGS, Vector_resize_2d_doc},
+ {"to_3d", (PyCFunction) Vector_to_3d, METH_NOARGS, Vector_to_3d_doc},
+ {"resize_3d", (PyCFunction) Vector_resize_3d, METH_NOARGS, Vector_resize_3d_doc},
+ {"to_4d", (PyCFunction) Vector_to_4d, METH_NOARGS, Vector_to_4d_doc},
+ {"resize_4d", (PyCFunction) Vector_resize_4d, METH_NOARGS, Vector_resize_4d_doc},
+ {"to_tuple", (PyCFunction) Vector_to_tuple, METH_VARARGS, Vector_to_tuple_doc},
+ {"to_track_quat", (PyCFunction) Vector_to_track_quat, METH_VARARGS, Vector_to_track_quat_doc},
+
+ /* operation between 2 or more types */
+ {"reflect", (PyCFunction) Vector_reflect, METH_O, Vector_reflect_doc},
+ {"cross", (PyCFunction) Vector_cross, METH_O, Vector_cross_doc},
+ {"dot", (PyCFunction) Vector_dot, METH_O, Vector_dot_doc},
+ {"angle", (PyCFunction) Vector_angle, METH_VARARGS, Vector_angle_doc},
+ {"difference", (PyCFunction) Vector_difference, METH_O, Vector_difference_doc},
+ {"project", (PyCFunction) Vector_project, METH_O, Vector_project_doc},
+ {"lerp", (PyCFunction) Vector_lerp, METH_VARARGS, Vector_lerp_doc},
+ {"rotate", (PyCFunction) Vector_rotate, METH_O, Vector_rotate_doc},
+
{"copy", (PyCFunction) Vector_copy, METH_NOARGS, Vector_copy_doc},
{"__copy__", (PyCFunction) Vector_copy, METH_NOARGS, NULL},
{NULL, NULL, 0, NULL}
@@ -2111,8 +2122,8 @@ static struct PyMethodDef Vector_methods[] = {
*/
static char vector_doc[] =
-"This object gives access to Vectors in Blender.";
-
+"This object gives access to Vectors in Blender."
+;
PyTypeObject vector_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
/* For printing, in format "<module>.<name>" */
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 3fc1ec140c6..9f7a9f2cabe 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -228,6 +228,10 @@ const char *PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce)
* chars since blender doesnt limit this */
return result;
}
+ else if(PyBytes_Check(py_str)) {
+ PyErr_Clear();
+ return PyBytes_AS_STRING(py_str);
+ }
else {
/* mostly copied from fileio.c's, fileio_init */
PyObject *stringobj;
@@ -278,6 +282,10 @@ PyObject *PyC_UnicodeFromByte(const char *str)
for 'pickle' to work as well as strings like this...
>> foo = 10
>> print(__import__("__main__").foo)
+*
+* note: this overwrites __main__ which gives problems with nested calles.
+* be sure to run PyC_MainModule_Backup & PyC_MainModule_Restore if there is
+* any chance that python is in the call stack.
*****************************************************************************/
PyObject *PyC_DefaultNameSpace(const char *filename)
{
@@ -293,6 +301,20 @@ PyObject *PyC_DefaultNameSpace(const char *filename)
return PyModule_GetDict(mod_main);
}
+/* restore MUST be called after this */
+void PyC_MainModule_Backup(PyObject **main_mod)
+{
+ PyInterpreterState *interp= PyThreadState_GET()->interp;
+ *main_mod= PyDict_GetItemString(interp->modules, "__main__");
+ Py_XINCREF(*main_mod); /* dont free */
+}
+
+void PyC_MainModule_Restore(PyObject *main_mod)
+{
+ PyInterpreterState *interp= PyThreadState_GET()->interp;
+ PyDict_SetItemString(interp->modules, "__main__", main_mod);
+ Py_XDECREF(main_mod);
+}
/* Would be nice if python had this built in */
void PyC_RunQuicky(const char *filepath, int n, ...)
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index f786fd80269..ccdbde5cecb 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -39,4 +39,7 @@ const char * PyC_UnicodeAsByte(PyObject *py_str, PyObject **coerce); /* coerce m
/* name namespace function for bpy & bge */
PyObject * PyC_DefaultNameSpace(const char *filename);
void PyC_RunQuicky(const char *filepath, int n, ...);
+
+void PyC_MainModule_Backup(PyObject **main_mod);
+void PyC_MainModule_Restore(PyObject *main_mod);
#endif // PY_CAPI_UTILS_H
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 38efb4523c4..776f2da8507 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -313,8 +313,22 @@ void BPY_python_end(void)
}
+/* super annoying, undo _PyModule_Clear(), bug [#23871] */
+#define PYMODULE_CLEAR_WORKAROUND
+
+#ifdef PYMODULE_CLEAR_WORKAROUND
+/* bad!, we should never do this, but currently only safe way I could find to keep namespace.
+ * from being cleared. - campbell */
+typedef struct {
+ PyObject_HEAD
+ PyObject *md_dict;
+ /* ommit other values, we only want the dict. */
+} PyModuleObject;
+#endif
+
static int python_script_exec(bContext *C, const char *fn, struct Text *text, struct ReportList *reports)
{
+ PyObject *main_mod= NULL;
PyObject *py_dict= NULL, *py_result= NULL;
PyGILState_STATE gilstate;
@@ -326,6 +340,8 @@ static int python_script_exec(bContext *C, const char *fn, struct Text *text, st
bpy_context_set(C, &gilstate);
+ PyC_MainModule_Backup(&main_mod);
+
if (text) {
char fn_dummy[FILE_MAXDIR];
bpy_text_filename_get(fn_dummy, text);
@@ -389,25 +405,21 @@ static int python_script_exec(bContext *C, const char *fn, struct Text *text, st
Py_DECREF( py_result );
}
-/* super annoying, undo _PyModule_Clear() */
-#define PYMODULE_CLEAR_WORKAROUND
-
if(py_dict) {
#ifdef PYMODULE_CLEAR_WORKAROUND
- PyObject *py_dict_back= PyDict_Copy(py_dict);
- Py_INCREF(py_dict);
-#endif
- /* normal */
- PyDict_SetItemString(PyThreadState_GET()->interp->modules, "__main__", Py_None);
-#ifdef PYMODULE_CLEAR_WORKAROUND
- PyDict_Clear(py_dict);
- PyDict_Update(py_dict, py_dict_back);
- Py_DECREF(py_dict);
- Py_DECREF(py_dict_back);
+ PyModuleObject *mmod= (PyModuleObject *)PyDict_GetItemString(PyThreadState_GET()->interp->modules, "__main__");
+ PyObject *dict_back = mmod->md_dict;
+ /* freeing the module will clear the namespace,
+ * gives problems running classes defined in this namespace being used later. */
+ mmod->md_dict= NULL;
+ Py_DECREF(dict_back);
#endif
+
#undef PYMODULE_CLEAR_WORKAROUND
}
+ PyC_MainModule_Restore(main_mod);
+
bpy_context_clear(C, &gilstate);
return (py_result != NULL);
@@ -437,6 +449,7 @@ int BPY_button_exec(bContext *C, const char *expr, double *value)
PyGILState_STATE gilstate;
PyObject *py_dict, *mod, *retval;
int error_ret = 0;
+ PyObject *main_mod= NULL;
if (!value || !expr) return -1;
@@ -446,7 +459,9 @@ int BPY_button_exec(bContext *C, const char *expr, double *value)
}
bpy_context_set(C, &gilstate);
-
+
+ PyC_MainModule_Backup(&main_mod);
+
py_dict= PyC_DefaultNameSpace("<blender button>");
mod = PyImport_ImportModule("math");
@@ -497,7 +512,7 @@ int BPY_button_exec(bContext *C, const char *expr, double *value)
BPy_errors_to_report(CTX_wm_reports(C));
}
- PyDict_SetItemString(PyThreadState_GET()->interp->modules, "__main__", Py_None);
+ PyC_MainModule_Backup(&main_mod);
bpy_context_clear(C, &gilstate);
@@ -507,6 +522,7 @@ int BPY_button_exec(bContext *C, const char *expr, double *value)
int BPY_string_exec(bContext *C, const char *expr)
{
PyGILState_STATE gilstate;
+ PyObject *main_mod= NULL;
PyObject *py_dict, *retval;
int error_ret = 0;
@@ -518,6 +534,8 @@ int BPY_string_exec(bContext *C, const char *expr)
bpy_context_set(C, &gilstate);
+ PyC_MainModule_Backup(&main_mod);
+
py_dict= PyC_DefaultNameSpace("<blender string>");
retval = PyRun_String(expr, Py_eval_input, py_dict, py_dict);
@@ -531,8 +549,8 @@ int BPY_string_exec(bContext *C, const char *expr)
Py_DECREF(retval);
}
- PyDict_SetItemString(PyThreadState_GET()->interp->modules, "__main__", Py_None);
-
+ PyC_MainModule_Restore(main_mod);
+
bpy_context_clear(C, &gilstate);
return error_ret;
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index d5446b11349..70aa46c1302 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -138,6 +138,11 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
return NULL;
}
+ if(!pyrna_write_check()) {
+ PyErr_Format(PyExc_SystemError, "Calling operator \"bpy.ops.%s\" error, can't modify blend data in this state (drawing/rendering)", opname);
+ return NULL;
+ }
+
if(context_str) {
if(RNA_enum_value_from_id(operator_context_items, context_str, &context)==0) {
char *enum_str= BPy_enum_as_string(operator_context_items);
@@ -226,6 +231,12 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
return NULL;
}
+ /* when calling bpy.ops.wm.read_factory_settings() bpy.data's main pointer is freed by clear_globals(),
+ * further access will crash blender. setting context is not needed in this case, only calling because this
+ * function corrects bpy.data (internal Main pointer) */
+ BPY_modules_update(C);
+
+
/* return operator_ret as a bpy enum */
return pyrna_enum_bitfield_to_py(operator_return_items, operator_ret);
diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c
index b8a448106f9..bbffbbf3b9e 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -83,7 +83,19 @@ static int rna_id_write_error(PointerRNA *ptr, PyObject *key)
}
return FALSE;
}
+#endif // USE_PEDANTIC_WRITE
+
+#ifdef USE_PEDANTIC_WRITE
+int pyrna_write_check(void)
+{
+ return !rna_disallow_writes;
+}
+#else // USE_PEDANTIC_WRITE
+int pyrna_write_check(void)
+{
+ return TRUE;
+}
#endif // USE_PEDANTIC_WRITE
static Py_ssize_t pyrna_prop_collection_length(BPy_PropertyRNA *self);
@@ -423,9 +435,9 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
int pyrna_enum_value_from_id(EnumPropertyItem *item, const char *identifier, int *value, const char *error_prefix)
{
if(RNA_enum_value_from_id(item, identifier, value) == 0) {
- char *enum_str= BPy_enum_as_string(item);
+ const char *enum_str= BPy_enum_as_string(item);
PyErr_Format(PyExc_TypeError, "%s: '%.200s' not found in (%s)", error_prefix, identifier, enum_str);
- MEM_freeN(enum_str);
+ MEM_freeN((void *)enum_str);
return -1;
}
@@ -504,13 +516,13 @@ static PyObject *pyrna_prop_richcmp(PyObject *a, PyObject *b, int op)
static PyObject *pyrna_struct_str( BPy_StructRNA *self )
{
PyObject *ret;
- char *name;
+ const char *name;
/* print name if available */
name= RNA_struct_name_get_alloc(&self->ptr, NULL, FALSE);
if(name) {
ret= PyUnicode_FromFormat( "<bpy_struct, %.200s(\"%.200s\")>", RNA_struct_identifier(self->ptr.type), name);
- MEM_freeN(name);
+ MEM_freeN((void *)name);
return ret;
}
@@ -528,11 +540,11 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self)
}
else {
PyObject *ret;
- char *path;
+ const char *path;
path= RNA_path_from_ID_to_struct(&self->ptr);
if(path) {
ret= PyUnicode_FromFormat( "bpy.data.%s[\"%s\"].%s", BKE_idcode_to_name_plural(GS(id->name)), id->name+2, path);
- MEM_freeN(path);
+ MEM_freeN((void *)path);
}
else { /* cant find, print something sane */
ret= PyUnicode_FromFormat( "bpy.data.%s[\"%s\"]...%s", BKE_idcode_to_name_plural(GS(id->name)), id->name+2, RNA_struct_identifier(self->ptr.type));
@@ -546,7 +558,7 @@ static PyObject *pyrna_prop_str( BPy_PropertyRNA *self )
{
PyObject *ret;
PointerRNA ptr;
- char *name;
+ const char *name;
const char *type_id= NULL;
char type_fmt[64]= "";
int type= RNA_property_type(self->prop);
@@ -579,7 +591,7 @@ static PyObject *pyrna_prop_str( BPy_PropertyRNA *self )
if(name) {
ret= PyUnicode_FromFormat( "<bpy_%.200s, %.200s.%.200s(\"%.200s\")>", type_fmt, RNA_struct_identifier(self->ptr.type), RNA_property_identifier(self->prop), name);
- MEM_freeN(name);
+ MEM_freeN((void *)name);
return ret;
}
}
@@ -591,7 +603,7 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
{
ID *id= self->ptr.id.data;
PyObject *ret;
- char *path;
+ const char *path;
if(id == NULL)
return pyrna_prop_str(self); /* fallback */
@@ -599,7 +611,7 @@ static PyObject *pyrna_prop_repr(BPy_PropertyRNA *self)
path= RNA_path_from_ID_to_property(&self->ptr, self->prop);
if(path) {
ret= PyUnicode_FromFormat( "bpy.data.%s[\"%s\"].%s", BKE_idcode_to_name_plural(GS(id->name)), id->name+2, path);
- MEM_freeN(path);
+ MEM_freeN((void *)path);
}
else { /* cant find, print something sane */
ret= PyUnicode_FromFormat( "bpy.data.%s[\"%s\"]...%s", BKE_idcode_to_name_plural(GS(id->name)), id->name+2, RNA_property_identifier(self->prop));
@@ -670,7 +682,7 @@ static const char *pyrna_enum_as_string(PointerRNA *ptr, PropertyRNA *prop)
static int pyrna_string_to_enum(PyObject *item, PointerRNA *ptr, PropertyRNA *prop, int *val, const char *error_prefix)
{
- char *param= _PyUnicode_AsString(item);
+ const char *param= _PyUnicode_AsString(item);
if (param==NULL) {
const char *enum_str= pyrna_enum_as_string(ptr, prop);
@@ -702,7 +714,7 @@ int pyrna_set_to_enum_bitfield(EnumPropertyItem *items, PyObject *value, int *r_
*r_value= 0;
while (_PySet_NextEntry(value, &pos, &key, &hash)) {
- char *param= _PyUnicode_AsString(key);
+ const char *param= _PyUnicode_AsString(key);
if(param==NULL) {
PyErr_Format(PyExc_TypeError, "%.200s expected a string. found a %.200s", error_prefix, Py_TYPE(key)->tp_name);
@@ -800,7 +812,7 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
ret= PyUnicode_FromString(item->identifier);
}
else {
- char *ptr_name= RNA_struct_name_get_alloc(ptr, NULL, FALSE);
+ const char *ptr_name= RNA_struct_name_get_alloc(ptr, NULL, FALSE);
/* prefer not fail silently incase of api errors, maybe disable it later */
printf("RNA Warning: Current value \"%d\" matches no enum in '%s', '%s', '%s'\n", val, RNA_struct_identifier(ptr->type), ptr_name, RNA_property_identifier(prop));
@@ -812,9 +824,9 @@ static PyObject *pyrna_enum_to_py(PointerRNA *ptr, PropertyRNA *prop, int val)
#endif
if(ptr_name)
- MEM_freeN(ptr_name);
+ MEM_freeN((void *)ptr_name);
- ret = PyUnicode_FromString( "" );
+ ret = PyUnicode_FromString("");
}
if(free)
@@ -851,7 +863,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
case PROP_STRING:
{
int subtype= RNA_property_subtype(prop);
- char *buf;
+ const char *buf;
buf = RNA_property_string_get_alloc(ptr, prop, NULL, -1);
#ifdef USE_STRING_COERCE
/* only file paths get special treatment, they may contain non utf-8 chars */
@@ -864,7 +876,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
#else // USE_STRING_COERCE
ret= PyUnicode_FromString(buf);
#endif // USE_STRING_COERCE
- MEM_freeN(buf);
+ MEM_freeN((void *)buf);
break;
}
case PROP_ENUM:
@@ -1277,7 +1289,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
if(pyrna_pydict_to_props(&itemptr, item, 1, "Converting a python list to an RNA collection")==-1) {
PyObject *msg= PyC_ExceptionBuffer();
- char *msg_char= _PyUnicode_AsString(msg);
+ const char *msg_char= _PyUnicode_AsString(msg);
PyErr_Format(PyExc_TypeError, "%.200s %.200s.%.200s error converting a member of a collection from a dicts into an RNA collection, failed with: %s", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), msg_char);
@@ -1899,7 +1911,7 @@ static int pyrna_prop_collection_contains(BPy_PropertyRNA *self, PyObject *value
PointerRNA newptr; /* not used, just so RNA_property_collection_lookup_string runs */
/* key in dict style check */
- char *keyname = _PyUnicode_AsString(value);
+ const char *keyname = _PyUnicode_AsString(value);
if(keyname==NULL) {
PyErr_SetString(PyExc_TypeError, "bpy_prop_collection.__contains__: expected a string");
@@ -1915,7 +1927,7 @@ static int pyrna_prop_collection_contains(BPy_PropertyRNA *self, PyObject *value
static int pyrna_struct_contains(BPy_StructRNA *self, PyObject *value)
{
IDProperty *group;
- char *name = _PyUnicode_AsString(value);
+ const char *name = _PyUnicode_AsString(value);
if (!name) {
PyErr_SetString(PyExc_TypeError, "bpy_struct.__contains__: expected a string");
@@ -1978,7 +1990,7 @@ static PyObject *pyrna_struct_subscript( BPy_StructRNA *self, PyObject *key )
{
/* mostly copied from BPy_IDGroup_Map_GetItem */
IDProperty *group, *idprop;
- char *name= _PyUnicode_AsString(key);
+ const char *name= _PyUnicode_AsString(key);
if(RNA_struct_idprops_check(self->ptr.type)==0) {
PyErr_SetString(PyExc_TypeError, "this type doesn't support IDProperties");
@@ -2114,7 +2126,7 @@ static PyObject *pyrna_struct_values(BPy_PropertyRNA *self)
/* for keyframes and drivers */
static int pyrna_struct_anim_args_parse(PointerRNA *ptr, const char *error_prefix, const char *path,
- char **path_full, int *index)
+ const char **path_full, int *index)
{
const int is_idbase= RNA_struct_is_ID(ptr->type);
PropertyRNA *prop;
@@ -2189,10 +2201,10 @@ static int pyrna_struct_anim_args_parse(PointerRNA *ptr, const char *error_prefi
/* internal use for insert and delete */
static int pyrna_struct_keyframe_parse(PointerRNA *ptr, PyObject *args, PyObject *kw, const char *parse_str, const char *error_prefix,
- char **path_full, int *index, float *cfra, char **group_name) /* return values */
+ const char **path_full, int *index, float *cfra, const char **group_name) /* return values */
{
static const char *kwlist[] = {"data_path", "index", "frame", "group", NULL};
- char *path;
+ const char *path;
/* note, parse_str MUST start with 's|ifs' */
if (!PyArg_ParseTupleAndKeywords(args, kw, parse_str, (char **)kwlist, &path, index, cfra, group_name))
@@ -2226,10 +2238,10 @@ static char pyrna_struct_keyframe_insert_doc[] =
static PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyObject *kw)
{
/* args, pyrna_struct_keyframe_parse handles these */
- char *path_full= NULL;
+ const char *path_full= NULL;
int index= -1;
float cfra= FLT_MAX;
- char *group_name= NULL;
+ const char *group_name= NULL;
if(pyrna_struct_keyframe_parse(&self->ptr, args, kw, "s|ifs:bpy_struct.keyframe_insert()", "bpy_struct.keyframe_insert()", &path_full, &index, &cfra, &group_name) == -1) {
return NULL;
@@ -2241,7 +2253,7 @@ static PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *arg
BKE_reports_init(&reports, RPT_STORE);
result= insert_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0);
- MEM_freeN(path_full);
+ MEM_freeN((void *)path_full);
if(BPy_reports_to_error(&reports, TRUE))
return NULL;
@@ -2269,10 +2281,10 @@ static char pyrna_struct_keyframe_delete_doc[] =
static PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyObject *kw)
{
/* args, pyrna_struct_keyframe_parse handles these */
- char *path_full= NULL;
+ const char *path_full= NULL;
int index= -1;
float cfra= FLT_MAX;
- char *group_name= NULL;
+ const char *group_name= NULL;
if(pyrna_struct_keyframe_parse(&self->ptr, args, kw, "s|ifs:bpy_struct.keyframe_delete()", "bpy_struct.keyframe_insert()", &path_full, &index, &cfra, &group_name) == -1) {
return NULL;
@@ -2284,7 +2296,7 @@ static PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *arg
BKE_reports_init(&reports, RPT_STORE);
result= delete_keyframe(&reports, (ID *)self->ptr.id.data, NULL, group_name, path_full, index, cfra, 0);
- MEM_freeN(path_full);
+ MEM_freeN((void *)path_full);
if(BPy_reports_to_error(&reports, TRUE))
return NULL;
@@ -2308,7 +2320,7 @@ static char pyrna_struct_driver_add_doc[] =
static PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
{
- char *path, *path_full;
+ const char *path, *path_full;
int index= -1;
if (!PyArg_ParseTuple(args, "s|i:driver_add", &path, &index))
@@ -2359,7 +2371,7 @@ static PyObject *pyrna_struct_driver_add(BPy_StructRNA *self, PyObject *args)
return NULL;
}
- MEM_freeN(path_full);
+ MEM_freeN((void *)path_full);
return ret;
}
@@ -2380,7 +2392,7 @@ static char pyrna_struct_driver_remove_doc[] =
static PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args)
{
- char *path, *path_full;
+ const char *path, *path_full;
int index= -1;
if (!PyArg_ParseTuple(args, "s|i:driver_remove", &path, &index))
@@ -2397,7 +2409,7 @@ static PyObject *pyrna_struct_driver_remove(BPy_StructRNA *self, PyObject *args)
result= ANIM_remove_driver(&reports, (ID *)self->ptr.id.data, path_full, index, 0);
- MEM_freeN(path_full);
+ MEM_freeN((void *)path_full);
if(BPy_reports_to_error(&reports, TRUE))
return NULL;
@@ -2418,7 +2430,7 @@ static char pyrna_struct_is_property_set_doc[] =
static PyObject *pyrna_struct_is_property_set(BPy_StructRNA *self, PyObject *args)
{
PropertyRNA *prop;
- char *name;
+ const char *name;
int ret;
if (!PyArg_ParseTuple(args, "s:is_property_set", &name))
@@ -2458,7 +2470,7 @@ static char pyrna_struct_is_property_hidden_doc[] =
static PyObject *pyrna_struct_is_property_hidden(BPy_StructRNA *self, PyObject *args)
{
PropertyRNA *prop;
- char *name;
+ const char *name;
if (!PyArg_ParseTuple(args, "s:is_property_hidden", &name))
return NULL;
@@ -2483,7 +2495,7 @@ static char pyrna_struct_path_resolve_doc[] =
static PyObject *pyrna_struct_path_resolve(BPy_StructRNA *self, PyObject *args)
{
- char *path;
+ const char *path;
PyObject *coerce= Py_True;
PointerRNA r_ptr;
PropertyRNA *r_prop;
@@ -2534,8 +2546,8 @@ static char pyrna_struct_path_from_id_doc[] =
static PyObject *pyrna_struct_path_from_id(BPy_StructRNA *self, PyObject *args)
{
- char *name= NULL;
- char *path;
+ const char *name= NULL;
+ const char *path;
PropertyRNA *prop;
PyObject *ret;
@@ -2562,7 +2574,7 @@ static PyObject *pyrna_struct_path_from_id(BPy_StructRNA *self, PyObject *args)
}
ret= PyUnicode_FromString(path);
- MEM_freeN(path);
+ MEM_freeN((void *)path);
return ret;
}
@@ -2577,7 +2589,7 @@ static char pyrna_prop_path_from_id_doc[] =
static PyObject *pyrna_prop_path_from_id(BPy_PropertyRNA *self)
{
- char *path;
+ const char *path;
PropertyRNA *prop = self->prop;
PyObject *ret;
@@ -2589,7 +2601,7 @@ static PyObject *pyrna_prop_path_from_id(BPy_PropertyRNA *self)
}
ret= PyUnicode_FromString(path);
- MEM_freeN(path);
+ MEM_freeN((void *)path);
return ret;
}
@@ -2724,7 +2736,7 @@ static PyObject *pyrna_struct_dir(BPy_StructRNA *self)
//---------------getattr--------------------------------------------
static PyObject *pyrna_struct_getattro( BPy_StructRNA *self, PyObject *pyname )
{
- char *name = _PyUnicode_AsString(pyname);
+ const char *name = _PyUnicode_AsString(pyname);
PyObject *ret;
PropertyRNA *prop;
FunctionRNA *func;
@@ -2902,13 +2914,13 @@ static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *attr, PyOb
}
else {
/* remove existing property if its set or we also end up with confusement */
- char *attr_str= _PyUnicode_AsString(attr);
+ const char *attr_str= _PyUnicode_AsString(attr);
RNA_def_property_free_identifier(srna, attr_str); /* ignore on failier */
}
}
else { /* __delattr__ */
/* first find if this is a registered property */
- char *attr_str= _PyUnicode_AsString(attr);
+ const char *attr_str= _PyUnicode_AsString(attr);
int ret= RNA_def_property_free_identifier(srna, attr_str);
if (ret == -1) {
PyErr_Format(PyExc_TypeError, "struct_meta_idprop.detattr(): '%s' not a dynamic property", attr_str);
@@ -2922,7 +2934,7 @@ static int pyrna_struct_meta_idprop_setattro(PyObject *cls, PyObject *attr, PyOb
static int pyrna_struct_setattro( BPy_StructRNA *self, PyObject *pyname, PyObject *value )
{
- char *name = _PyUnicode_AsString(pyname);
+ const char *name = _PyUnicode_AsString(pyname);
PropertyRNA *prop= NULL;
#ifdef USE_PEDANTIC_WRITE
@@ -3005,7 +3017,7 @@ static PyObject *pyrna_prop_array_getattro( BPy_PropertyRNA *self, PyObject *pyn
static PyObject *pyrna_prop_collection_getattro( BPy_PropertyRNA *self, PyObject *pyname )
{
- char *name = _PyUnicode_AsString(pyname);
+ const char *name = _PyUnicode_AsString(pyname);
if(name == NULL) {
PyErr_SetString(PyExc_AttributeError, "bpy_prop_collection: __getattr__ must be a string");
@@ -3040,7 +3052,7 @@ static PyObject *pyrna_prop_collection_getattro( BPy_PropertyRNA *self, PyObject
//--------------- setattr-------------------------------------------
static int pyrna_prop_collection_setattro( BPy_PropertyRNA *self, PyObject *pyname, PyObject *value )
{
- char *name = _PyUnicode_AsString(pyname);
+ const char *name = _PyUnicode_AsString(pyname);
PropertyRNA *prop;
PointerRNA r_ptr;
@@ -3225,7 +3237,7 @@ static PyObject *pyrna_struct_get(BPy_StructRNA *self, PyObject *args)
{
IDProperty *group, *idprop;
- char *key;
+ const char *key;
PyObject* def = Py_None;
if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
@@ -3267,7 +3279,7 @@ static PyObject *pyrna_prop_collection_get(BPy_PropertyRNA *self, PyObject *args
{
PointerRNA newptr;
- char *key;
+ const char *key;
PyObject* def = Py_None;
if (!PyArg_ParseTuple(args, "s|O:get", &key, &def))
@@ -3279,7 +3291,7 @@ static PyObject *pyrna_prop_collection_get(BPy_PropertyRNA *self, PyObject *args
return Py_INCREF(def), def;
}
-static void foreach_attr_type( BPy_PropertyRNA *self, char *attr,
+static void foreach_attr_type( BPy_PropertyRNA *self, const char *attr,
/* values to assign */
RawPropertyType *raw_type, int *attr_tot, int *attr_signed )
{
@@ -3304,7 +3316,7 @@ static int foreach_parse_args(
BPy_PropertyRNA *self, PyObject *args,
/*values to assign */
- char **attr, PyObject **seq, int *tot, int *size, RawPropertyType *raw_type, int *attr_tot, int *attr_signed)
+ const char **attr, PyObject **seq, int *tot, int *size, RawPropertyType *raw_type, int *attr_tot, int *attr_signed)
{
#if 0
int array_tot;
@@ -3386,7 +3398,7 @@ static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set)
void *array= NULL;
/* get/set both take the same args currently */
- char *attr;
+ const char *attr;
PyObject *seq;
int tot, size, attr_tot, attr_signed;
RawPropertyType raw_type;
@@ -3986,7 +3998,7 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
DynStr *bad_args= BLI_dynstr_new();
DynStr *good_args= BLI_dynstr_new();
- char *arg_name, *bad_args_str, *good_args_str;
+ const char *arg_name, *bad_args_str, *good_args_str;
int found= FALSE, first= TRUE;
while (PyDict_Next(kw, &pos, &key, &value)) {
@@ -4039,8 +4051,8 @@ static PyObject * pyrna_func_call(PyObject *self, PyObject *args, PyObject *kw)
BLI_dynstr_free(bad_args);
BLI_dynstr_free(good_args);
- MEM_freeN(bad_args_str);
- MEM_freeN(good_args_str);
+ MEM_freeN((void *)bad_args_str);
+ MEM_freeN((void *)good_args_str);
err= -1;
}
@@ -4868,7 +4880,7 @@ static PyObject *pyrna_basetype_getattro( BPy_BaseTypeRNA *self, PyObject *pynam
{
PointerRNA newptr;
PyObject *ret;
- char *name= _PyUnicode_AsString(pyname);
+ const char *name= _PyUnicode_AsString(pyname);
if(name == NULL) {
PyErr_SetString(PyExc_AttributeError, "bpy.types: __getattr__ must be a string");
@@ -5304,8 +5316,6 @@ static int bpy_class_validate(PointerRNA *dummyptr, void *py_data, int *have_fun
return 0;
}
-extern void BPY_modules_update(bContext *C); //XXX temp solution
-
/* TODO - multiple return values like with rna functions */
static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, ParameterList *parms)
{
@@ -5324,8 +5334,9 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param
PyGILState_STATE gilstate;
#ifdef USE_PEDANTIC_WRITE
+ const char *func_id= RNA_function_identifier(func);
/* testing, for correctness, not operator and not draw function */
- const short is_readonly= strstr("draw", RNA_function_identifier(func)) || !RNA_struct_is_a(ptr->type, &RNA_Operator);
+ const short is_readonly= strstr("draw", func_id) || /*strstr("render", func_id) ||*/ !RNA_struct_is_a(ptr->type, &RNA_Operator);
#endif
py_class= RNA_struct_py_type_get(ptr->type);
diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h
index 77b602b6f83..31954eb6828 100644
--- a/source/blender/python/intern/bpy_rna.h
+++ b/source/blender/python/intern/bpy_rna.h
@@ -108,4 +108,8 @@ PyObject *pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr,
PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop);
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value);
+int pyrna_write_check(void);
+
+void BPY_modules_update(struct bContext *C); //XXX temp solution
+
#endif
diff --git a/source/blender/python/rna_dump.py b/source/blender/python/rna_dump.py
index 89240715584..df902886f30 100644
--- a/source/blender/python/rna_dump.py
+++ b/source/blender/python/rna_dump.py
@@ -18,6 +18,8 @@
#
# #**** END GPL LICENSE BLOCK #****
+# <pep8 compliant>
+
if 1:
# Print once every 1000
GEN_PATH = True
@@ -37,6 +39,7 @@ else:
seek_count = [0]
+
def seek(r, txt, recurs):
seek_count[0] += 1
@@ -71,52 +74,60 @@ def seek(r, txt, recurs):
print(txt + ' -> "' + str(r) + '"')
return
- try: keys = r.keys()
- except: keys = None
+ try:
+ keys = r.keys()
+ except:
+ keys = None
if keys != None:
if PRINT_DATA:
print(txt + '.keys() - ' + str(r.keys()))
- try: __members__ = dir(r)
- except: __members__ = []
+ try:
+ __members__ = dir(r)
+ except:
+ __members__ = []
for item in __members__:
- if item.startswith('__'):
+ if item.startswith("__"):
continue
- if GEN_PATH: newtxt = txt + '.' + item
+ if GEN_PATH:
+ newtxt = txt + '.' + item
- if item == 'rna_type' and VERBOSE_TYPE==False: # just avoid because it spits out loads of data
+ if item == 'rna_type' and VERBOSE_TYPE == False: # just avoid because it spits out loads of data
continue
- try: value = getattr(r, item)
- except: value = None
-
- seek( value, newtxt, recurs + 1)
+ value = getattr(r, item, None)
+ seek(value, newtxt, recurs + 1)
if keys:
for k in keys:
- if GEN_PATH: newtxt = txt + '["' + k + '"]'
- seek(r.__getitem__(k), newtxt, recurs+1)
+ if GEN_PATH:
+ newtxt = txt + '["' + k + '"]'
+ seek(r.__getitem__(k), newtxt, recurs + 1)
else:
- try: length = len( r )
- except: length = 0
-
- if VERBOSE==False and length >= 4:
- for i in (0, length-1):
- if i>0:
+ try:
+ length = len(r)
+ except:
+ length = 0
+
+ if VERBOSE == False and length >= 4:
+ for i in (0, length - 1):
+ if i > 0:
if PRINT_DATA:
- print((' '*len(txt)) + ' ... skipping '+str(length-2)+' items ...')
+ print((" " * len(txt)) + " ... skipping " + str(length - 2) + " items ...")
- if GEN_PATH: newtxt = txt + '[' + str(i) + ']'
- seek(r[i], newtxt, recurs+1)
+ if GEN_PATH:
+ newtxt = txt + '[' + str(i) + ']'
+ seek(r[i], newtxt, recurs + 1)
else:
for i in range(length):
- if GEN_PATH: newtxt = txt + '[' + str(i) + ']'
- seek(r[i], newtxt, recurs+1)
+ if GEN_PATH:
+ newtxt = txt + '[' + str(i) + ']'
+ seek(r[i], newtxt, recurs + 1)
seek(bpy.data, 'bpy.data', 0)
# seek(bpy.types, 'bpy.types', 0)
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index ddb7d56ca71..2680c9f183f 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -44,9 +44,14 @@ set(INC
set(SRC
intern/raytrace/rayobject.cpp
+ intern/raytrace/rayobject_empty.cpp
+ intern/raytrace/rayobject_octree.cpp
+ intern/raytrace/rayobject_raycounter.cpp
+ intern/raytrace/rayobject_svbvh.cpp
+ intern/raytrace/rayobject_blibvh.cpp
+ intern/raytrace/rayobject_instance.cpp
intern/raytrace/rayobject_qbvh.cpp
intern/raytrace/rayobject_rtbuild.cpp
- intern/raytrace/rayobject_svbvh.cpp
intern/raytrace/rayobject_vbvh.cpp
intern/source/convertblender.c
intern/source/envmap.c
@@ -58,12 +63,9 @@ set(SRC
intern/source/pixelblending.c
intern/source/pixelshading.c
intern/source/pointdensity.c
- intern/source/rayobject_blibvh.c
- intern/source/rayobject_instance.c
- intern/source/rayobject_octree.c
- intern/source/rayobject_raycounter.c
intern/source/rayshade.c
intern/source/rendercore.c
+ intern/source/render_texture.c
intern/source/renderdatabase.c
intern/source/shadbuf.c
intern/source/shadeinput.c
@@ -71,14 +73,12 @@ set(SRC
intern/source/sss.c
intern/source/strand.c
intern/source/sunsky.c
- intern/source/texture.c
intern/source/volume_precache.c
intern/source/volumetric.c
intern/source/voxeldata.c
intern/source/zbuf.c
extern/include/RE_pipeline.h
- extern/include/RE_raytrace.h
extern/include/RE_render_ext.h
extern/include/RE_shader_ext.h
intern/include/envmap.h
@@ -90,6 +90,8 @@ set(SRC
intern/include/pointdensity.h
intern/include/raycounter.h
intern/include/rayobject.h
+ intern/include/rayintersection.h
+ intern/include/raycounter.h
intern/include/render_types.h
intern/include/rendercore.h
intern/include/renderdatabase.h
@@ -106,6 +108,7 @@ set(SRC
intern/include/zbuf.h
intern/raytrace/bvh.h
intern/raytrace/rayobject_hint.h
+ intern/raytrace/rayobject_internal.h
intern/raytrace/rayobject_rtbuild.h
intern/raytrace/reorganize.h
intern/raytrace/svbvh.h
diff --git a/source/blender/render/extern/include/RE_raytrace.h b/source/blender/render/extern/include/RE_raytrace.h
deleted file mode 100644
index cf463c0795e..00000000000
--- a/source/blender/render/extern/include/RE_raytrace.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/**
- * $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) 2007 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- * RE_raytrace.h: ray tracing api, can be used independently from the renderer.
- */
-
-#ifndef RE_RAYTRACE_H
-#define RE_RAYTRACE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// #define RE_RAYCOUNTER /* enable counters per ray, usefull for measuring raytrace structures performance */
-
-#define RE_RAY_LCTS_MAX_SIZE 256
-#define RT_USE_LAST_HIT /* last shadow hit is reused before raycasting on whole tree */
-//#define RT_USE_HINT /* last hit object is reused before raycasting on whole tree */
-
-#ifdef RE_RAYCOUNTER
-
-typedef struct RayCounter RayCounter;
-struct RayCounter
-{
-
- struct
- {
- unsigned long long test, hit;
-
- } faces, bb, simd_bb, raycast, raytrace_hint, rayshadow_last_hit;
-};
-#endif
-
-/* Internals about raycasting structures can be found on intern/raytree.h */
-typedef struct RayObject RayObject;
-typedef struct Isect Isect;
-typedef struct RayHint RayHint;
-typedef struct RayTraceHint RayTraceHint;
-
-struct DerivedMesh;
-struct Mesh;
-struct VlakRen;
-struct ObjectInstanceRen;
-
-int RE_rayobject_raycast(RayObject *r, Isect *i);
-void RE_rayobject_add (RayObject *r, RayObject *);
-void RE_rayobject_done(RayObject *r);
-void RE_rayobject_free(RayObject *r);
-
-/* Extend min/max coords so that the rayobject is inside them */
-void RE_rayobject_merge_bb(RayObject *ob, float *min, float *max);
-
-/* initializes an hint for optiming raycast where it is know that a ray will pass by the given BB often the origin point */
-void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max);
-
-/* initializes an hint for optiming raycast where it is know that a ray will be contained inside the given cone*/
-/* void RE_rayobject_hint_cone(RayObject *r, RayHint *hint, float *); */
-
-/* RayObject constructors */
-RayObject* RE_rayobject_octree_create(int ocres, int size);
-RayObject* RE_rayobject_instance_create(RayObject *target, float transform[][4], void *ob, void *target_ob);
-RayObject* RE_rayobject_empty_create(void);
-
-RayObject* RE_rayobject_blibvh_create(int size); /* BLI_kdopbvh.c */
-RayObject* RE_rayobject_vbvh_create(int size); /* raytrace/rayobject_vbvh.c */
-RayObject* RE_rayobject_svbvh_create(int size); /* raytrace/rayobject_svbvh.c */
-RayObject* RE_rayobject_qbvh_create(int size); /* raytrace/rayobject_qbvh.c */
-
-
-/*
- * This ray object represents a triangle or a quad face.
- * All data needed to realize intersection is "localy" available.
- */
-typedef struct RayFace
-{
- float v1[4], v2[4], v3[4], v4[3];
- int quad;
- void *ob;
- void *face;
-
-} RayFace;
-
-#define RE_rayface_isQuad(a) ((a)->quad)
-
-RayObject* RE_rayface_from_vlak(RayFace *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr);
-RayObject* RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *co1, float *co2, float *co3, float *co4);
-
-
-/*
- * This ray object represents faces directly from a given VlakRen structure.
- * Thus allowing to save memory, but making code triangle intersection dependant on render structures
- */
-typedef struct VlakPrimitive
-{
- struct ObjectInstanceRen *ob;
- struct VlakRen *face;
-} VlakPrimitive;
-
-RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr);
-
-
-
-/*
- * Raytrace hints
- */
-typedef struct LCTSHint LCTSHint;
-struct LCTSHint
-{
- int size;
- RayObject *stack[RE_RAY_LCTS_MAX_SIZE];
-};
-
-struct RayHint
-{
- union
- {
- LCTSHint lcts;
- } data;
-};
-
-
-/* Ray Intersection */
-struct Isect
-{
- float start[3];
- float vec[3];
- float labda;
-
- /* length of vec, configured by RE_rayobject_raycast */
- int bv_index[6];
- float idot_axis[3];
- float dist;
-
-/* float end[3]; - not used */
-
- float u, v;
-
- struct
- {
- void *ob;
- void *face;
- }
- hit, orig;
-
- RayObject *last_hit; /* last hit optimization */
-
-#ifdef RT_USE_HINT
- RayTraceHint *hint, *hit_hint;
-#endif
-
- short isect; /* which half of quad */
- short mode; /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */
- int lay; /* -1 default, set for layer lamps */
-
- int skip; /* RE_SKIP_CULLFACE */
- int check;
-
- float col[4]; /* RGBA for shadow_tra */
-
- void *userdata;
-
- RayHint *hint;
-
-#ifdef RE_RAYCOUNTER
- RayCounter *raycounter;
-#endif
-};
-
-/* ray types */
-#define RE_RAY_SHADOW 0
-#define RE_RAY_MIRROR 1
-#define RE_RAY_SHADOW_TRA 2
-
-/* skip options */
-#define RE_SKIP_CULLFACE (1 << 0)
-/* if using this flag then *face should be a pointer to a VlakRen */
-#define RE_SKIP_VLR_NEIGHBOUR (1 << 1)
-
-/* check options */
-#define RE_CHECK_VLR_NONE 0
-#define RE_CHECK_VLR_RENDER 1
-#define RE_CHECK_VLR_NON_SOLID_MATERIAL 2
-#define RE_CHECK_VLR_BAKE 3
-
-/* TODO use: FLT_MAX? */
-#define RE_RAYTRACE_MAXDIST 1e33
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /*__RE_RAYTRACE_H__*/
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index 26e34a741f7..2b451810e37 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -30,7 +30,6 @@
#ifndef RE_SHADER_EXT_H
#define RE_SHADER_EXT_H
-#include "RE_raytrace.h" /* For RE_RAYCOUNTER */
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
/* this include is for shading and texture exports */
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
diff --git a/source/blender/render/intern/include/raycounter.h b/source/blender/render/intern/include/raycounter.h
index 5377a1147af..1a9b91c17a8 100644
--- a/source/blender/render/intern/include/raycounter.h
+++ b/source/blender/render/intern/include/raycounter.h
@@ -26,16 +26,27 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
+
#ifndef RE_RAYCOUNTER_H
#define RE_RAYCOUNTER_H
-#include "RE_raytrace.h"
+//#define RE_RAYCOUNTER /* enable counters per ray, usefull for measuring raytrace structures performance */
+#ifdef __cplusplus
+extern "C" {
+#endif
#ifdef RE_RAYCOUNTER
-/* #define RE_RC_INIT(isec, shi) (isec).count = re_rc_counter+(shi).thread */
-#define RE_RC_INIT(isec, shi) (isec).raycounter = &((shi).raycounter)
+/* ray counter functions */
+
+typedef struct RayCounter {
+ struct {
+ unsigned long long test, hit;
+ } faces, bb, simd_bb, raycast, raytrace_hint, rayshadow_last_hit;
+} RayCounter;
+
+#define RE_RC_INIT(isec, shi) (isec).raycounter = &((shi).shading.raycounter)
void RE_RC_INFO (RayCounter *rc);
void RE_RC_MERGE(RayCounter *rc, RayCounter *tmp);
#define RE_RC_COUNT(var) (var)++
@@ -44,12 +55,17 @@ extern RayCounter re_rc_counter[];
#else
-# define RE_RC_INIT(isec,shi)
-# define RE_RC_INFO(rc)
-# define RE_RC_MERGE(dest,src)
-# define RE_RC_COUNT(var)
+/* ray counter stubs */
+
+#define RE_RC_INIT(isec,shi)
+#define RE_RC_INFO(rc)
+#define RE_RC_MERGE(dest,src)
+#define RE_RC_COUNT(var)
#endif
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h
new file mode 100644
index 00000000000..eefd65dae1b
--- /dev/null
+++ b/source/blender/render/intern/include/rayintersection.h
@@ -0,0 +1,124 @@
+/**
+ * $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) 2007 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ * RE_raytrace.h: ray tracing api, can be used independently from the renderer.
+ */
+
+#ifndef __RENDER_RAYINTERSECTION_H__
+#define __RENDER_RAYINTERSECTION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct RayObject;
+
+/* Ray Hints */
+
+#define RE_RAY_LCTS_MAX_SIZE 256
+#define RT_USE_LAST_HIT /* last shadow hit is reused before raycasting on whole tree */
+//#define RT_USE_HINT /* last hit object is reused before raycasting on whole tree */
+
+typedef struct LCTSHint {
+ int size;
+ struct RayObject *stack[RE_RAY_LCTS_MAX_SIZE];
+} LCTSHint;
+
+typedef struct RayHint {
+ union { LCTSHint lcts; } data;
+} RayHint;
+
+/* Ray Intersection */
+
+typedef struct Isect {
+ /* ray start, direction (normalized vector), and max distance. on hit,
+ the distance is modified to be the distance to the hit point. */
+ float start[3];
+ float dir[3];
+ float dist;
+
+ /* precomputed values to accelerate bounding box intersection */
+ int bv_index[6];
+ float idot_axis[3];
+
+ /* intersection options */
+ int mode; /* RE_RAY_SHADOW, RE_RAY_MIRROR, RE_RAY_SHADOW_TRA */
+ int lay; /* -1 default, set for layer lamps */
+ int skip; /* skip flags */
+ int check; /* check flags */
+ void *userdata; /* used by bake check */
+
+ /* hit information */
+ float u, v;
+ int isect; /* which half of quad */
+
+ struct {
+ void *ob;
+ void *face;
+ } hit, orig;
+
+ /* last hit optimization */
+ struct RayObject *last_hit;
+
+ /* hints */
+#ifdef RT_USE_HINT
+ RayTraceHint *hint, *hit_hint;
+#endif
+ RayHint *hint;
+
+ /* ray counter */
+#ifdef RE_RAYCOUNTER
+ RayCounter *raycounter;
+#endif
+} Isect;
+
+/* ray types */
+#define RE_RAY_SHADOW 0
+#define RE_RAY_MIRROR 1
+#define RE_RAY_SHADOW_TRA 2
+
+/* skip options */
+#define RE_SKIP_CULLFACE (1 << 0)
+/* if using this flag then *face should be a pointer to a VlakRen */
+#define RE_SKIP_VLR_NEIGHBOUR (1 << 1)
+
+/* check options */
+#define RE_CHECK_VLR_NONE 0
+#define RE_CHECK_VLR_RENDER 1
+#define RE_CHECK_VLR_NON_SOLID_MATERIAL 2
+#define RE_CHECK_VLR_BAKE 3
+
+/* arbitrary, but can't use e.g. FLT_MAX because of precision issues */
+#define RE_RAYTRACE_MAXDIST 1e15f
+#define RE_RAYTRACE_EPSILON 0.0f
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __RENDER_RAYINTERSECTION_H__ */
+
diff --git a/source/blender/render/intern/include/rayobject.h b/source/blender/render/intern/include/rayobject.h
index e16ec83fb61..61b7a23cf54 100644
--- a/source/blender/render/intern/include/rayobject.h
+++ b/source/blender/render/intern/include/rayobject.h
@@ -26,6 +26,7 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
+
#ifndef RE_RAYOBJECT_H
#define RE_RAYOBJECT_H
@@ -33,176 +34,86 @@
extern "C" {
#endif
-#include "RE_raytrace.h"
-#include "render_types.h"
-#include <stdio.h>
-#include <float.h>
-
+struct Isect;
+struct ObjectInstanceRen;
+struct RayHint;
+struct VlakRen;
/* RayObject
-
- A ray object is everything where we can cast rays like:
- * a face/triangle
- * an octree
- * a bvh tree
- * an octree of bvh's
- * a bvh of bvh's
-
-
- All types of RayObjects can be created by implementing the
- callbacks of the RayObject.
-
- Due to high computing time evolved with casting on faces
- there is a special type of RayObject (named RayFace)
- which won't use callbacks like other generic nodes.
-
- In order to allow a mixture of RayFace+RayObjects,
- all RayObjects must be 4byte aligned, allowing us to use the
- 2 least significant bits (with the mask 0x03) to define the
- type of RayObject.
-
- This leads to 4 possible types of RayObject:
-
- addr&3 - type of object
- 0 Self (reserved for each structure)
- 1 RayFace (tri/quad primitive)
- 2 RayObject (generic with API callbacks)
- 3 VlakPrimitive
- (vlak primitive - to be used when we have a vlak describing the data
- eg.: on render code)
-
- 0 means it's reserved and has it own meaning inside each ray acceleration structure
- (this way each structure can use the allign offset to determine if a node represents a
- RayObject primitive, which can be used to save memory)
-
- You actually don't need to care about this if you are only using the API
- described on RE_raytrace.h
- */
-/* used to align a given ray object */
-#define RE_rayobject_align(o) ((RayObject*)(((intptr_t)o)&(~3)))
-
-/* used to unalign a given ray object */
-#define RE_rayobject_unalignRayFace(o) ((RayObject*)(((intptr_t)o)|1))
-#define RE_rayobject_unalignRayAPI(o) ((RayObject*)(((intptr_t)o)|2))
-#define RE_rayobject_unalignVlakPrimitive(o) ((RayObject*)(((intptr_t)o)|3))
-
-/* used to test the type of ray object */
-#define RE_rayobject_isAligned(o) ((((intptr_t)o)&3) == 0)
-#define RE_rayobject_isRayFace(o) ((((intptr_t)o)&3) == 1)
-#define RE_rayobject_isRayAPI(o) ((((intptr_t)o)&3) == 2)
-#define RE_rayobject_isVlakPrimitive(o) ((((intptr_t)o)&3) == 3)
-
-
-
-/*
- * This class is intended as a place holder for control, configuration of the rayobject like:
- * - stop building (TODO maybe when porting build to threads this could be implemented with some thread_cancel function)
- * - max number of threads and threads callback to use during build
- * ...
- */
-typedef int (*RE_rayobjectcontrol_test_break_callback)(void *data);
-typedef struct RayObjectControl RayObjectControl;
-struct RayObjectControl
-{
- void *data;
- RE_rayobjectcontrol_test_break_callback test_break;
-};
-
-/*
- * This rayobject represents a generic object. With it's own callbacks for raytrace operations.
- * It's suitable to implement things like LOD.
- */
-struct RayObject
-{
- struct RayObjectAPI *api;
-
- struct RayObjectControl control;
-};
+ Can be a face/triangle, bvh tree, object instance, etc. This is the
+ public API used by the renderer, see rayobject_internal.h for the
+ internal implementation details. */
+typedef struct RayObject RayObject;
+/* Intersection, see rayintersection.h */
+int RE_rayobject_raycast(RayObject *r, struct Isect *i);
-typedef int (*RE_rayobject_raycast_callback)(RayObject *, Isect *);
-typedef void (*RE_rayobject_add_callback)(RayObject *raytree, RayObject *rayobject);
-typedef void (*RE_rayobject_done_callback)(RayObject *);
-typedef void (*RE_rayobject_free_callback)(RayObject *);
-typedef void (*RE_rayobject_merge_bb_callback)(RayObject *, float *min, float *max);
-typedef float (*RE_rayobject_cost_callback)(RayObject *);
-typedef void (*RE_rayobject_hint_bb_callback)(RayObject *, RayHint *, float *, float *);
+/* Acceleration Structures */
-typedef struct RayObjectAPI
-{
- RE_rayobject_raycast_callback raycast;
- RE_rayobject_add_callback add;
- RE_rayobject_done_callback done;
- RE_rayobject_free_callback free;
- RE_rayobject_merge_bb_callback bb;
- RE_rayobject_cost_callback cost;
- RE_rayobject_hint_bb_callback hint_bb;
-
-} RayObjectAPI;
+RayObject* RE_rayobject_octree_create(int ocres, int size);
+RayObject* RE_rayobject_instance_create(RayObject *target, float transform[][4], void *ob, void *target_ob);
+RayObject* RE_rayobject_empty_create();
+RayObject* RE_rayobject_blibvh_create(int size); /* BLI_kdopbvh.c */
+RayObject* RE_rayobject_vbvh_create(int size); /* raytrace/rayobject_vbvh.c */
+RayObject* RE_rayobject_svbvh_create(int size); /* raytrace/rayobject_svbvh.c */
+RayObject* RE_rayobject_qbvh_create(int size); /* raytrace/rayobject_qbvh.c */
-/*
- * This function differs from RE_rayobject_raycast
- * RE_rayobject_intersect does NOT perform last-hit optimization
- * So this is probably a function to call inside raytrace structures
- */
-int RE_rayobject_intersect(RayObject *r, Isect *i);
+/* Building */
-/*
- * Returns distance ray must travel to hit the given bounding box
- * BB should be in format [2][3]
- */
-/* float RE_rayobject_bb_intersect(const Isect *i, const float *bb); */
-int RE_rayobject_bb_intersect_test(const Isect *i, const float *bb); /* same as bb_intersect but doens't calculates distance */
+void RE_rayobject_add(RayObject *r, RayObject *);
+void RE_rayobject_done(RayObject *r);
+void RE_rayobject_free(RayObject *r);
-/*
- * Returns the expected cost of raycast on this node, primitives have a cost of 1
- */
-float RE_rayobject_cost(RayObject *r);
+void RE_rayobject_set_control(RayObject *r, void *data, int (*test_break)(void *data));
+/* RayObject representing faces, all data is locally available instead
+ of referring to some external data structure, for possibly faster
+ intersection tests. */
-/*
- * Returns true if for some reason a heavy processing function should stop
- * (eg.: user asked to stop during a tree a build)
- */
-int RE_rayobjectcontrol_test_break(RayObjectControl *c);
+typedef struct RayFace {
+ float v1[4], v2[4], v3[4], v4[3];
+ int quad;
+ void *ob;
+ void *face;
+} RayFace;
+#define RE_rayface_isQuad(a) ((a)->quad)
-#define ISECT_EPSILON ((float)FLT_EPSILON)
+RayObject* RE_rayface_from_vlak(RayFace *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr);
+/* RayObject representing faces directly from a given VlakRen structure. Thus
+ allowing to save memory, but making code triangle intersection dependant on
+ render structures. */
+typedef struct VlakPrimitive {
+ struct ObjectInstanceRen *ob;
+ struct VlakRen *face;
+} VlakPrimitive;
-#if !defined(_WIN32) && !defined(_WIN64)
+RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr);
-#include <sys/time.h>
-#include <time.h>
+/* Bounding Box */
-#define BENCH(a,name) \
- { \
- double _t1, _t2; \
- struct timeval _tstart, _tend; \
- clock_t _clock_init = clock(); \
- gettimeofday ( &_tstart, NULL); \
- (a); \
- gettimeofday ( &_tend, NULL); \
- _t1 = ( double ) _tstart.tv_sec + ( double ) _tstart.tv_usec/ ( 1000*1000 ); \
- _t2 = ( double ) _tend.tv_sec + ( double ) _tend.tv_usec/ ( 1000*1000 ); \
- printf("BENCH:%s: %fs (real) %fs (cpu)\n", #name, _t2-_t1, (float)(clock()-_clock_init)/CLOCKS_PER_SEC);\
- }
-#else
+/* extend min/max coords so that the rayobject is inside them */
+void RE_rayobject_merge_bb(RayObject *ob, float *min, float *max);
-#define BENCH(a,name) (a)
+/* initializes an hint for optiming raycast where it is know that a ray will pass by the given BB often the origin point */
+void RE_rayobject_hint_bb(RayObject *r, struct RayHint *hint, float *min, float *max);
-#endif
+/* initializes an hint for optiming raycast where it is know that a ray will be contained inside the given cone*/
+/* void RE_rayobject_hint_cone(RayObject *r, struct RayHint *hint, float *); */
+/* Internals */
+#include "../raytrace/rayobject_internal.h"
#ifdef __cplusplus
}
#endif
-
#endif
+
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index 1de918de749..0e74e7715ef 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -609,6 +609,7 @@ typedef struct LampRen {
#define R_DIVIDE_24 32
/* vertex normals are tangent or view-corrected vector, for hair strands */
#define R_TANGENT 64
+#define R_TRACEBLE 128
/* strandbuffer->flag */
#define R_STRAND_BSPLINE 1
diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h
index e9e30f64fdd..3b0929bbe27 100644
--- a/source/blender/render/intern/include/rendercore.h
+++ b/source/blender/render/intern/include/rendercore.h
@@ -48,6 +48,7 @@ struct RenderPart;
struct RenderLayer;
struct ObjectRen;
struct ListBase;
+struct RayObject;
/* ------------------------------------------------------------------------- */
@@ -95,7 +96,7 @@ int get_sample_layers(struct RenderPart *pa, struct RenderLayer *rl, struct Rend
extern void freeraytree(Render *re);
extern void makeraytree(Render *re);
-RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi);
+struct RayObject* makeraytree_object(Render *re, ObjectInstanceRen *obi);
extern void ray_shadow(ShadeInput *, LampRen *, float *);
extern void ray_trace(ShadeInput *, ShadeResult *);
diff --git a/source/blender/render/intern/include/volumetric.h b/source/blender/render/intern/include/volumetric.h
index 37b1bd7ca29..827aaf3672c 100644
--- a/source/blender/render/intern/include/volumetric.h
+++ b/source/blender/render/intern/include/volumetric.h
@@ -26,6 +26,10 @@
* ***** END GPL LICENSE BLOCK *****
*/
+struct Isect;
+struct ShadeInput;
+struct ShadeResult;
+
float vol_get_density(struct ShadeInput *shi, float *co);
void vol_get_scattering(ShadeInput *shi, float *scatter_col, float *co_);
diff --git a/source/blender/render/intern/raytrace/bvh.h b/source/blender/render/intern/raytrace/bvh.h
index c31d1213b99..dd23967297a 100644
--- a/source/blender/render/intern/raytrace/bvh.h
+++ b/source/blender/render/intern/raytrace/bvh.h
@@ -26,12 +26,16 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-#include "rayobject.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+
#include "raycounter.h"
-#include "rayobject_rtbuild.h"
+#include "rayintersection.h"
+#include "rayobject.h"
#include "rayobject_hint.h"
-
-#include "BLI_utildefines.h"
+#include "rayobject_rtbuild.h"
#include <assert.h>
@@ -45,21 +49,49 @@
#ifdef __SSE__
inline int test_bb_group4(__m128 *bb_group, const Isect *isec)
{
-
const __m128 tmin0 = _mm_setzero_ps();
- const __m128 tmax0 = _mm_load1_ps(&isec->labda);
-
- const __m128 tmin1 = _mm_max_ps(tmin0, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[0]], _mm_load1_ps(&isec->start[0]) ), _mm_load1_ps(&isec->idot_axis[0])) );
- const __m128 tmax1 = _mm_min_ps(tmax0, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[1]], _mm_load1_ps(&isec->start[0]) ), _mm_load1_ps(&isec->idot_axis[0])) );
- const __m128 tmin2 = _mm_max_ps(tmin1, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[2]], _mm_load1_ps(&isec->start[1]) ), _mm_load1_ps(&isec->idot_axis[1])) );
- const __m128 tmax2 = _mm_min_ps(tmax1, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[3]], _mm_load1_ps(&isec->start[1]) ), _mm_load1_ps(&isec->idot_axis[1])) );
- const __m128 tmin3 = _mm_max_ps(tmin2, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[4]], _mm_load1_ps(&isec->start[2]) ), _mm_load1_ps(&isec->idot_axis[2])) );
- const __m128 tmax3 = _mm_min_ps(tmax2, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[5]], _mm_load1_ps(&isec->start[2]) ), _mm_load1_ps(&isec->idot_axis[2])) );
+ const __m128 tmax0 = _mm_set_ps1(isec->dist);
+
+ float start[3], idot_axis[3];
+ copy_v3_v3(start, isec->start);
+ copy_v3_v3(idot_axis, isec->idot_axis);
+
+ const __m128 tmin1 = _mm_max_ps(tmin0, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[0]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) );
+ const __m128 tmax1 = _mm_min_ps(tmax0, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[1]], _mm_set_ps1(start[0]) ), _mm_set_ps1(idot_axis[0])) );
+ const __m128 tmin2 = _mm_max_ps(tmin1, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[2]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) );
+ const __m128 tmax2 = _mm_min_ps(tmax1, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[3]], _mm_set_ps1(start[1]) ), _mm_set_ps1(idot_axis[1])) );
+ const __m128 tmin3 = _mm_max_ps(tmin2, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[4]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) );
+ const __m128 tmax3 = _mm_min_ps(tmax2, _mm_mul_ps( _mm_sub_ps( bb_group[isec->bv_index[5]], _mm_set_ps1(start[2]) ), _mm_set_ps1(idot_axis[2])) );
return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3));
}
#endif
+/*
+ * Determines the distance that the ray must travel to hit the bounding volume of the given node
+ * Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe
+ * [http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9]
+ */
+static int rayobject_bb_intersect_test(const Isect *isec, const float *_bb)
+{
+ const float *bb = _bb;
+
+ float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0];
+ float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0];
+ float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1];
+ float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1];
+ float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2];
+ float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2];
+
+ RE_RC_COUNT(isec->raycounter->bb.test);
+
+ if(t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0;
+ if(t2x < 0.0 || t2y < 0.0 || t2z < 0.0) return 0;
+ if(t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0;
+ RE_RC_COUNT(isec->raycounter->bb.hit);
+
+ return 1;
+}
/* bvh tree generics */
template<class Tree> static int bvh_intersect(Tree *obj, Isect *isec);
@@ -108,7 +140,7 @@ static float bvh_cost(Tree *obj)
/* bvh tree nodes generics */
template<class Node> static inline int bvh_node_hit_test(Node *node, Isect *isec)
{
- return RE_rayobject_bb_intersect_test(isec, (const float*)node->bb);
+ return rayobject_bb_intersect_test(isec, (const float*)node->bb);
}
@@ -133,7 +165,7 @@ static inline void bvh_node_merge_bb(Node *node, float *min, float *max)
*/
template<class Node> static inline void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos);
-template<class Node,int MAX_STACK_SIZE,bool TEST_ROOT>
+template<class Node,int MAX_STACK_SIZE,bool TEST_ROOT,bool SHADOW>
static int bvh_node_stack_raycast(Node *root, Isect *isec)
{
Node *stack[MAX_STACK_SIZE];
@@ -158,7 +190,7 @@ static int bvh_node_stack_raycast(Node *root, Isect *isec)
else
{
hit |= RE_rayobject_intersect( (RayObject*)node, isec);
- if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ if(SHADOW && hit) return hit;
}
}
return hit;
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
index c267b89fc2c..dd4932f0bd9 100644
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ b/source/blender/render/intern/raytrace/rayobject.cpp
@@ -22,135 +22,90 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): Andr Pinto.
+ * Contributor(s): André Pinto.
*
* ***** END GPL LICENSE BLOCK *****
*/
+
#include <assert.h>
+#include "MEM_guardedalloc.h"
+
#include "BLI_math.h"
#include "BLI_utildefines.h"
-
-
#include "DNA_material_types.h"
-#include "RE_raytrace.h"
-
-#include "render_types.h"
+#include "rayintersection.h"
#include "rayobject.h"
#include "raycounter.h"
+#include "render_types.h"
-/*
- * Determines the distance that the ray must travel to hit the bounding volume of the given node
- * Based on Tactical Optimization of Ray/Box Intersection, by Graham Fyffe
- * [http://tog.acm.org/resources/RTNews/html/rtnv21n1.html#art9]
- */
-int RE_rayobject_bb_intersect_test(const Isect *isec, const float *_bb)
-{
- const float *bb = _bb;
-
- float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0];
- float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0];
- float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1];
- float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1];
- float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2];
- float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2];
-
- RE_RC_COUNT(isec->raycounter->bb.test);
-
- if(t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0;
- if(t2x < 0.0 || t2y < 0.0 || t2z < 0.0) return 0;
- if(t1x > isec->labda || t1y > isec->labda || t1z > isec->labda) return 0;
- RE_RC_COUNT(isec->raycounter->bb.hit);
-
- return 1;
-}
+/* RayFace
+ note we force always inline here, because compiler refuses to otherwise
+ because function is too long. Since this is code that is called billions
+ of times we really do want to inline. */
-/* only for self-intersecting test with current render face (where ray left) */
-static int intersection2(VlakRen *face, float r0, float r1, float r2, float rx1, float ry1, float rz1)
+MALWAYS_INLINE RayObject* rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4)
{
- float co1[3], co2[3], co3[3], co4[3];
- float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22;
- float m0, m1, m2, divdet, det, det1;
- float u1, v, u2;
+ rayface->ob = ob;
+ rayface->face = face;
+
+ copy_v3_v3(rayface->v1, v1);
+ copy_v3_v3(rayface->v2, v2);
+ copy_v3_v3(rayface->v3, v3);
- VECCOPY(co1, face->v1->co);
- VECCOPY(co2, face->v2->co);
- if(face->v4)
+ if(v4)
{
- VECCOPY(co3, face->v4->co);
- VECCOPY(co4, face->v3->co);
+ copy_v3_v3(rayface->v4, v4);
+ rayface->quad = 1;
}
else
{
- VECCOPY(co3, face->v3->co);
+ rayface->quad = 0;
}
- t00= co3[0]-co1[0];
- t01= co3[1]-co1[1];
- t02= co3[2]-co1[2];
- t10= co3[0]-co2[0];
- t11= co3[1]-co2[1];
- t12= co3[2]-co2[2];
-
- x0= t11*r2-t12*r1;
- x1= t12*r0-t10*r2;
- x2= t10*r1-t11*r0;
-
- divdet= t00*x0+t01*x1+t02*x2;
+ return RE_rayobject_unalignRayFace(rayface);
+}
- m0= rx1-co3[0];
- m1= ry1-co3[1];
- m2= rz1-co3[2];
- det1= m0*x0+m1*x1+m2*x2;
-
- if(divdet!=0.0f) {
- u1= det1/divdet;
+MALWAYS_INLINE void rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
+{
+ rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0);
- if(u1<ISECT_EPSILON) {
- det= t00*(m1*r2-m2*r1);
- det+= t01*(m2*r0-m0*r2);
- det+= t02*(m0*r1-m1*r0);
- v= det/divdet;
+ if(obi->transform_primitives)
+ {
+ mul_m4_v3(obi->mat, rayface->v1);
+ mul_m4_v3(obi->mat, rayface->v2);
+ mul_m4_v3(obi->mat, rayface->v3);
- if(v<ISECT_EPSILON && (u1 + v) > -(1.0f+ISECT_EPSILON)) {
- return 1;
- }
- }
+ if(RE_rayface_isQuad(rayface))
+ mul_m4_v3(obi->mat, rayface->v4);
}
+}
- if(face->v4) {
+RayObject* RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
+{
+ return rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0);
+}
- t20= co3[0]-co4[0];
- t21= co3[1]-co4[1];
- t22= co3[2]-co4[2];
+/* VlakPrimitive */
- divdet= t20*x0+t21*x1+t22*x2;
- if(divdet!=0.0f) {
- u2= det1/divdet;
-
- if(u2<ISECT_EPSILON) {
- det= t20*(m1*r2-m2*r1);
- det+= t21*(m2*r0-m0*r2);
- det+= t22*(m0*r1-m1*r0);
- v= det/divdet;
-
- if(v<ISECT_EPSILON && (u2 + v) >= -(1.0f+ISECT_EPSILON)) {
- return 2;
- }
- }
- }
- }
- return 0;
+RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr)
+{
+ face->ob = obi;
+ face->face = vlr;
+
+ return RE_rayobject_unalignVlakPrimitive(face);
}
-static inline int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr)
+/* Checks for ignoring faces or materials */
+
+MALWAYS_INLINE int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen *vlr)
{
/* for baking selected to active non-traceable materials might still
* be in the raytree */
- if(!(vlr->mat->mode & MA_TRACEBLE))
+ if(!(vlr->flag & R_TRACEBLE))
return 0;
/* I know... cpu cycle waste, might do smarter once */
@@ -160,7 +115,7 @@ static inline int vlr_check_intersect(Isect *is, ObjectInstanceRen *obi, VlakRen
return (is->lay & obi->lay);
}
-static inline int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr)
+MALWAYS_INLINE int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr)
{
/* solid material types only */
if (vlr->mat->material_type == MA_TYPE_SURFACE)
@@ -169,168 +124,223 @@ static inline int vlr_check_intersect_solid(Isect *is, ObjectInstanceRen* obi, V
return 0;
}
-static inline int vlr_check_bake(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr)
+MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen* obi, VlakRen *vlr)
{
return (obi->obr->ob != is->userdata);
}
-static inline int rayface_check_cullface(RayFace *face, Isect *is)
-{
- float nor[3];
-
- /* don't intersect if the ray faces along the face normal */
- if(face->quad) normal_quad_v3( nor,face->v1, face->v2, face->v3, face->v4);
- else normal_tri_v3( nor,face->v1, face->v2, face->v3);
-
- return (INPR(nor, is->vec) < 0);
-}
+/* Ray Triangle/Quad Intersection */
-/* ray - triangle or quad intersection */
-/* this function shall only modify Isect if it detects an hit */
-static int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is)
+MALWAYS_INLINE int isec_tri_quad(float start[3], float dir[3], RayFace *face, float uv[2], float *lambda)
{
- float co1[3],co2[3],co3[3],co4[3]={0};
- float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22,r0,r1,r2;
- float m0, m1, m2, divdet, det1;
- float labda, u, v;
- short ok=0;
-
- if(is->orig.ob == face->ob && is->orig.face == face->face)
- return 0;
-
- /* check if we should intersect this face */
- if(is->check == RE_CHECK_VLR_RENDER)
- {
- if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face ) == 0)
- return 0;
- }
- else if(is->check == RE_CHECK_VLR_NON_SOLID_MATERIAL)
- {
- if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face ) == 0)
- return 0;
- if(vlr_check_intersect_solid(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0)
- return 0;
- }
- else if(is->check == RE_CHECK_VLR_BAKE) {
- if(vlr_check_bake(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face ) == 0)
- return 0;
- }
+ float co1[3], co2[3], co3[3], co4[3];
+ float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1, l;
+ int quad;
- if(is->skip & RE_SKIP_CULLFACE)
- {
- if(rayface_check_cullface(face, is) == 0)
- return 0;
- }
+ quad= RE_rayface_isQuad(face);
- RE_RC_COUNT(is->raycounter->faces.test);
+ copy_v3_v3(co1, face->v1);
+ copy_v3_v3(co2, face->v2);
+ copy_v3_v3(co3, face->v3);
- //Load coords
- VECCOPY(co1, face->v1);
- VECCOPY(co2, face->v2);
- if(RE_rayface_isQuad(face))
- {
- VECCOPY(co3, face->v4);
- VECCOPY(co4, face->v3);
- }
- else
- {
- VECCOPY(co3, face->v3);
- }
+ copy_v3_v3(r, dir);
- t00= co3[0]-co1[0];
- t01= co3[1]-co1[1];
- t02= co3[2]-co1[2];
- t10= co3[0]-co2[0];
- t11= co3[1]-co2[1];
- t12= co3[2]-co2[2];
-
- r0= is->vec[0];
- r1= is->vec[1];
- r2= is->vec[2];
-
- x0= t12*r1-t11*r2;
- x1= t10*r2-t12*r0;
- x2= t11*r0-t10*r1;
+ /* intersect triangle */
+ sub_v3_v3v3(t0, co3, co2);
+ sub_v3_v3v3(t1, co3, co1);
- divdet= t00*x0+t01*x1+t02*x2;
+ cross_v3_v3v3(x, r, t1);
+ divdet= dot_v3v3(t0, x);
- m0= is->start[0]-co3[0];
- m1= is->start[1]-co3[1];
- m2= is->start[2]-co3[2];
- det1= m0*x0+m1*x1+m2*x2;
+ sub_v3_v3v3(m, start, co3);
+ det1= dot_v3v3(m, x);
- if(divdet!=0.0f) {
-
+ if(divdet != 0.0f) {
divdet= 1.0f/divdet;
- u= det1*divdet;
- if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
- float cros0, cros1, cros2;
-
- cros0= m1*t02-m2*t01;
- cros1= m2*t00-m0*t02;
- cros2= m0*t01-m1*t00;
- v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
+ v= det1*divdet;
- if(v<ISECT_EPSILON && (u + v) > -(1.0f+ISECT_EPSILON)) {
- labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
+ if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
+ float cros[3];
- if(labda>-ISECT_EPSILON && labda<is->labda) {
- ok= 1;
+ cross_v3_v3v3(cros, m, t0);
+ u= divdet*dot_v3v3(cros, r);
+
+ if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) {
+ l= divdet*dot_v3v3(cros, t1);
+
+ /* check if intersection is within ray length */
+ if(l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+ uv[0]= u;
+ uv[1]= v;
+ *lambda= l;
+ return 1;
}
}
}
}
- if(ok==0 && RE_rayface_isQuad(face)) {
-
- t20= co3[0]-co4[0];
- t21= co3[1]-co4[1];
- t22= co3[2]-co4[2];
+ /* intersect second triangle in quad */
+ if(quad) {
+ copy_v3_v3(co4, face->v4);
+ sub_v3_v3v3(t0, co3, co4);
+ divdet= dot_v3v3(t0, x);
- divdet= t20*x0+t21*x1+t22*x2;
- if(divdet!=0.0f) {
+ if(divdet != 0.0f) {
divdet= 1.0f/divdet;
- u = det1*divdet;
+ v = det1*divdet;
- if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
- float cros0, cros1, cros2;
- cros0= m1*t22-m2*t21;
- cros1= m2*t20-m0*t22;
- cros2= m0*t21-m1*t20;
- v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
+ if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
+ float cros[3];
+
+ cross_v3_v3v3(cros, m, t0);
+ u= divdet*dot_v3v3(cros, r);
- if(v<ISECT_EPSILON && (u + v) >-(1.0f+ISECT_EPSILON)) {
- labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
+ if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON)) {
+ l= divdet*dot_v3v3(cros, t1);
- if(labda>-ISECT_EPSILON && labda<is->labda) {
- ok= 2;
+ if(l >- RE_RAYTRACE_EPSILON && l < *lambda) {
+ uv[0]= u;
+ uv[1]= -(1.0f + v + u);
+ *lambda= l;
+ return 2;
}
}
}
}
}
+ return 0;
+}
+
+/* Simpler yes/no Ray Triangle/Quad Intersection */
+
+MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face)
+{
+ float co1[3], co2[3], co3[3], co4[3];
+ float t0[3], t1[3], x[3], r[3], m[3], u, v, divdet, det1;
+ int quad;
+
+ quad= RE_rayface_isQuad(face);
+
+ copy_v3_v3(co1, face->v1);
+ copy_v3_v3(co2, face->v2);
+ copy_v3_v3(co3, face->v3);
+
+ negate_v3_v3(r, dir); /* note, different than above function */
+
+ /* intersect triangle */
+ sub_v3_v3v3(t0, co3, co2);
+ sub_v3_v3v3(t1, co3, co1);
+
+ cross_v3_v3v3(x, r, t1);
+ divdet= dot_v3v3(t0, x);
+
+ sub_v3_v3v3(m, start, co3);
+ det1= dot_v3v3(m, x);
+
+ if(divdet != 0.0f) {
+ divdet= 1.0f/divdet;
+ v= det1*divdet;
+
+ if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
+ float cros[3];
+
+ cross_v3_v3v3(cros, m, t0);
+ u= divdet*dot_v3v3(cros, r);
+
+ if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON))
+ return 1;
+ }
+ }
+
+ /* intersect second triangle in quad */
+ if(quad) {
+ copy_v3_v3(co4, face->v4);
+ sub_v3_v3v3(t0, co3, co4);
+ divdet= dot_v3v3(t0, x);
+
+ if(divdet != 0.0f) {
+ divdet= 1.0f/divdet;
+ v = det1*divdet;
+
+ if(v < RE_RAYTRACE_EPSILON && v > -(1.0f+RE_RAYTRACE_EPSILON)) {
+ float cros[3];
+
+ cross_v3_v3v3(cros, m, t0);
+ u= divdet*dot_v3v3(cros, r);
+
+ if(u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f+RE_RAYTRACE_EPSILON))
+ return 2;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/* RayFace intersection with checks and neighbour verifaction included,
+ Isect is modified if the face is hit. */
+
+MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is)
+{
+ float dist, uv[2];
+ int ok= 0;
+
+ /* avoid self-intersection */
+ if(is->orig.ob == face->ob && is->orig.face == face->face)
+ return 0;
+
+ /* check if we should intersect this face */
+ if(is->check == RE_CHECK_VLR_RENDER)
+ {
+ if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0)
+ return 0;
+ }
+ else if(is->check == RE_CHECK_VLR_NON_SOLID_MATERIAL)
+ {
+ if(vlr_check_intersect(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0)
+ return 0;
+ if(vlr_check_intersect_solid(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0)
+ return 0;
+ }
+ else if(is->check == RE_CHECK_VLR_BAKE) {
+ if(vlr_check_bake(is, (ObjectInstanceRen*)face->ob, (VlakRen*)face->face) == 0)
+ return 0;
+ }
+
+ /* ray counter */
+ RE_RC_COUNT(is->raycounter->faces.test);
+
+ dist= is->dist;
+ ok= isec_tri_quad(is->start, is->dir, face, uv, &dist);
+
if(ok) {
- /* when a shadow ray leaves a face, it can be little outside the edges of it, causing
- intersection to be detected in its neighbour face */
+ /* when a shadow ray leaves a face, it can be little outside the edges
+ of it, causing intersection to be detected in its neighbour face */
if(is->skip & RE_SKIP_VLR_NEIGHBOUR)
{
- if(labda < 0.1f && is->orig.ob == face->ob)
+ if(dist < 0.1f && is->orig.ob == face->ob)
{
VlakRen * a = (VlakRen*)is->orig.face;
VlakRen * b = (VlakRen*)face->face;
- /* so there's a shared edge or vertex, let's intersect ray with face
- itself, if that's true we can safely return 1, otherwise we assume
- the intersection is invalid, 0 */
+ /* so there's a shared edge or vertex, let's intersect ray with
+ face itself, if that's true we can safely return 1, otherwise
+ we assume the intersection is invalid, 0 */
if(a->v1==b->v1 || a->v2==b->v1 || a->v3==b->v1 || a->v4==b->v1
|| a->v1==b->v2 || a->v2==b->v2 || a->v3==b->v2 || a->v4==b->v2
|| a->v1==b->v3 || a->v2==b->v3 || a->v3==b->v3 || a->v4==b->v3
- || (b->v4 && (a->v1==b->v4 || a->v2==b->v4 || a->v3==b->v4 || a->v4==b->v4)))
- if(!intersection2((VlakRen*)a, -r0, -r1, -r2, is->start[0], is->start[1], is->start[2]))
- {
- return 0;
+ || (b->v4 && (a->v1==b->v4 || a->v2==b->v4 || a->v3==b->v4 || a->v4==b->v4))) {
+ /* create RayFace from original face, transformed if necessary */
+ RayFace origface;
+ ObjectInstanceRen *ob= (ObjectInstanceRen*)is->orig.ob;
+ rayface_from_vlak(&origface, ob, (VlakRen*)is->orig.face);
+
+ if(!isec_tri_quad_neighbour(is->start, is->dir, &origface))
+ {
+ return 0;
+ }
}
}
}
@@ -338,8 +348,8 @@ static int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is)
RE_RC_COUNT(is->raycounter->faces.hit);
is->isect= ok; // which half of the quad
- is->labda= labda;
- is->u= u; is->v= v;
+ is->dist= dist;
+ is->u= uv[0]; is->v= uv[1];
is->hit.ob = face->ob;
is->hit.face = face->face;
@@ -352,51 +362,18 @@ static int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *is)
return 0;
}
-RayObject* RE_rayface_from_vlak(RayFace *rayface, ObjectInstanceRen *obi, VlakRen *vlr)
-{
- return RE_rayface_from_coords(rayface, obi, vlr, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4 ? vlr->v4->co : 0 );
-}
-
-RayObject* RE_rayface_from_coords(RayFace *rayface, void *ob, void *face, float *v1, float *v2, float *v3, float *v4)
-{
- rayface->ob = ob;
- rayface->face = face;
-
- VECCOPY(rayface->v1, v1);
- VECCOPY(rayface->v2, v2);
- VECCOPY(rayface->v3, v3);
- if(v4)
- {
- VECCOPY(rayface->v4, v4);
- rayface->quad = 1;
- }
- else
- {
- rayface->quad = 0;
- }
-
- return RE_rayobject_unalignRayFace(rayface);
-}
-
-RayObject* RE_vlakprimitive_from_vlak(VlakPrimitive *face, struct ObjectInstanceRen *obi, struct VlakRen *vlr)
-{
- face->ob = obi;
- face->face = vlr;
- return RE_rayobject_unalignVlakPrimitive(face);
-}
-
+/* Intersection */
int RE_rayobject_raycast(RayObject *r, Isect *isec)
{
int i;
+
RE_RC_COUNT(isec->raycounter->raycast.test);
- /* Setup vars used on raycast */
- isec->dist = len_v3(isec->vec);
-
+ /* setup vars used on raycast */
for(i=0; i<3; i++)
{
- isec->idot_axis[i] = 1.0f / isec->vec[i];
+ isec->idot_axis[i] = 1.0f / isec->dir[i];
isec->bv_index[2*i] = isec->idot_axis[i] < 0.0 ? 1 : 0;
isec->bv_index[2*i+1] = 1 - isec->bv_index[2*i];
@@ -406,7 +383,7 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec)
}
#ifdef RT_USE_LAST_HIT
- /* Last hit heuristic */
+ /* last hit heuristic */
if(isec->mode==RE_RAY_SHADOW && isec->last_hit)
{
RE_RC_COUNT(isec->raycounter->rayshadow_last_hit.test);
@@ -433,6 +410,7 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec)
#endif
return 1;
}
+
return 0;
}
@@ -447,103 +425,93 @@ int RE_rayobject_intersect(RayObject *r, Isect *i)
//TODO optimize (useless copy to RayFace to avoid duplicate code)
VlakPrimitive *face = (VlakPrimitive*) RE_rayobject_align(r);
RayFace nface;
- RE_rayface_from_vlak(&nface, face->ob, face->face);
-
- if(face->ob->transform_primitives)
- {
- mul_m4_v3(face->ob->mat, nface.v1);
- mul_m4_v3(face->ob->mat, nface.v2);
- mul_m4_v3(face->ob->mat, nface.v3);
- if(RE_rayface_isQuad(&nface))
- mul_m4_v3(face->ob->mat, nface.v4);
- }
+ rayface_from_vlak(&nface, face->ob, face->face);
return intersect_rayface(r, &nface, i);
}
else if(RE_rayobject_isRayAPI(r))
{
- r = RE_rayobject_align( r );
- return r->api->raycast( r, i );
+ r = RE_rayobject_align(r);
+ return r->api->raycast(r, i);
+ }
+ else {
+ assert(0);
+ return 0;
}
- else assert(0);
- return 0; /* wont reach this, quiet compilers */
}
+/* Building */
+
void RE_rayobject_add(RayObject *r, RayObject *o)
{
- r = RE_rayobject_align( r );
- return r->api->add( r, o );
+ r = RE_rayobject_align(r);
+ return r->api->add(r, o);
}
void RE_rayobject_done(RayObject *r)
{
- r = RE_rayobject_align( r );
- r->api->done( r );
+ r = RE_rayobject_align(r);
+ r->api->done(r);
}
void RE_rayobject_free(RayObject *r)
{
- r = RE_rayobject_align( r );
- r->api->free( r );
+ r = RE_rayobject_align(r);
+ r->api->free(r);
}
+float RE_rayobject_cost(RayObject *r)
+{
+ if(RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r))
+ {
+ return 1.0f;
+ }
+ else if(RE_rayobject_isRayAPI(r))
+ {
+ r = RE_rayobject_align(r);
+ return r->api->cost(r);
+ }
+ else {
+ assert(0);
+ return 1.0f;
+ }
+}
+
+/* Bounding Boxes */
+
void RE_rayobject_merge_bb(RayObject *r, float *min, float *max)
{
if(RE_rayobject_isRayFace(r))
{
RayFace *face = (RayFace*) RE_rayobject_align(r);
- DO_MINMAX( face->v1, min, max );
- DO_MINMAX( face->v2, min, max );
- DO_MINMAX( face->v3, min, max );
- if(RE_rayface_isQuad(face)) DO_MINMAX( face->v4, min, max );
+ DO_MINMAX(face->v1, min, max);
+ DO_MINMAX(face->v2, min, max);
+ DO_MINMAX(face->v3, min, max);
+ if(RE_rayface_isQuad(face)) DO_MINMAX(face->v4, min, max);
}
else if(RE_rayobject_isVlakPrimitive(r))
{
VlakPrimitive *face = (VlakPrimitive*) RE_rayobject_align(r);
RayFace nface;
- RE_rayface_from_vlak(&nface, face->ob, face->face);
-
- if(face->ob->transform_primitives)
- {
- mul_m4_v3(face->ob->mat, nface.v1);
- mul_m4_v3(face->ob->mat, nface.v2);
- mul_m4_v3(face->ob->mat, nface.v3);
- if(RE_rayface_isQuad(&nface))
- mul_m4_v3(face->ob->mat, nface.v4);
- }
-
- DO_MINMAX( nface.v1, min, max );
- DO_MINMAX( nface.v2, min, max );
- DO_MINMAX( nface.v3, min, max );
- if(RE_rayface_isQuad(&nface)) DO_MINMAX( nface.v4, min, max );
- }
- else if(RE_rayobject_isRayAPI(r))
- {
- r = RE_rayobject_align( r );
- r->api->bb( r, min, max );
- }
- else assert(0);
-}
+ rayface_from_vlak(&nface, face->ob, face->face);
-float RE_rayobject_cost(RayObject *r)
-{
- if(RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r))
- {
- return 1.0;
+ DO_MINMAX(nface.v1, min, max);
+ DO_MINMAX(nface.v2, min, max);
+ DO_MINMAX(nface.v3, min, max);
+ if(RE_rayface_isQuad(&nface)) DO_MINMAX(nface.v4, min, max);
}
else if(RE_rayobject_isRayAPI(r))
{
- r = RE_rayobject_align( r );
- return r->api->cost( r );
+ r = RE_rayobject_align(r);
+ r->api->bb(r, min, max);
}
else
- {
assert(0);
- return 1.0; /* XXX, better default value? */
- }
}
+/* Hints */
+
void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max)
{
if(RE_rayobject_isRayFace(r) || RE_rayobject_isVlakPrimitive(r))
@@ -552,60 +520,30 @@ void RE_rayobject_hint_bb(RayObject *r, RayHint *hint, float *min, float *max)
}
else if(RE_rayobject_isRayAPI(r))
{
- r = RE_rayobject_align( r );
- return r->api->hint_bb( r, hint, min, max );
+ r = RE_rayobject_align(r);
+ return r->api->hint_bb(r, hint, min, max);
}
- else assert(0);
+ else
+ assert(0);
}
+/* RayObjectControl */
+
int RE_rayobjectcontrol_test_break(RayObjectControl *control)
{
if(control->test_break)
- return control->test_break( control->data );
+ return control->test_break(control->data);
return 0;
}
-
-/*
- * Empty raytree
- */
-static int RE_rayobject_empty_intersect(RayObject *o, Isect *is)
+void RE_rayobject_set_control(RayObject *r, void *data, RE_rayobjectcontrol_test_break_callback test_break)
{
- return 0;
-}
-
-static void RE_rayobject_empty_free(RayObject *o)
-{
-}
-
-static void RE_rayobject_empty_bb(RayObject *o, float *min, float *max)
-{
- return;
-}
-
-static float RE_rayobject_empty_cost(RayObject *o)
-{
- return 0.0;
+ if(RE_rayobject_isRayAPI(r))
+ {
+ r = RE_rayobject_align(r);
+ r->control.data = data;
+ r->control.test_break = test_break;
+ }
}
-static void RE_rayobject_empty_hint_bb(RayObject *o, RayHint *hint, float *min, float *max)
-{}
-
-static RayObjectAPI empty_api =
-{
- RE_rayobject_empty_intersect,
- NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob);
- NULL, //static void RE_rayobject_instance_done(RayObject *o);
- RE_rayobject_empty_free,
- RE_rayobject_empty_bb,
- RE_rayobject_empty_cost,
- RE_rayobject_empty_hint_bb
-};
-
-static RayObject empty_raytree = { &empty_api, {0, 0} };
-
-RayObject *RE_rayobject_empty_create()
-{
- return RE_rayobject_unalignRayAPI( &empty_raytree );
-}
diff --git a/source/blender/render/intern/source/rayobject_blibvh.c b/source/blender/render/intern/raytrace/rayobject_blibvh.cpp
index fa5c32a8e8d..5231c221662 100644
--- a/source/blender/render/intern/source/rayobject_blibvh.c
+++ b/source/blender/render/intern/raytrace/rayobject_blibvh.cpp
@@ -22,7 +22,7 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): Andr Pinto.
+ * Contributor(s): André Pinto.
*
* ***** END GPL LICENSE BLOCK *****
*/
@@ -33,8 +33,8 @@
#include "BLI_kdopbvh.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "RE_raytrace.h"
-#include "render_types.h"
+
+#include "rayintersection.h"
#include "rayobject.h"
static int RE_rayobject_blibvh_intersect(RayObject *o, Isect *isec);
@@ -71,14 +71,12 @@ typedef struct BVHObject
RayObject **leafs, **next_leaf;
BVHTree *bvh;
float bb[2][3];
-
} BVHObject;
-
RayObject *RE_rayobject_blibvh_create(int size)
{
BVHObject *obj= (BVHObject*)MEM_callocN(sizeof(BVHObject), "BVHObject");
- assert( RE_rayobject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */
+ assert(RE_rayobject_isAligned(obj)); /* RayObject API assumes real data to be 4-byte aligned */
obj->rayobj.api = &bvh_api;
obj->bvh = BLI_bvhtree_new(size, 0.0, 4, 6);
@@ -107,7 +105,7 @@ static void bvh_callback(void *userdata, int index, const BVHTreeRay *ray, BVHTr
if(isec->mode == RE_RAY_SHADOW)
hit->dist = 0;
else
- hit->dist = isec->labda*isec->dist;
+ hit->dist = isec->dist;
}
}
@@ -120,11 +118,10 @@ static int RE_rayobject_blibvh_intersect(RayObject *o, Isect *isec)
data.isec = isec;
data.leafs = obj->leafs;
- VECCOPY(dir, isec->vec);
- normalize_v3(dir);
+ copy_v3_v3(dir, isec->dir);
hit.index = 0;
- hit.dist = isec->labda*isec->dist;
+ hit.dist = isec->dist;
return BLI_bvhtree_ray_cast(obj->bvh, isec->start, dir, 0.0, &hit, bvh_callback, (void*)&data);
}
@@ -139,7 +136,7 @@ static void RE_rayobject_blibvh_add(RayObject *o, RayObject *ob)
DO_MIN(min_max , obj->bb[0]);
DO_MAX(min_max+3, obj->bb[1]);
- BLI_bvhtree_insert(obj->bvh, obj->next_leaf - obj->leafs, min_max, 2 );
+ BLI_bvhtree_insert(obj->bvh, obj->next_leaf - obj->leafs, min_max, 2);
*(obj->next_leaf++) = ob;
}
@@ -165,6 +162,7 @@ static void RE_rayobject_blibvh_free(RayObject *o)
static void RE_rayobject_blibvh_bb(RayObject *o, float *min, float *max)
{
BVHObject *obj = (BVHObject*)o;
- DO_MIN( obj->bb[0], min );
- DO_MAX( obj->bb[1], max );
+ DO_MIN(obj->bb[0], min);
+ DO_MAX(obj->bb[1], max);
}
+
diff --git a/source/blender/render/intern/raytrace/rayobject_empty.cpp b/source/blender/render/intern/raytrace/rayobject_empty.cpp
new file mode 100644
index 00000000000..abd54ab9fab
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_empty.cpp
@@ -0,0 +1,75 @@
+/**
+ * $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) 1990-1998 NeoGeo BV.
+ * All rights reserved.
+ *
+ * Contributors: 2004/2005 Blender Foundation, full recode
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "rayobject.h"
+
+/*
+ * Empty raytree
+ */
+
+static int RE_rayobject_empty_intersect(RayObject *o, Isect *is)
+{
+ return 0;
+}
+
+static void RE_rayobject_empty_free(RayObject *o)
+{
+}
+
+static void RE_rayobject_empty_bb(RayObject *o, float *min, float *max)
+{
+ return;
+}
+
+static float RE_rayobject_empty_cost(RayObject *o)
+{
+ return 0.0;
+}
+
+static void RE_rayobject_empty_hint_bb(RayObject *o, RayHint *hint, float *min, float *max)
+{}
+
+static RayObjectAPI empty_api =
+{
+ RE_rayobject_empty_intersect,
+ NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob);
+ NULL, //static void RE_rayobject_instance_done(RayObject *o);
+ RE_rayobject_empty_free,
+ RE_rayobject_empty_bb,
+ RE_rayobject_empty_cost,
+ RE_rayobject_empty_hint_bb
+};
+
+static RayObject empty_raytree = { &empty_api, {0, 0} };
+
+RayObject *RE_rayobject_empty_create()
+{
+ return RE_rayobject_unalignRayAPI( &empty_raytree );
+}
+
diff --git a/source/blender/render/intern/raytrace/rayobject_hint.h b/source/blender/render/intern/raytrace/rayobject_hint.h
index 1ea59d00bac..adb7d652276 100644
--- a/source/blender/render/intern/raytrace/rayobject_hint.h
+++ b/source/blender/render/intern/raytrace/rayobject_hint.h
@@ -26,6 +26,7 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
+
#ifndef RE_RAYTRACE_RAYOBJECT_HINT_H
#define RE_RAYTRACE_RAYOBJECT_HINT_H
@@ -68,3 +69,4 @@ inline int hint_test_bb(HintFrustum &obj, float *Nmin, float *Nmax)
*/
#endif
+
diff --git a/source/blender/render/intern/source/rayobject_instance.c b/source/blender/render/intern/raytrace/rayobject_instance.cpp
index d7b4beb8023..6274c76a004 100644
--- a/source/blender/render/intern/source/rayobject_instance.c
+++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp
@@ -22,19 +22,19 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): Andr Pinto.
+ * Contributor(s): André Pinto.
*
* ***** END GPL LICENSE BLOCK *****
*/
+
#include <assert.h>
#include "MEM_guardedalloc.h"
-
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "RE_raytrace.h"
+#include "rayintersection.h"
#include "rayobject.h"
#define RE_COST_INSTANCE (1.0f)
@@ -44,7 +44,7 @@ static void RE_rayobject_instance_free(RayObject *o);
static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max);
static float RE_rayobject_instance_cost(RayObject *o);
-static void RE_rayobject_instance_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint), float *UNUSED(min), float *UNUSED(max))
+static void RE_rayobject_instance_hint_bb(RayObject *o, RayHint *hint, float *min, float *max)
{}
static RayObjectAPI instance_api =
@@ -90,42 +90,32 @@ RayObject *RE_rayobject_instance_create(RayObject *target, float transform[][4],
static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
{
- //TODO
- // *there is probably a faster way to convert between coordinates
-
InstanceRayObject *obj = (InstanceRayObject*)o;
- int res;
- float start[3], vec[3], labda, dist;
- int changed = 0, i;
+ float start[3], dir[3], idot_axis[3], dist;
+ int changed = 0, i, res;
- //TODO - this is disabling self intersection on instances
+ // TODO - this is disabling self intersection on instances
if(isec->orig.ob == obj->ob && obj->ob)
{
changed = 1;
isec->orig.ob = obj->target_ob;
}
-
- VECCOPY( start, isec->start );
- VECCOPY( vec , isec->vec );
- labda = isec->labda;
- dist = isec->dist;
-
- //Transform to target coordinates system
- VECADD( isec->vec, isec->vec, isec->start );
+ // backup old values
+ copy_v3_v3(start, isec->start);
+ copy_v3_v3(dir, isec->dir);
+ copy_v3_v3(idot_axis, isec->idot_axis);
+ dist = isec->dist;
+ // transform to target coordinates system
mul_m4_v3(obj->global2target, isec->start);
- mul_m4_v3(obj->global2target, isec->vec );
-
- isec->dist = len_v3v3( isec->start, isec->vec );
- VECSUB( isec->vec, isec->vec, isec->start );
+ mul_mat3_m4_v3(obj->global2target, isec->dir);
+ isec->dist *= normalize_v3(isec->dir);
- isec->labda *= isec->dist / dist;
-
- //Update idot_axis and bv_index
+ // update idot_axis and bv_index
for(i=0; i<3; i++)
{
- isec->idot_axis[i] = 1.0f / isec->vec[i];
+ isec->idot_axis[i] = 1.0f / isec->dir[i];
isec->bv_index[2*i] = isec->idot_axis[i] < 0.0 ? 1 : 0;
isec->bv_index[2*i+1] = 1 - isec->bv_index[2*i];
@@ -134,17 +124,24 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
isec->bv_index[2*i+1] = i+3*isec->bv_index[2*i+1];
}
- //Raycast
+ // raycast
res = RE_rayobject_intersect(obj->target, isec);
- //Restore coordinate space coords
+ // map dist into original coordinate space
if(res == 0)
{
- isec->labda = labda;
+ isec->dist = dist;
}
else
{
- isec->labda *= dist / isec->dist;
+ // note we don't just multiply dist, because of possible
+ // non-uniform scaling in the transform matrix
+ float vec[3];
+
+ mul_v3_v3fl(vec, isec->dir, isec->dist);
+ mul_mat3_m4_v3(obj->target2global, vec);
+
+ isec->dist = len_v3(vec);
isec->hit.ob = obj->ob;
#ifdef RT_USE_LAST_HIT
@@ -154,18 +151,18 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
isec->last_hit = RE_rayobject_unalignRayAPI((RayObject*) obj);
#endif
}
- isec->dist = dist;
- VECCOPY( isec->start, start );
- VECCOPY( isec->vec, vec );
+
+ // restore values
+ copy_v3_v3(isec->start, start);
+ copy_v3_v3(isec->dir, dir);
+ copy_v3_v3(isec->idot_axis, idot_axis);
if(changed)
isec->orig.ob = obj->ob;
- //Update idot_axis and bv_index
+ // restore bv_index
for(i=0; i<3; i++)
{
- isec->idot_axis[i] = 1.0f / isec->vec[i];
-
isec->bv_index[2*i] = isec->idot_axis[i] < 0.0 ? 1 : 0;
isec->bv_index[2*i+1] = 1 - isec->bv_index[2*i];
@@ -208,3 +205,4 @@ static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max)
DO_MINMAX(t, min, max);
}
}
+
diff --git a/source/blender/render/intern/raytrace/rayobject_internal.h b/source/blender/render/intern/raytrace/rayobject_internal.h
new file mode 100644
index 00000000000..6067be07c50
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_internal.h
@@ -0,0 +1,128 @@
+
+#ifndef RE_RAYOBJECT_INTERNAL_H
+#define RE_RAYOBJECT_INTERNAL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* RayObjectControl
+ *
+ * This class is intended as a place holder for control, configuration of the
+ * rayobject like:
+ * - stop building (TODO maybe when porting build to threads this could be
+ * implemented with some thread_cancel function)
+ * - max number of threads and threads callback to use during build
+ * ...
+ */
+
+typedef int (*RE_rayobjectcontrol_test_break_callback)(void *data);
+
+typedef struct RayObjectControl {
+ void *data;
+ RE_rayobjectcontrol_test_break_callback test_break;
+} RayObjectControl;
+
+/* Returns true if for some reason a heavy processing function should stop
+ * (eg.: user asked to stop during a tree a build)
+ */
+
+int RE_rayobjectcontrol_test_break(RayObjectControl *c);
+
+/* RayObject
+
+ A ray object is everything where we can cast rays like:
+ * a face/triangle
+ * an octree
+ * a bvh tree
+ * an octree of bvh's
+ * a bvh of bvh's
+
+
+ All types of RayObjects can be created by implementing the
+ callbacks of the RayObject.
+
+ Due to high computing time evolved with casting on faces
+ there is a special type of RayObject (named RayFace)
+ which won't use callbacks like other generic nodes.
+
+ In order to allow a mixture of RayFace+RayObjects,
+ all RayObjects must be 4byte aligned, allowing us to use the
+ 2 least significant bits (with the mask 0x03) to define the
+ type of RayObject.
+
+ This leads to 4 possible types of RayObject:
+
+ addr&3 - type of object
+ 0 Self (reserved for each structure)
+ 1 RayFace (tri/quad primitive)
+ 2 RayObject (generic with API callbacks)
+ 3 VlakPrimitive
+ (vlak primitive - to be used when we have a vlak describing the data
+ eg.: on render code)
+
+ 0 means it's reserved and has it own meaning inside each ray acceleration structure
+ (this way each structure can use the allign offset to determine if a node represents a
+ RayObject primitive, which can be used to save memory)
+ */
+
+/* used to test the type of ray object */
+#define RE_rayobject_isAligned(o) ((((intptr_t)o)&3) == 0)
+#define RE_rayobject_isRayFace(o) ((((intptr_t)o)&3) == 1)
+#define RE_rayobject_isRayAPI(o) ((((intptr_t)o)&3) == 2)
+#define RE_rayobject_isVlakPrimitive(o) ((((intptr_t)o)&3) == 3)
+
+/* used to align a given ray object */
+#define RE_rayobject_align(o) ((RayObject*)(((intptr_t)o)&(~3)))
+
+/* used to unalign a given ray object */
+#define RE_rayobject_unalignRayFace(o) ((RayObject*)(((intptr_t)o)|1))
+#define RE_rayobject_unalignRayAPI(o) ((RayObject*)(((intptr_t)o)|2))
+#define RE_rayobject_unalignVlakPrimitive(o) ((RayObject*)(((intptr_t)o)|3))
+
+/*
+ * This rayobject represents a generic object. With it's own callbacks for raytrace operations.
+ * It's suitable to implement things like LOD.
+ */
+
+struct RayObject {
+ struct RayObjectAPI *api;
+ struct RayObjectControl control;
+};
+
+typedef int (*RE_rayobject_raycast_callback)(RayObject *, struct Isect *);
+typedef void (*RE_rayobject_add_callback)(RayObject *raytree, RayObject *rayobject);
+typedef void (*RE_rayobject_done_callback)(RayObject *);
+typedef void (*RE_rayobject_free_callback)(RayObject *);
+typedef void (*RE_rayobject_merge_bb_callback)(RayObject *, float *min, float *max);
+typedef float (*RE_rayobject_cost_callback)(RayObject *);
+typedef void (*RE_rayobject_hint_bb_callback)(RayObject *, struct RayHint *, float *, float *);
+
+typedef struct RayObjectAPI {
+ RE_rayobject_raycast_callback raycast;
+ RE_rayobject_add_callback add;
+ RE_rayobject_done_callback done;
+ RE_rayobject_free_callback free;
+ RE_rayobject_merge_bb_callback bb;
+ RE_rayobject_cost_callback cost;
+ RE_rayobject_hint_bb_callback hint_bb;
+} RayObjectAPI;
+
+/*
+ * Returns the expected cost of raycast on this node, primitives have a cost of 1
+ */
+float RE_rayobject_cost(RayObject *r);
+
+/*
+ * This function differs from RE_rayobject_raycast
+ * RE_rayobject_intersect does NOT perform last-hit optimization
+ * So this is probably a function to call inside raytrace structures
+ */
+int RE_rayobject_intersect(RayObject *r, struct Isect *i);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/source/blender/render/intern/source/rayobject_octree.c b/source/blender/render/intern/raytrace/rayobject_octree.cpp
index 8a8b102c6fa..9db9f1ffdb8 100644
--- a/source/blender/render/intern/source/rayobject_octree.c
+++ b/source/blender/render/intern/raytrace/rayobject_octree.cpp
@@ -41,8 +41,7 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-
-
+#include "rayintersection.h"
#include "rayobject.h"
/* ********** structs *************** */
@@ -126,8 +125,8 @@ static void calc_ocval_face(float *v1, float *v2, float *v3, float *v4, short x,
float min[3], max[3];
int ocmin, ocmax;
- VECCOPY(min, v1);
- VECCOPY(max, v1);
+ copy_v3_v3(min, v1);
+ copy_v3_v3(max, v1);
DO_MINMAX(v2, min, max);
DO_MINMAX(v3, min, max);
if(v4) {
@@ -192,7 +191,7 @@ static Branch *addbranch(Octree *oc, Branch *br, short ocb)
index= oc->branchcount>>12;
if(oc->adrbranch[index]==NULL)
- oc->adrbranch[index]= MEM_callocN(4096*sizeof(Branch), "new oc branch");
+ oc->adrbranch[index]= (Branch*)MEM_callocN(4096*sizeof(Branch), "new oc branch");
if(oc->branchcount>= BRANCH_ARRAY*4096) {
printf("error; octree branches full\n");
@@ -210,7 +209,7 @@ static Node *addnode(Octree *oc)
index= oc->nodecount>>12;
if(oc->adrnode[index]==NULL)
- oc->adrnode[index]= MEM_callocN(4096*sizeof(Node),"addnode");
+ oc->adrnode[index]= (Node*)MEM_callocN(4096*sizeof(Node),"addnode");
if(oc->nodecount> NODE_ARRAY*NODE_ARRAY) {
printf("error; octree nodes full\n");
@@ -465,7 +464,7 @@ static void RE_rayobject_octree_free(RayObject *tree)
RayObject *RE_rayobject_octree_create(int ocres, int size)
{
- Octree *oc= MEM_callocN(sizeof(Octree), "Octree");
+ Octree *oc= (Octree*)MEM_callocN(sizeof(Octree), "Octree");
assert( RE_rayobject_isAligned(oc) ); /* RayObject API assumes real data to be 4-byte aligned */
oc->rayobj.api = &octree_api;
@@ -505,11 +504,11 @@ static void octree_fill_rayface(Octree *oc, RayFace *face)
ocres2= oc->ocres*oc->ocres;
- VECCOPY(co1, face->v1);
- VECCOPY(co2, face->v2);
- VECCOPY(co3, face->v3);
+ copy_v3_v3(co1, face->v1);
+ copy_v3_v3(co2, face->v2);
+ copy_v3_v3(co3, face->v3);
if(face->v4)
- VECCOPY(co4, face->v4);
+ copy_v3_v3(co4, face->v4);
for(c=0;c<3;c++) {
rtf[0][c]= (co1[c]-oc->min[c])*ocfac[c] ;
@@ -621,13 +620,13 @@ static void RE_rayobject_octree_done(RayObject *tree)
RE_rayobject_merge_bb( RE_rayobject_unalignRayFace(oc->ro_nodes[c]), oc->min, oc->max);
/* Alloc memory */
- oc->adrbranch= MEM_callocN(sizeof(void *)*BRANCH_ARRAY, "octree branches");
- oc->adrnode= MEM_callocN(sizeof(void *)*NODE_ARRAY, "octree nodes");
+ oc->adrbranch= (Branch**)MEM_callocN(sizeof(void *)*BRANCH_ARRAY, "octree branches");
+ oc->adrnode= (Node**)MEM_callocN(sizeof(void *)*NODE_ARRAY, "octree nodes");
oc->adrbranch[0]=(Branch *)MEM_callocN(4096*sizeof(Branch), "makeoctree");
/* the lookup table, per face, for which nodes to fill in */
- oc->ocface= MEM_callocN( 3*ocres2 + 8, "ocface");
+ oc->ocface= (char*)MEM_callocN( 3*ocres2 + 8, "ocface");
memset(oc->ocface, 0, 3*ocres2);
for(c=0;c<3;c++) { /* octree enlarge, still needed? */
@@ -857,20 +856,20 @@ static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is)
is->userdata= oc->userdata;
#endif
- VECCOPY( start, is->start );
- VECADDFAC( end, is->start, is->vec, is->labda );
- ldx= is->vec[0]*is->labda;
- olabda = is->labda;
+ copy_v3_v3( start, is->start );
+ madd_v3_v3v3fl( end, is->start, is->dir, is->dist );
+ ldx= is->dir[0]*is->dist;
+ olabda = is->dist;
u1= 0.0f;
u2= 1.0f;
/* clip with octree cube */
if(cliptest(-ldx, start[0]-oc->min[0], &u1,&u2)) {
if(cliptest(ldx, oc->max[0]-start[0], &u1,&u2)) {
- ldy= is->vec[1]*is->labda;
+ ldy= is->dir[1]*is->dist;
if(cliptest(-ldy, start[1]-oc->min[1], &u1,&u2)) {
if(cliptest(ldy, oc->max[1]-start[1], &u1,&u2)) {
- ldz = is->vec[2]*is->labda;
+ ldz = is->dir[2]*is->dist;
if(cliptest(-ldz, start[2]-oc->min[2], &u1,&u2)) {
if(cliptest(ldz, oc->max[2]-start[2], &u1,&u2)) {
c1=1;
@@ -974,11 +973,10 @@ static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is)
ldz=0;
dz= 0;
}
-
+
xo=ocx1; yo=ocy1; zo=ocz1;
- ddalabda= MIN3(labdax,labday,labdaz);
- /*labdao= ddalabda;*/ /*NEVER READ*/
-
+ labdao= ddalabda= MIN3(labdax,labday,labdaz);
+
vec2[0]= ox1;
vec2[1]= oy1;
vec2[2]= oz1;
@@ -992,18 +990,18 @@ static int RE_rayobject_octree_intersect(RayObject *tree, Isect *is)
if(no) {
/* calculate ray intersection with octree node */
- VECCOPY(vec1, vec2);
+ copy_v3_v3(vec1, vec2);
// dox,y,z is negative
vec2[0]= ox1-ddalabda*dox;
vec2[1]= oy1-ddalabda*doy;
vec2[2]= oz1-ddalabda*doz;
calc_ocval_ray(&ocval, (float)xo, (float)yo, (float)zo, vec1, vec2);
- //is->labda = (u1+ddalabda*(u2-u1))*olabda;
+ //is->dist = (u1+ddalabda*(u2-u1))*olabda;
if( testnode(oc, is, no, ocval) )
found = 1;
- if(is->labda < (u1+ddalabda*(u2-u1))*olabda)
+ if(is->dist < (u1+ddalabda*(u2-u1))*olabda)
return found;
}
diff --git a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp
index c510af540db..e8a118d3349 100644
--- a/source/blender/render/intern/raytrace/rayobject_qbvh.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_qbvh.cpp
@@ -26,7 +26,11 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
+
#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
#include "vbvh.h"
#include "svbvh.h"
#include "reorganize.h"
@@ -60,10 +64,10 @@ void bvh_done<QBVHTree>(QBVHTree *obj)
BLI_memarena_use_malloc(arena2);
BLI_memarena_use_align(arena2, 16);
- //Build and optimize the tree
- //TODO do this in 1 pass (half memory usage during building)
+ //Build and optimize the tree
+ //TODO do this in 1 pass (half memory usage during building)
VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
-
+
if(RE_rayobjectcontrol_test_break(&obj->rayobj.control))
{
BLI_memarena_free(arena1);
@@ -71,28 +75,32 @@ void bvh_done<QBVHTree>(QBVHTree *obj)
return;
}
- pushup_simd<VBVHNode,4>(root);
+ pushup_simd<VBVHNode,4>(root);
+
obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root);
- //Cleanup
- BLI_memarena_free(arena1);
+ //Free data
+ BLI_memarena_free(arena1);
- rtbuild_free( obj->builder );
- obj->builder = NULL;
-
obj->node_arena = arena2;
- obj->cost = 1.0;
-}
+ obj->cost = 1.0;
+ rtbuild_free(obj->builder);
+ obj->builder = NULL;
+}
template<int StackSize>
int intersect(QBVHTree *obj, Isect* isec)
{
//TODO renable hint support
- if(RE_rayobject_isAligned(obj->root))
- return bvh_node_stack_raycast<SVBVHNode,StackSize,false>( obj->root, isec);
+ if(RE_rayobject_isAligned(obj->root)) {
+ if(isec->mode == RE_RAY_SHADOW)
+ return svbvh_node_stack_raycast<StackSize,true>(obj->root, isec);
+ else
+ return svbvh_node_stack_raycast<StackSize,false>(obj->root, isec);
+ }
else
- return RE_rayobject_intersect( (RayObject*) obj->root, isec );
+ return RE_rayobject_intersect((RayObject*)obj->root, isec);
}
template<class Tree>
@@ -132,13 +140,11 @@ RayObjectAPI* bvh_get_api(int maxstacksize)
return 0;
}
-
RayObject *RE_rayobject_qbvh_create(int size)
{
return bvh_create_tree<QBVHTree,DFS_STACK_SIZE>(size);
}
-
#else
RayObject *RE_rayobject_qbvh_create(int size)
diff --git a/source/blender/render/intern/source/rayobject_raycounter.c b/source/blender/render/intern/raytrace/rayobject_raycounter.cpp
index 16446bde501..52262a8044a 100644
--- a/source/blender/render/intern/source/rayobject_raycounter.c
+++ b/source/blender/render/intern/raytrace/rayobject_raycounter.cpp
@@ -26,6 +26,7 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
+
#include "rayobject.h"
#include "raycounter.h"
diff --git a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
index 79bb3b9260f..cdaaebc7f92 100644
--- a/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_rtbuild.cpp
@@ -22,23 +22,23 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): Andr Pinto.
+ * Contributor(s): André Pinto.
*
* ***** END GPL LICENSE BLOCK *****
*/
+
#include <assert.h>
#include <math.h>
#include <stdlib.h>
#include <algorithm>
#include "rayobject_rtbuild.h"
+
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
-
-
static bool selected_node(RTBuilder::Object *node)
{
return node->selected;
@@ -94,13 +94,22 @@ void rtbuild_free(RTBuilder *b)
void rtbuild_add(RTBuilder *b, RayObject *o)
{
+ float bb[6];
+
assert( b->primitives.begin + b->primitives.maxsize != b->primitives.end );
+
+ INIT_MINMAX(bb, bb+3);
+ RE_rayobject_merge_bb(o, bb, bb+3);
+
+ /* skip objects with zero bounding box, they are of no use, and
+ will give problems in rtbuild_heuristic_object_split later */
+ if(len_squared_v3v3(bb, bb+3) == 0.0f)
+ return;
+ copy_v3_v3(b->primitives.end->bb, bb);
+ copy_v3_v3(b->primitives.end->bb+3, bb+3);
b->primitives.end->obj = o;
b->primitives.end->cost = RE_rayobject_cost(o);
-
- INIT_MINMAX(b->primitives.end->bb, b->primitives.end->bb+3);
- RE_rayobject_merge_bb(o, b->primitives.end->bb, b->primitives.end->bb+3);
for(int i=0; i<3; i++)
{
@@ -333,8 +342,8 @@ int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds)
{
if(i == size-1)
{
- VECCOPY(sweep[i].bb, obj[i]->bb);
- VECCOPY(sweep[i].bb+3, obj[i]->bb+3);
+ copy_v3_v3(sweep[i].bb, obj[i]->bb);
+ copy_v3_v3(sweep[i].bb+3, obj[i]->bb+3);
sweep[i].cost = obj[i]->cost;
}
else
@@ -365,8 +374,12 @@ int rtbuild_heuristic_object_split(RTBuilder *b, int nchilds)
//Worst case heuristic (cost of each child is linear)
float hcost, left_side, right_side;
- left_side = bb_area(sweep_left.bb, sweep_left.bb+3)*(sweep_left.cost+logf((float)i));
- right_side= bb_area(sweep[i].bb, sweep[i].bb+3)*(sweep[i].cost+logf((float)size-i));
+ // not using log seems to have no impact on raytracing perf, but
+ // makes tree construction quicker, left out for now to test (brecht)
+ // left_side = bb_area(sweep_left.bb, sweep_left.bb+3)*(sweep_left.cost+logf((float)i));
+ // right_side= bb_area(sweep[i].bb, sweep[i].bb+3)*(sweep[i].cost+logf((float)size-i));
+ left_side = bb_area(sweep_left.bb, sweep_left.bb+3)*(sweep_left.cost);
+ right_side= bb_area(sweep[i].bb, sweep[i].bb+3)*(sweep[i].cost);
hcost = left_side+right_side;
assert(left_side >= 0);
diff --git a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp
index 647c5771e4f..c10da3ad8c0 100644
--- a/source/blender/render/intern/raytrace/rayobject_svbvh.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_svbvh.cpp
@@ -26,8 +26,11 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
+
#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
+
#include "vbvh.h"
#include "svbvh.h"
#include "reorganize.h"
@@ -75,7 +78,8 @@ void bvh_done<SVBVHTree>(SVBVHTree *obj)
//Build and optimize the tree
if(0)
{
- VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1,&obj->rayobj.control).transform(obj->builder);
+ VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
+
if(RE_rayobjectcontrol_test_break(&obj->rayobj.control))
{
BLI_memarena_free(arena1);
@@ -86,11 +90,11 @@ void bvh_done<SVBVHTree>(SVBVHTree *obj)
reorganize(root);
remove_useless(root, &root);
bvh_refit(root);
-
+
pushup(root);
pushdown(root);
pushup_simd<VBVHNode,4>(root);
-
+
obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root);
}
else
@@ -98,6 +102,7 @@ void bvh_done<SVBVHTree>(SVBVHTree *obj)
//Finds the optimal packing of this tree using a given cost model
//TODO this uses quite a lot of memory, find ways to reduce memory usage during building
OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena1,&obj->rayobj.control).transform(obj->builder);
+
if(RE_rayobjectcontrol_test_break(&obj->rayobj.control))
{
BLI_memarena_free(arena1);
@@ -108,15 +113,13 @@ void bvh_done<SVBVHTree>(SVBVHTree *obj)
VBVH_optimalPackSIMD<OVBVHNode,PackCost>(PackCost()).transform(root);
obj->root = Reorganize_SVBVH<OVBVHNode>(arena2).transform(root);
}
-
//Free data
BLI_memarena_free(arena1);
obj->node_arena = arena2;
obj->cost = 1.0;
-
-
+
rtbuild_free( obj->builder );
obj->builder = NULL;
}
@@ -125,8 +128,12 @@ template<int StackSize>
int intersect(SVBVHTree *obj, Isect* isec)
{
//TODO renable hint support
- if(RE_rayobject_isAligned(obj->root))
- return bvh_node_stack_raycast<SVBVHNode,StackSize,false>( obj->root, isec);
+ if(RE_rayobject_isAligned(obj->root)) {
+ if(isec->mode == RE_RAY_SHADOW)
+ return svbvh_node_stack_raycast<StackSize,true>(obj->root, isec);
+ else
+ return svbvh_node_stack_raycast<StackSize,false>(obj->root, isec);
+ }
else
return RE_rayobject_intersect( (RayObject*) obj->root, isec );
}
@@ -172,6 +179,7 @@ RayObject *RE_rayobject_svbvh_create(int size)
{
return bvh_create_tree<SVBVHTree,DFS_STACK_SIZE>(size);
}
+
#else
RayObject *RE_rayobject_svbvh_create(int size)
diff --git a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp
index b2104a2d557..df5842db2bf 100644
--- a/source/blender/render/intern/raytrace/rayobject_vbvh.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_vbvh.cpp
@@ -22,29 +22,33 @@
*
* The Original Code is: all of this file.
*
- * Contributor(s): Andr Pinto.
+ * Contributor(s): André Pinto.
*
* ***** END GPL LICENSE BLOCK *****
*/
+
int tot_pushup = 0;
int tot_pushdown = 0;
int tot_hints = 0;
-
#include <assert.h>
-#include "rayobject.h"
-#include "rayobject_rtbuild.h"
-#include "RE_raytrace.h"
-#include "BLI_memarena.h"
+
#include "MEM_guardedalloc.h"
+
#include "BKE_global.h"
#include "BLI_math.h"
+#include "BLI_memarena.h"
+#include "BLI_utildefines.h"
+
+#include "rayintersection.h"
+#include "rayobject.h"
+#include "rayobject_rtbuild.h"
#include "reorganize.h"
#include "bvh.h"
#include "vbvh.h"
-#include "svbvh.h"
+
#include <queue>
#include <algorithm>
@@ -126,8 +130,12 @@ template<int StackSize>
int intersect(VBVHTree *obj, Isect* isec)
{
//TODO renable hint support
- if(RE_rayobject_isAligned(obj->root))
- return bvh_node_stack_raycast<VBVHNode,StackSize,false>( obj->root, isec);
+ if(RE_rayobject_isAligned(obj->root)) {
+ if(isec->mode == RE_RAY_SHADOW)
+ return bvh_node_stack_raycast<VBVHNode,StackSize,false,true>( obj->root, isec);
+ else
+ return bvh_node_stack_raycast<VBVHNode,StackSize,false,false>( obj->root, isec);
+ }
else
return RE_rayobject_intersect( (RayObject*) obj->root, isec );
}
diff --git a/source/blender/render/intern/raytrace/reorganize.h b/source/blender/render/intern/raytrace/reorganize.h
index c8fbd1cfe94..4e2dce32136 100644
--- a/source/blender/render/intern/raytrace/reorganize.h
+++ b/source/blender/render/intern/raytrace/reorganize.h
@@ -26,18 +26,18 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
+
+#include <float.h>
+#include <math.h>
#include <stdio.h>
+
#include <algorithm>
-#include <math.h>
-#include <vector>
#include <queue>
-
-#include "BLI_utildefines.h"
+#include <vector>
#include "BKE_global.h"
#ifdef _WIN32
-#undef INFINITY
#define INFINITY FLT_MAX // in mingw math.h: (1.0F/0.0F). This generates compile error, though.
#endif
@@ -302,7 +302,7 @@ float bvh_refit(Node *node)
* with the purpose to reduce the expected cost (eg.: number of BB tests).
*/
#include <vector>
-#define MAX_CUT_SIZE 16
+#define MAX_CUT_SIZE 4 /* svbvh assumes max 4 children! */
#define MAX_OPTIMIZE_CHILDS MAX_CUT_SIZE
struct OVBVHNode
diff --git a/source/blender/render/intern/raytrace/svbvh.h b/source/blender/render/intern/raytrace/svbvh.h
index 11511fccb89..832058870dd 100644
--- a/source/blender/render/intern/raytrace/svbvh.h
+++ b/source/blender/render/intern/raytrace/svbvh.h
@@ -26,6 +26,7 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
+
#ifdef __SSE__
#ifndef RE_RAYTRACE_SVBVH_H
@@ -33,56 +34,132 @@
#include "bvh.h"
#include "BLI_memarena.h"
-#include "BLI_utildefines.h"
#include "BKE_global.h"
#include <stdio.h>
#include <algorithm>
struct SVBVHNode
{
+ float child_bb[24];
+ SVBVHNode *child[4];
int nchilds;
-
- //Array of bb, array of childs
- float *child_bb;
- SVBVHNode **child;
};
-template<>
-inline int bvh_node_hit_test<SVBVHNode>(SVBVHNode *node, Isect *isec)
+static int svbvh_bb_intersect_test_simd4(const Isect *isec, const __m128 *bb_group)
+{
+ const __m128 tmin0 = _mm_setzero_ps();
+ const __m128 tmax0 = _mm_set_ps1(isec->dist);
+
+ const __m128 start0 = _mm_set_ps1(isec->start[0]);
+ const __m128 start1 = _mm_set_ps1(isec->start[1]);
+ const __m128 start2 = _mm_set_ps1(isec->start[2]);
+ const __m128 sub0 = _mm_sub_ps(bb_group[isec->bv_index[0]], start0);
+ const __m128 sub1 = _mm_sub_ps(bb_group[isec->bv_index[1]], start0);
+ const __m128 sub2 = _mm_sub_ps(bb_group[isec->bv_index[2]], start1);
+ const __m128 sub3 = _mm_sub_ps(bb_group[isec->bv_index[3]], start1);
+ const __m128 sub4 = _mm_sub_ps(bb_group[isec->bv_index[4]], start2);
+ const __m128 sub5 = _mm_sub_ps(bb_group[isec->bv_index[5]], start2);
+ const __m128 idot_axis0 = _mm_set_ps1(isec->idot_axis[0]);
+ const __m128 idot_axis1 = _mm_set_ps1(isec->idot_axis[1]);
+ const __m128 idot_axis2 = _mm_set_ps1(isec->idot_axis[2]);
+ const __m128 mul0 = _mm_mul_ps(sub0, idot_axis0);
+ const __m128 mul1 = _mm_mul_ps(sub1, idot_axis0);
+ const __m128 mul2 = _mm_mul_ps(sub2, idot_axis1);
+ const __m128 mul3 = _mm_mul_ps(sub3, idot_axis1);
+ const __m128 mul4 = _mm_mul_ps(sub4, idot_axis2);
+ const __m128 mul5 = _mm_mul_ps(sub5, idot_axis2);
+ const __m128 tmin1 = _mm_max_ps(tmin0, mul0);
+ const __m128 tmax1 = _mm_min_ps(tmax0, mul1);
+ const __m128 tmin2 = _mm_max_ps(tmin1, mul2);
+ const __m128 tmax2 = _mm_min_ps(tmax1, mul3);
+ const __m128 tmin3 = _mm_max_ps(tmin2, mul4);
+ const __m128 tmax3 = _mm_min_ps(tmax2, mul5);
+
+ return _mm_movemask_ps(_mm_cmpge_ps(tmax3, tmin3));
+}
+
+static int svbvh_bb_intersect_test(const Isect *isec, const float *_bb)
{
+ const float *bb = _bb;
+
+ float t1x = (bb[isec->bv_index[0]] - isec->start[0]) * isec->idot_axis[0];
+ float t2x = (bb[isec->bv_index[1]] - isec->start[0]) * isec->idot_axis[0];
+ float t1y = (bb[isec->bv_index[2]] - isec->start[1]) * isec->idot_axis[1];
+ float t2y = (bb[isec->bv_index[3]] - isec->start[1]) * isec->idot_axis[1];
+ float t1z = (bb[isec->bv_index[4]] - isec->start[2]) * isec->idot_axis[2];
+ float t2z = (bb[isec->bv_index[5]] - isec->start[2]) * isec->idot_axis[2];
+
+ RE_RC_COUNT(isec->raycounter->bb.test);
+
+ if(t1x > t2y || t2x < t1y || t1x > t2z || t2x < t1z || t1y > t2z || t2y < t1z) return 0;
+ if(t2x < 0.0 || t2y < 0.0 || t2z < 0.0) return 0;
+ if(t1x > isec->dist || t1y > isec->dist || t1z > isec->dist) return 0;
+
+ RE_RC_COUNT(isec->raycounter->bb.hit);
+
return 1;
}
-template<>
-inline void bvh_node_push_childs<SVBVHNode>(SVBVHNode *node, Isect *isec, SVBVHNode **stack, int &stack_pos)
+static bool svbvh_node_is_leaf(const SVBVHNode *node)
{
- int i=0;
- while(i+4 <= node->nchilds)
- {
- int res = test_bb_group4( (__m128*) (node->child_bb+6*i), isec );
- RE_RC_COUNT(isec->raycounter->simd_bb.test);
-
- if(res & 1) { stack[stack_pos++] = node->child[i+0]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- if(res & 2) { stack[stack_pos++] = node->child[i+1]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- if(res & 4) { stack[stack_pos++] = node->child[i+2]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
- if(res & 8) { stack[stack_pos++] = node->child[i+3]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
-
- i += 4;
- }
- while(i < node->nchilds)
+ return !RE_rayobject_isAligned(node);
+}
+
+template<int MAX_STACK_SIZE, bool SHADOW>
+static int svbvh_node_stack_raycast(SVBVHNode *root, Isect *isec)
+{
+ SVBVHNode *stack[MAX_STACK_SIZE], *node;
+ int hit = 0, stack_pos = 0;
+
+ stack[stack_pos++] = root;
+
+ while(stack_pos)
{
- if(RE_rayobject_bb_intersect_test(isec, (const float*)node->child_bb+6*i))
- stack[stack_pos++] = node->child[i];
- i++;
+ node = stack[--stack_pos];
+
+ if(!svbvh_node_is_leaf(node))
+ {
+ int nchilds= node->nchilds;
+
+ if(nchilds == 4) {
+ float *child_bb= node->child_bb;
+ int res = svbvh_bb_intersect_test_simd4(isec, ((__m128*) (child_bb)));
+ SVBVHNode **child= node->child;
+
+ RE_RC_COUNT(isec->raycounter->simd_bb.test);
+
+ if(res & 1) { stack[stack_pos++] = child[0]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
+ if(res & 2) { stack[stack_pos++] = child[1]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
+ if(res & 4) { stack[stack_pos++] = child[2]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
+ if(res & 8) { stack[stack_pos++] = child[3]; RE_RC_COUNT(isec->raycounter->simd_bb.hit); }
+ }
+ else {
+ float *child_bb= node->child_bb;
+ SVBVHNode **child= node->child;
+ int i;
+
+ for(i=0; i<nchilds; i++)
+ if(svbvh_bb_intersect_test(isec, (float*)child_bb+6*i))
+ stack[stack_pos++] = child[i];
+ }
+ }
+ else
+ {
+ hit |= RE_rayobject_intersect((RayObject*)node, isec);
+ if(SHADOW && hit) break;
+ }
}
+
+ return hit;
}
+
template<>
inline void bvh_node_merge_bb<SVBVHNode>(SVBVHNode *node, float *min, float *max)
{
if(is_leaf(node))
{
- RE_rayobject_merge_bb( (RayObject*)node, min, max);
+ RE_rayobject_merge_bb((RayObject*)node, min, max);
}
else
{
@@ -156,15 +233,13 @@ struct Reorganize_SVBVH
{
SVBVHNode *node = (SVBVHNode*)BLI_memarena_alloc(arena, sizeof(SVBVHNode));
node->nchilds = nchilds;
- node->child_bb = (float*)BLI_memarena_alloc(arena, sizeof(float)*6*nchilds);
- node->child= (SVBVHNode**)BLI_memarena_alloc(arena, sizeof(SVBVHNode*)*nchilds);
return node;
}
void copy_bb(float *bb, const float *old_bb)
{
- std::copy( old_bb, old_bb+6, bb );
+ std::copy(old_bb, old_bb+6, bb);
}
void prepare_for_simd(SVBVHNode *node)
@@ -174,7 +249,7 @@ struct Reorganize_SVBVH
{
float vec_tmp[4*6];
float *res = node->child_bb+6*i;
- std::copy( res, res+6*4, vec_tmp);
+ std::copy(res, res+6*4, vec_tmp);
for(int j=0; j<6; j++)
{
@@ -231,7 +306,7 @@ struct Reorganize_SVBVH
{
float bb[6];
INIT_MINMAX(bb, bb+3);
- RE_rayobject_merge_bb( (RayObject*)o_child, bb, bb+3);
+ RE_rayobject_merge_bb((RayObject*)o_child, bb, bb+3);
copy_bb(node->child_bb+i*6, bb);
break;
}
@@ -240,7 +315,7 @@ struct Reorganize_SVBVH
copy_bb(node->child_bb+i*6, o_child->bb);
}
}
- assert( i == 0 );
+ assert(i == 0);
prepare_for_simd(node);
@@ -251,3 +326,4 @@ struct Reorganize_SVBVH
#endif
#endif //__SSE__
+
diff --git a/source/blender/render/intern/raytrace/vbvh.h b/source/blender/render/intern/raytrace/vbvh.h
index a5ca093de2a..06188ede8c6 100644
--- a/source/blender/render/intern/raytrace/vbvh.h
+++ b/source/blender/render/intern/raytrace/vbvh.h
@@ -26,12 +26,13 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-#include <assert.h>
+#include <assert.h>
#include <algorithm>
-#include "rayobject_rtbuild.h"
+
#include "BLI_memarena.h"
-#include "BLI_utildefines.h"
+
+#include "rayobject_rtbuild.h"
/*
* VBVHNode represents a BVHNode with support for a variable number of childrens
@@ -167,12 +168,11 @@ struct BuildBinaryVBVH
Node *node = create_node();
- INIT_MINMAX(node->bb, node->bb+3);
- rtbuild_merge_bb(builder, node->bb, node->bb+3);
-
Node **child = &node->child;
int nc = rtbuild_split(builder);
+ INIT_MINMAX(node->bb, node->bb+3);
+
assert(nc == 2);
for(int i=0; i<nc; i++)
{
@@ -180,6 +180,8 @@ struct BuildBinaryVBVH
rtbuild_get_child(builder, i, &tmp);
*child = _transform(&tmp);
+ DO_MIN((*child)->bb, node->bb);
+ DO_MAX((*child)->bb+3, node->bb+3);
child = &((*child)->sibling);
}
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index f7fecca6a60..14f80986ba3 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -1492,13 +1492,13 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
StrandBound *sbound= 0;
StrandRen *strand=0;
RNG *rng= 0;
- float loc[3],loc1[3],loc0[3],mat[4][4],nmat[3][3],co[3],nor[3];
+ float loc[3],loc1[3],loc0[3],mat[4][4],nmat[3][3],co[3],nor[3],duplimat[4][4];
float strandlen=0.0f, curlen=0.0f;
float hasize, pa_size, r_tilt, r_length;
float pa_time, pa_birthtime, pa_dietime;
float random, simplify[2], pa_co[3];
const float cfra= BKE_curframe(re->scene);
- int i, a, k, max_k=0, totpart, dosimplify = 0, dosurfacecache = 0;
+ int i, a, k, max_k=0, totpart, dosimplify = 0, dosurfacecache = 0, use_duplimat = 0;
int totchild=0;
int seed, path_nbr=0, orco1=0, num;
int totface, *origindex = 0;
@@ -1638,6 +1638,12 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
copy_m3_m4(nmat, ob->imat);
transpose_m3(nmat);
+ if(psys->flag & PSYS_USE_IMAT) {
+ /* psys->imat is the original emitter's inverse matrix, ob->obmat is the duplicated object's matrix */
+ mul_m4_m4m4(duplimat, psys->imat, ob->obmat);
+ use_duplimat = 1;
+ }
+
/* 2.6 setup strand rendering */
if(part->ren_as == PART_DRAW_PATH && psys->pathcache){
path_nbr=(int)pow(2.0,(double) part->ren_step);
@@ -1949,6 +1955,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
if(psys->parent)
mul_m4_v3(psys->parent->obmat, state.co);
+ if(use_duplimat)
+ mul_m4_v4(duplimat, state.co);
+
if(part->ren_as == PART_DRAW_BB) {
bb.random = random;
bb.size = pa_size;
@@ -1971,6 +1980,9 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
if(psys->parent)
mul_m4_v3(psys->parent->obmat, state.co);
+ if(use_duplimat)
+ mul_m4_v4(duplimat, state.co);
+
if(part->ren_as == PART_DRAW_BB) {
bb.random = random;
bb.size = pa_size;
@@ -3940,30 +3952,35 @@ static void set_phong_threshold(ObjectRen *obr)
/* per face check if all samples should be taken.
if raytrace or multisample, do always for raytraced material, or when material full_osa set */
-static void set_fullsample_flag(Render *re, ObjectRen *obr)
+static void set_fullsample_trace_flag(Render *re, ObjectRen *obr)
{
VlakRen *vlr;
- int a, trace, mode;
+ int a, trace, mode, osa;
- if(re->osa==0)
- return;
-
+ osa= re->osa;
trace= re->r.mode & R_RAYTRACE;
for(a=obr->totvlak-1; a>=0; a--) {
vlr= RE_findOrAddVlak(obr, a);
mode= vlr->mat->mode;
+
+ if(trace && (mode & MA_TRACEBLE))
+ vlr->flag |= R_TRACEBLE;
- if(mode & MA_FULL_OSA)
- vlr->flag |= R_FULL_OSA;
- else if(trace) {
- if(mode & MA_SHLESS);
- else if(vlr->mat->material_type == MA_TYPE_VOLUME);
- else if((mode & MA_RAYMIRROR) || ((mode & MA_TRANSP) && (mode & MA_RAYTRANSP)))
- /* for blurry reflect/refract, better to take more samples
- * inside the raytrace than as OSA samples */
- if ((vlr->mat->gloss_mir == 1.0) && (vlr->mat->gloss_tra == 1.0))
- vlr->flag |= R_FULL_OSA;
+ if(osa) {
+ if(mode & MA_FULL_OSA) {
+ vlr->flag |= R_FULL_OSA;
+ }
+ else if(trace) {
+ if(mode & MA_SHLESS);
+ else if(vlr->mat->material_type == MA_TYPE_VOLUME);
+ else if((mode & MA_RAYMIRROR) || ((mode & MA_TRANSP) && (mode & MA_RAYTRANSP))) {
+ /* for blurry reflect/refract, better to take more samples
+ * inside the raytrace than as OSA samples */
+ if ((vlr->mat->gloss_mir == 1.0) && (vlr->mat->gloss_tra == 1.0))
+ vlr->flag |= R_FULL_OSA;
+ }
+ }
}
}
}
@@ -4158,7 +4175,7 @@ static void finalize_render_object(Render *re, ObjectRen *obr, int timeoffset)
check_non_flat_quads(obr);
}
- set_fullsample_flag(re, obr);
+ set_fullsample_trace_flag(re, obr);
/* compute bounding boxes for clipping */
INIT_MINMAX(min, max);
@@ -4340,7 +4357,7 @@ static void init_render_object_data(Render *re, ObjectRen *obr, int timeoffset)
int i;
if(obr->psysindex) {
- if((!obr->prev || obr->prev->ob != ob) && ob->type==OB_MESH) {
+ if((!obr->prev || obr->prev->ob != ob || (obr->prev->flag & R_INSTANCEABLE)==0) && ob->type==OB_MESH) {
/* the emitter mesh wasn't rendered so the modifier stack wasn't
* evaluated with render settings */
DerivedMesh *dm;
@@ -4432,8 +4449,11 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject *
}
if(obr->lay & vectorlay)
obr->flag |= R_NEED_VECTORS;
+ if(dob)
+ psys->flag |= PSYS_USE_IMAT;
init_render_object_data(re, obr, timeoffset);
psys_render_restore(ob, psys);
+ psys->flag &= ~PSYS_USE_IMAT;
/* only add instance for objects that have not been used for dupli */
if(!(ob->transflag & OB_RENDER_DUPLI)) {
@@ -4765,6 +4785,8 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
int psysindex;
float mat[4][4];
+ obi=NULL;
+
/* instances instead of the actual object are added in two cases, either
* this is a duplivert/face/particle, or it is a non-animated object in
* a dupligroup that has already been created before */
@@ -4789,15 +4811,14 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
find_dupli_instances(re, obr);
}
}
- else
- /* can't instance, just create the object */
- init_render_object(re, obd, ob, dob, timeoffset, vectorlay);
/* same logic for particles, each particle system has it's own object, so
* need to go over them separately */
psysindex= 1;
for(psys=obd->particlesystem.first; psys; psys=psys->next) {
- if(dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, ob, psysindex))) {
+ if(dob->type != OB_DUPLIGROUP || (obr=find_dupligroup_dupli(re, obd, psysindex))) {
+ if(obi == NULL)
+ mul_m4_m4m4(mat, dob->mat, re->viewmat);
obi= RE_addRenderInstance(re, NULL, obd, ob, dob->index, psysindex++, mat, obd->lay);
set_dupli_tex_mat(re, obi, dob);
@@ -4813,6 +4834,10 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
}
}
}
+
+ if(obi==NULL)
+ /* can't instance, just create the object */
+ init_render_object(re, obd, ob, dob, timeoffset, vectorlay);
if(dob->type != OB_DUPLIGROUP) {
obd->flag |= OB_DONE;
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 5940a8bf48b..1ec37dd7b1c 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -2423,6 +2423,7 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree)
G.afbreek= 0;
re->main= bmain;
+ re->scene= sce;
/* first call RE_ReadRenderResult on every renderlayer scene. this creates Render structs */
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 1bbf994d505..00092b8b053 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -60,13 +60,13 @@
#include "texture.h"
#include "volumetric.h"
-#include "RE_raytrace.h"
+#include "rayintersection.h"
#include "rayobject.h"
#include "raycounter.h"
#define RAY_TRA 1
-#define RAY_TRAFLIP 2
+#define RAY_INSIDE 2
#define DEPTH_SHADOW_TRA 10
@@ -195,7 +195,7 @@ void freeraytree(Render *re)
static int is_raytraceable_vlr(Render *re, VlakRen *vlr)
{
/* note: volumetric must be tracable, wire must not */
- if((re->flag & R_BAKE_TRACE) || (vlr->mat->mode & MA_TRACEBLE) || (vlr->mat->material_type == MA_TYPE_VOLUME))
+ if((re->flag & R_BAKE_TRACE) || (vlr->flag & R_TRACEBLE) || (vlr->mat->material_type == MA_TYPE_VOLUME))
if(vlr->mat->material_type != MA_TYPE_WIRE)
return 1;
return 0;
@@ -209,12 +209,13 @@ static int is_raytraceable(Render *re, ObjectInstanceRen *obi)
if(re->excludeob && obr->ob == re->excludeob)
return 0;
- for(v=0;v<obr->totvlak;v++)
- {
+ for(v=0;v<obr->totvlak;v++) {
VlakRen *vlr = obr->vlaknodes[v>>8].vlak + (v&255);
+
if(is_raytraceable_vlr(re, vlr))
return 1;
}
+
return 0;
}
@@ -444,11 +445,7 @@ void makeraytree(Render *re)
if(re->r.raytrace_structure == R_RAYSTRUCTURE_OCTREE)
re->r.raytrace_options &= ~( R_RAYTRACE_USE_INSTANCES | R_RAYTRACE_USE_LOCAL_COORDS);
- if(G.f & G_DEBUG) {
- BENCH(makeraytree_single(re), tree_build);
- }
- else
- makeraytree_single(re);
+ makeraytree_single(re);
if(test_break(re))
{
@@ -522,12 +519,12 @@ void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
VlakRen *vlr= (VlakRen*)is->hit.face;
/* set up view vector */
- VECCOPY(shi->view, is->vec);
+ VECCOPY(shi->view, is->dir);
/* render co */
- shi->co[0]= is->start[0]+is->labda*(shi->view[0]);
- shi->co[1]= is->start[1]+is->labda*(shi->view[1]);
- shi->co[2]= is->start[2]+is->labda*(shi->view[2]);
+ shi->co[0]= is->start[0]+is->dist*(shi->view[0]);
+ shi->co[1]= is->start[1]+is->dist*(shi->view[1]);
+ shi->co[2]= is->start[2]+is->dist*(shi->view[2]);
normalize_v3(shi->view);
@@ -537,15 +534,10 @@ void shade_ray(Isect *is, ShadeInput *shi, ShadeResult *shr)
shi->mat= vlr->mat;
shade_input_init_material(shi);
- if(vlr->v4) {
- if(is->isect==2)
- shade_input_set_triangle_i(shi, obi, vlr, 2, 1, 3);
- else
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 3);
- }
- else {
+ if(is->isect==2)
+ shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
+ else
shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
- }
shi->u= is->u;
shi->v= is->v;
@@ -717,15 +709,15 @@ static void ray_fadeout(Isect *is, ShadeInput *shi, float *col, float *blendcol,
/* the main recursive tracer itself
* note: 'col' must be initialized */
-static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, float *start, float *vec, float *col, ObjectInstanceRen *obi, VlakRen *vlr, int traflag)
+static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, float *start, float *dir, float *col, ObjectInstanceRen *obi, VlakRen *vlr, int traflag)
{
ShadeInput shi= {0};
Isect isec;
float dist_mir = origshi->mat->dist_mir;
VECCOPY(isec.start, start);
- VECCOPY(isec.vec, vec );
- isec.labda = dist_mir > 0 ? dist_mir : RE_RAYTRACE_MAXDIST;
+ VECCOPY(isec.dir, dir );
+ isec.dist = dist_mir > 0 ? dist_mir : RE_RAYTRACE_MAXDIST;
isec.mode= RE_RAY_MIRROR;
isec.check = RE_CHECK_VLR_RENDER;
isec.skip = RE_SKIP_VLR_NEIGHBOUR;
@@ -758,7 +750,8 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo
shi.mat_override= origshi->mat_override;
shade_ray(&isec, &shi, &shr);
- if (traflag & RAY_TRA)
+ /* ray has traveled inside the material, so shade by transmission */
+ if (traflag & RAY_INSIDE)
d= shade_by_transmission(&isec, &shi, &shr);
if(depth>0) {
@@ -773,21 +766,33 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo
tracol[3]= col[3]; // we pass on and accumulate alpha
if((shi.mat->mode & MA_TRANSP) && (shi.mat->mode & MA_RAYTRANSP)) {
- /* odd depths: use normal facing viewer, otherwise flip */
- if(traflag & RAY_TRAFLIP) {
+ if(traflag & RAY_INSIDE) {
+ /* inside the material, so use inverse normal */
float norm[3];
norm[0]= - shi.vn[0];
norm[1]= - shi.vn[1];
norm[2]= - shi.vn[2];
- if (!refraction(refract, norm, shi.view, shi.ang))
+
+ if (refraction(refract, norm, shi.view, shi.ang)) {
+ /* ray comes out from the material into air */
+ traflag &= ~RAY_INSIDE;
+ }
+ else {
+ /* total internal reflection (ray stays inside the material) */
reflection(refract, norm, shi.view, shi.vn);
+ }
}
else {
- if (!refraction(refract, shi.vn, shi.view, shi.ang))
+ if (refraction(refract, shi.vn, shi.view, shi.ang)) {
+ /* ray goes in to the material from air */
+ traflag |= RAY_INSIDE;
+ }
+ else {
+ /* total external reflection (ray doesn't enter the material) */
reflection(refract, shi.vn, shi.view, shi.vn);
+ }
}
- traflag |= RAY_TRA;
- traceray(origshi, origshr, depth-1, shi.co, refract, tracol, shi.obi, shi.vlr, traflag ^ RAY_TRAFLIP);
+ traceray(origshi, origshr, depth-1, shi.co, refract, tracol, shi.obi, shi.vlr, traflag);
}
else
traceray(origshi, origshr, depth-1, shi.co, shi.view, tracol, shi.obi, shi.vlr, 0);
@@ -850,7 +855,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo
/* max ray distance set, but found an intersection, so fade this color
* out towards the sky/material color for a smooth transition */
- ray_fadeout_endcolor(blendcol, origshi, &shi, origshr, &isec, vec);
+ ray_fadeout_endcolor(blendcol, origshi, &shi, origshr, &isec, dir);
ray_fadeout(&isec, &shi, col, blendcol, dist_mir);
}
}
@@ -862,7 +867,7 @@ static void traceray(ShadeInput *origshi, ShadeResult *origshr, short depth, flo
}
else {
- ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, vec);
+ ray_fadeout_endcolor(col, origshi, &shi, origshr, &isec, dir);
}
RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
}
@@ -1285,6 +1290,7 @@ static void trace_refract(float *col, ShadeInput *shi, ShadeResult *shr)
{
QMCSampler *qsa=NULL;
int samp_type;
+ int traflag=0;
float samp3d[3], orthx[3], orthy[3];
float v_refract[3], v_refract_new[3];
@@ -1312,7 +1318,18 @@ static void trace_refract(float *col, ShadeInput *shi, ShadeResult *shr)
while (samples < max_samples) {
- refraction(v_refract, shi->vn, shi->view, shi->ang);
+ if(refraction(v_refract, shi->vn, shi->view, shi->ang)) {
+ traflag |= RAY_INSIDE;
+ } else {
+ /* total external reflection can happen for materials with IOR < 1.0 */
+ if((shi->vlr->flag & R_SMOOTH))
+ reflection(v_refract, shi->vn, shi->view, shi->facenor);
+ else
+ reflection(v_refract, shi->vn, shi->view, NULL);
+
+ /* can't blur total external reflection */
+ max_samples = 1;
+ }
if (max_samples > 1) {
/* get a quasi-random vector from a phong-weighted disc */
@@ -1334,7 +1351,7 @@ static void trace_refract(float *col, ShadeInput *shi, ShadeResult *shr)
sampcol[0]= sampcol[1]= sampcol[2]= sampcol[3]= 0.0f;
- traceray(shi, shr, shi->mat->ray_depth_tra, shi->co, v_refract_new, sampcol, shi->obi, shi->vlr, RAY_TRA|RAY_TRAFLIP);
+ traceray(shi, shr, shi->mat->ray_depth_tra, shi->co, v_refract_new, sampcol, shi->obi, shi->vlr, traflag);
col[0] += sampcol[0];
col[1] += sampcol[1];
@@ -1580,13 +1597,13 @@ static void addAlphaLight(float *shadfac, float *col, float alpha, float filter)
shadfac[3]= (1.0f-alpha)*shadfac[3];
}
-static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int traflag)
+static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int traflag, float col[4])
{
/* ray to lamp, find first face that intersects, check alpha properties,
if it has col[3]>0.0f continue. so exit when alpha is full */
ShadeInput shi;
ShadeResult shr;
- float initial_labda = is->labda;
+ float initial_dist = is->dist;
if(RE_rayobject_raycast(R.raytree, is)) {
float d= 1.0f;
@@ -1614,26 +1631,26 @@ static void ray_trace_shadow_tra(Isect *is, ShadeInput *origshi, int depth, int
d= shade_by_transmission(is, &shi, &shr);
/* mix colors based on shadfac (rgb + amount of light factor) */
- addAlphaLight(is->col, shr.diff, shr.alpha, d*shi.mat->filter);
+ addAlphaLight(col, shr.diff, shr.alpha, d*shi.mat->filter);
} else if (shi.mat->material_type == MA_TYPE_VOLUME) {
- const float a = is->col[3];
+ const float a = col[3];
- is->col[0] = a*is->col[0] + shr.alpha*shr.combined[0];
- is->col[1] = a*is->col[1] + shr.alpha*shr.combined[1];
- is->col[2] = a*is->col[2] + shr.alpha*shr.combined[2];
+ col[0] = a*col[0] + shr.alpha*shr.combined[0];
+ col[1] = a*col[1] + shr.alpha*shr.combined[1];
+ col[2] = a*col[2] + shr.alpha*shr.combined[2];
- is->col[3] = (1.0 - shr.alpha)*a;
+ col[3] = (1.0 - shr.alpha)*a;
}
- if(depth>0 && is->col[3]>0.0f) {
+ if(depth>0 && col[3]>0.0f) {
/* adapt isect struct */
VECCOPY(is->start, shi.co);
- is->labda = initial_labda-is->labda;
+ is->dist = initial_dist-is->dist;
is->orig.ob = shi.obi;
is->orig.face = shi.vlr;
- ray_trace_shadow_tra(is, origshi, depth-1, traflag | RAY_TRA);
+ ray_trace_shadow_tra(is, origshi, depth-1, traflag | RAY_TRA, col);
}
RE_RC_MERGE(&origshi->raycounter, &shi.raycounter);
@@ -1680,8 +1697,8 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr)
vec[2]-= vec[2];
}
- VECCOPY(isec.vec, vec );
- isec.labda = RE_RAYTRACE_MAXDIST;
+ VECCOPY(isec.dir, vec );
+ isec.dist = RE_RAYTRACE_MAXDIST;
if(RE_rayobject_raycast(R.raytree, &isec)) {
float fac;
@@ -1692,7 +1709,7 @@ int ray_trace_shadow_rad(ShadeInput *ship, ShadeResult *shr)
/* end warning! - Campbell */
shade_ray(&isec, &shi, &shr_t);
- fac= isec.labda*isec.labda;
+ fac= isec.dist*isec.dist;
fac= 1.0f;
accum[0]+= fac*(shr_t.diff[0]+shr_t.spec[0]);
accum[1]+= fac*(shr_t.diff[1]+shr_t.spec[1]);
@@ -1911,7 +1928,7 @@ static void ray_ao_qmc(ShadeInput *shi, float *ao, float *env)
else {
VECCOPY(nrm, shi->facenor);
}
-
+
ortho_basis_v3v3_v3( up, side,nrm);
/* sampling init */
@@ -1929,7 +1946,6 @@ static void ray_ao_qmc(ShadeInput *shi, float *ao, float *env)
QMC_initPixel(qsa, shi->thread);
-
while (samples < max_samples) {
/* sampling, returns quasi-random vector in unit hemisphere */
@@ -1941,15 +1957,15 @@ static void ray_ao_qmc(ShadeInput *shi, float *ao, float *env)
normalize_v3(dir);
- isec.vec[0] = -dir[0];
- isec.vec[1] = -dir[1];
- isec.vec[2] = -dir[2];
- isec.labda = maxdist;
+ isec.dir[0] = -dir[0];
+ isec.dir[1] = -dir[1];
+ isec.dir[2] = -dir[2];
+ isec.dist = maxdist;
prev = fac;
if(RE_rayobject_raycast(R.raytree, &isec)) {
- if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.labda*R.wrld.aodistfac);
+ if (R.wrld.aomode & WO_AODIST) fac+= exp(-isec.dist*R.wrld.aodistfac);
else fac+= 1.0f;
}
else if(envcolor!=WO_AOPLAIN) {
@@ -2077,15 +2093,15 @@ static void ray_ao_spheresamp(ShadeInput *shi, float *ao, float *env)
actual++;
- /* always set start/vec/labda */
- isec.vec[0] = -vec[0];
- isec.vec[1] = -vec[1];
- isec.vec[2] = -vec[2];
- isec.labda = maxdist;
+ /* always set start/vec/dist */
+ isec.dir[0] = -vec[0];
+ isec.dir[1] = -vec[1];
+ isec.dir[2] = -vec[2];
+ isec.dist = maxdist;
/* do the trace */
if(RE_rayobject_raycast(R.raytree, &isec)) {
- if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.labda*R.wrld.aodistfac);
+ if (R.wrld.aomode & WO_AODIST) sh+= exp(-isec.dist*R.wrld.aodistfac);
else sh+= 1.0f;
}
else if(envcolor!=WO_AOPLAIN) {
@@ -2300,26 +2316,25 @@ static void ray_shadow_qmc(ShadeInput *shi, LampRen *lar, float *lampco, float *
}
VECCOPY(isec->start, co);
- isec->vec[0] = end[0]-isec->start[0];
- isec->vec[1] = end[1]-isec->start[1];
- isec->vec[2] = end[2]-isec->start[2];
- isec->labda = 1.0f; // * normalize_v3(isec->vec);
+ isec->dir[0] = end[0]-isec->start[0];
+ isec->dir[1] = end[1]-isec->start[1];
+ isec->dir[2] = end[2]-isec->start[2];
+ isec->dist = normalize_v3(isec->dir);
/* trace the ray */
if(isec->mode==RE_RAY_SHADOW_TRA) {
- isec->col[0]= isec->col[1]= isec->col[2]= 1.0f;
- isec->col[3]= 1.0f;
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0);
- shadfac[0] += isec->col[0];
- shadfac[1] += isec->col[1];
- shadfac[2] += isec->col[2];
- shadfac[3] += isec->col[3];
+ ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col);
+ shadfac[0] += col[0];
+ shadfac[1] += col[1];
+ shadfac[2] += col[2];
+ shadfac[3] += col[3];
/* for variance calc */
- colsq[0] += isec->col[0]*isec->col[0];
- colsq[1] += isec->col[1]*isec->col[1];
- colsq[2] += isec->col[2]*isec->col[2];
+ colsq[0] += col[0]*col[0];
+ colsq[1] += col[1]*col[1];
+ colsq[2] += col[2]*col[2];
}
else {
if( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
@@ -2402,23 +2417,22 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, float *lampco, floa
mul_m3_v3(lar->mat, vec);
/* set start and vec */
- isec->vec[0] = vec[0]+lampco[0]-isec->start[0];
- isec->vec[1] = vec[1]+lampco[1]-isec->start[1];
- isec->vec[2] = vec[2]+lampco[2]-isec->start[2];
- isec->labda = 1.0f;
+ isec->dir[0] = vec[0]+lampco[0]-isec->start[0];
+ isec->dir[1] = vec[1]+lampco[1]-isec->start[1];
+ isec->dir[2] = vec[2]+lampco[2]-isec->start[2];
+ isec->dist = 1.0f;
isec->check = RE_CHECK_VLR_RENDER;
isec->skip = RE_SKIP_VLR_NEIGHBOUR;
if(isec->mode==RE_RAY_SHADOW_TRA) {
/* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
- isec->col[0]= isec->col[1]= isec->col[2]= 1.0f;
- isec->col[3]= 1.0f;
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0);
- shadfac[0] += isec->col[0];
- shadfac[1] += isec->col[1];
- shadfac[2] += isec->col[2];
- shadfac[3] += isec->col[3];
+ ray_trace_shadow_tra(isec, shi, DEPTH_SHADOW_TRA, 0, col);
+ shadfac[0] += col[0];
+ shadfac[1] += col[1];
+ shadfac[2] += col[2];
+ shadfac[3] += col[3];
}
else if( RE_rayobject_raycast(R.raytree, isec) ) fac+= 1.0f;
@@ -2499,18 +2513,17 @@ void ray_shadow(ShadeInput *shi, LampRen *lar, float *shadfac)
shadfac[3]= 1.0f; // 1.0=full light
- /* set up isec vec */
+ /* set up isec.dir */
VECCOPY(isec.start, shi->co);
- VECSUB(isec.vec, lampco, isec.start);
- isec.labda = 1.0f;
+ VECSUB(isec.dir, lampco, isec.start);
+ isec.dist = normalize_v3(isec.dir);
if(isec.mode==RE_RAY_SHADOW_TRA) {
/* isec.col is like shadfac, so defines amount of light (0.0 is full shadow) */
- isec.col[0]= isec.col[1]= isec.col[2]= 1.0f;
- isec.col[3]= 1.0f;
+ float col[4] = {1.0f, 1.0f, 1.0f, 1.0f};
- ray_trace_shadow_tra(&isec, shi, DEPTH_SHADOW_TRA, 0);
- QUATCOPY(shadfac, isec.col);
+ ray_trace_shadow_tra(&isec, shi, DEPTH_SHADOW_TRA, 0, col);
+ QUATCOPY(shadfac, col);
}
else if(RE_rayobject_raycast(R.raytree, &isec))
shadfac[3]= 0.0f;
@@ -2555,7 +2568,7 @@ static void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float
isec.orig.ob = shi->obi;
isec.orig.face = shi->vlr;
- /* set up isec vec */
+ /* set up isec.dir */
VECCOPY(isec.start, shi->co);
VECCOPY(isec.end, lampco);
@@ -2563,11 +2576,11 @@ static void ray_translucent(ShadeInput *shi, LampRen *lar, float *distfac, float
/* we got a face */
/* render co */
- co[0]= isec.start[0]+isec.labda*(isec.vec[0]);
- co[1]= isec.start[1]+isec.labda*(isec.vec[1]);
- co[2]= isec.start[2]+isec.labda*(isec.vec[2]);
+ co[0]= isec.start[0]+isec.dist*(isec.dir[0]);
+ co[1]= isec.start[1]+isec.dist*(isec.dir[1]);
+ co[2]= isec.start[2]+isec.dist*(isec.dir[2]);
- *distfac= len_v3(isec.vec);
+ *distfac= len_v3(isec.dir);
}
else
*distfac= 0.0f;
diff --git a/source/blender/render/intern/source/texture.c b/source/blender/render/intern/source/render_texture.c
index a7a6727c508..a62c4bd8e74 100644
--- a/source/blender/render/intern/source/texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -1607,7 +1607,6 @@ static void texco_mapping(ShadeInput* shi, Tex* tex, MTex* mtex, float* co, floa
do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
// translate and scale
- /*
texvec[0] = mtex->size[0]*(texvec[0] - 0.5f) + mtex->ofs[0] + 0.5f;
texvec[1] = mtex->size[1]*(texvec[1] - 0.5f) + mtex->ofs[1] + 0.5f;
if (shi->osatex) {
@@ -1616,7 +1615,6 @@ static void texco_mapping(ShadeInput* shi, Tex* tex, MTex* mtex, float* co, floa
dyt[0] = mtex->size[0]*dyt[0];
dyt[1] = mtex->size[1]*dyt[1];
}
- */
/* problem: repeat-mirror is not a 'repeat' but 'extend' in imagetexture.c */
// TXF: bug was here, only modify texvec when repeat mode set, old code affected other modes too.
@@ -2115,7 +2113,8 @@ void do_material_tex(ShadeInput *shi)
use_ntap_bump= (mtex->texflag & (MTEX_3TAP_BUMP|MTEX_5TAP_BUMP));
/* XXX texture node trees don't work for this yet */
- if(tex->nodetree && tex->use_nodes) {
+ /* it also needs derivatives */
+ if((tex->nodetree && tex->use_nodes) || shi->osatex==0) {
use_compat_bump = 0;
use_ntap_bump = 0;
}
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index d955043b1f1..fac2e39c89a 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -61,6 +61,8 @@
#include "IMB_imbuf.h"
/* local include */
+#include "rayintersection.h"
+#include "rayobject.h"
#include "renderpipeline.h"
#include "render_types.h"
#include "renderdatabase.h"
@@ -71,7 +73,6 @@
#include "shading.h"
#include "sss.h"
#include "zbuf.h"
-#include "RE_raytrace.h"
#include "PIL_time.h"
@@ -2081,24 +2082,10 @@ static void bake_mask_clear( ImBuf *ibuf, char *mask, char val )
static void bake_set_shade_input(ObjectInstanceRen *obi, VlakRen *vlr, ShadeInput *shi, int quad, int isect, int x, int y, float u, float v)
{
- if(isect) {
- /* raytrace intersection with different u,v than scanconvert */
- if(vlr->v4) {
- if(quad)
- shade_input_set_triangle_i(shi, obi, vlr, 2, 1, 3);
- else
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 3);
- }
- else
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
- }
- else {
- /* regular scanconvert */
- if(quad)
- shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
- else
- shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
- }
+ if(quad)
+ shade_input_set_triangle_i(shi, obi, vlr, 0, 2, 3);
+ else
+ shade_input_set_triangle_i(shi, obi, vlr, 0, 1, 2);
/* cache for shadow */
shi->samplenr= R.shadowsamplenr[shi->thread]++;
@@ -2287,19 +2274,19 @@ static int bake_intersect_tree(RayObject* raytree, Isect* isect, float *start, f
/* 'dir' is always normalized */
VECADDFAC(isect->start, start, dir, -R.r.bake_biasdist);
- isect->vec[0] = dir[0]*maxdist*sign;
- isect->vec[1] = dir[1]*maxdist*sign;
- isect->vec[2] = dir[2]*maxdist*sign;
+ isect->dir[0] = dir[0]*sign;
+ isect->dir[1] = dir[1]*sign;
+ isect->dir[2] = dir[2]*sign;
- isect->labda = maxdist;
+ isect->dist = maxdist;
hit = RE_rayobject_raycast(raytree, isect);
if(hit) {
- hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
- hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
- hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
+ hitco[0] = isect->start[0] + isect->dist*isect->dir[0];
+ hitco[1] = isect->start[1] + isect->dist*isect->dir[1];
+ hitco[2] = isect->start[2] + isect->dist*isect->dir[2];
- *dist= len_v3v3(start, hitco);
+ *dist= isect->dist;
}
return hit;
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index b917c1ddc92..c1a3b989c1f 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -76,8 +76,8 @@
#include "BKE_DerivedMesh.h"
#include "RE_render_ext.h" /* externtex */
-#include "RE_raytrace.h"
+#include "rayobject.h"
#include "renderpipeline.h"
#include "render_types.h"
#include "renderdatabase.h"
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 14af838d826..cd21ab44142 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -154,8 +154,8 @@ float mistfactor(float zcor, float *co)
static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
{
double a, b, c, disc, nray[3], npos[3];
- float t0, t1 = 0.0f, t2= 0.0f, t3, haint;
- float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f;
+ double t0, t1 = 0.0f, t2= 0.0f, t3;
+ float p1[3], p2[3], ladist, maxz = 0.0f, maxy = 0.0f, haint;
int snijp, doclip=1, use_yco=0;
int ok1=0, ok2=0;
@@ -202,7 +202,7 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
maxz*= lar->sh_zfac;
maxy= lar->imat[0][1]*p1[0]+lar->imat[1][1]*p1[1]+lar->imat[2][1]*p1[2];
- if( fabs(nray[2]) < DBL_EPSILON ) use_yco= 1;
+ if( fabs(nray[2]) < FLT_EPSILON ) use_yco= 1;
}
/* scale z to make sure volume is normalized */
diff --git a/source/blender/render/intern/source/volume_precache.c b/source/blender/render/intern/source/volume_precache.c
index 2813df3744f..609e647637f 100644
--- a/source/blender/render/intern/source/volume_precache.c
+++ b/source/blender/render/intern/source/volume_precache.c
@@ -42,10 +42,11 @@
#include "PIL_time.h"
#include "RE_shader_ext.h"
-#include "RE_raytrace.h"
#include "DNA_material_types.h"
+#include "rayintersection.h"
+#include "rayobject.h"
#include "render_types.h"
#include "rendercore.h"
#include "renderdatabase.h"
@@ -74,11 +75,11 @@ int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int l
if (RE_rayobject_raycast(tree, isect)) {
- isect->start[0] = isect->start[0] + isect->labda*isect->vec[0];
- isect->start[1] = isect->start[1] + isect->labda*isect->vec[1];
- isect->start[2] = isect->start[2] + isect->labda*isect->vec[2];
+ isect->start[0] = isect->start[0] + isect->dist*isect->dir[0];
+ isect->start[1] = isect->start[1] + isect->dist*isect->dir[1];
+ isect->start[2] = isect->start[2] + isect->dist*isect->dir[2];
- isect->labda = FLT_MAX;
+ isect->dist = FLT_MAX;
isect->skip = RE_SKIP_VLR_NEIGHBOUR;
isect->orig.face= isect->hit.face;
isect->orig.ob= isect->hit.ob;
@@ -93,21 +94,21 @@ int intersect_outside_volume(RayObject *tree, Isect *isect, float *offset, int l
int point_inside_obi(RayObject *tree, ObjectInstanceRen *UNUSED(obi), float *co)
{
Isect isect= {{0}};
- float vec[3] = {0.0f,0.0f,1.0f};
+ float dir[3] = {0.0f,0.0f,1.0f};
int final_depth=0, depth=0, limit=20;
/* set up the isect */
VECCOPY(isect.start, co);
- VECCOPY(isect.vec, vec);
+ VECCOPY(isect.dir, dir);
isect.mode= RE_RAY_MIRROR;
isect.last_hit= NULL;
isect.lay= -1;
- isect.labda = FLT_MAX;
+ isect.dist = FLT_MAX;
isect.orig.face= NULL;
isect.orig.ob = NULL;
- final_depth = intersect_outside_volume(tree, &isect, vec, limit, depth);
+ final_depth = intersect_outside_volume(tree, &isect, dir, limit, depth);
/* even number of intersections: point is outside
* odd number: point is inside */
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
index b0aca038e72..dc016a161b5 100644
--- a/source/blender/render/intern/source/volumetric.c
+++ b/source/blender/render/intern/source/volumetric.c
@@ -40,7 +40,6 @@
#include "BLI_utildefines.h"
#include "RE_shader_ext.h"
-#include "RE_raytrace.h"
#include "DNA_material_types.h"
#include "DNA_group_types.h"
@@ -51,6 +50,8 @@
#include "render_types.h"
#include "pixelshading.h"
+#include "rayintersection.h"
+#include "rayobject.h"
#include "shading.h"
#include "shadbuf.h"
#include "texture.h"
@@ -84,13 +85,13 @@ static float vol_get_shadow(ShadeInput *shi, LampRen *lar, float *co)
copy_v3_v3(is.start, co);
if(lar->type==LA_SUN || lar->type==LA_HEMI) {
- is.vec[0] = -lar->vec[0];
- is.vec[1] = -lar->vec[1];
- is.vec[2] = -lar->vec[2];
- is.labda = R.maxdist;
+ is.dir[0] = -lar->vec[0];
+ is.dir[1] = -lar->vec[1];
+ is.dir[2] = -lar->vec[2];
+ is.dist = R.maxdist;
} else {
- VECSUB( is.vec, lar->co, is.start );
- is.labda = len_v3( is.vec );
+ VECSUB( is.dir, lar->co, is.start );
+ is.dist = normalize_v3( is.dir );
}
is.mode = RE_RAY_MIRROR;
@@ -119,8 +120,8 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco,
{
VECCOPY(isect->start, co);
- VECCOPY(isect->vec, vec );
- isect->labda = FLT_MAX;
+ VECCOPY(isect->dir, vec );
+ isect->dist = FLT_MAX;
isect->mode= RE_RAY_MIRROR;
isect->last_hit = NULL;
isect->lay= -1;
@@ -138,9 +139,9 @@ static int vol_get_bounds(ShadeInput *shi, float *co, float *vec, float *hitco,
if(RE_rayobject_raycast(R.raytree, isect))
{
- hitco[0] = isect->start[0] + isect->labda*isect->vec[0];
- hitco[1] = isect->start[1] + isect->labda*isect->vec[1];
- hitco[2] = isect->start[2] + isect->labda*isect->vec[2];
+ hitco[0] = isect->start[0] + isect->dist*isect->dir[0];
+ hitco[1] = isect->start[1] + isect->dist*isect->dir[1];
+ hitco[2] = isect->start[2] + isect->dist*isect->dir[2];
return 1;
} else {
return 0;
@@ -185,8 +186,8 @@ static void vol_trace_behind(ShadeInput *shi, VlakRen *vlr, float *co, float *co
Isect isect;
VECCOPY(isect.start, co);
- VECCOPY(isect.vec, shi->view);
- isect.labda = FLT_MAX;
+ VECCOPY(isect.dir, shi->view);
+ isect.dist = FLT_MAX;
isect.mode= RE_RAY_MIRROR;
isect.check = RE_CHECK_VLR_NONE;
@@ -772,7 +773,7 @@ void shade_volume_shadow(struct ShadeInput *shi, struct ShadeResult *shr, struct
/* due to idiosyncracy in ray_trace_shadow_tra() */
if (is.hit.ob == shi->obi) {
copy_v3_v3(shi->co, hitco);
- last_is->labda -= is.labda;
+ last_is->dist -= is.dist;
shi->vlr = (VlakRen *)is.hit.face;
}
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 80b88309883..644320b0566 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -429,9 +429,13 @@ int WM_read_homefile(bContext *C, ReportList *reports, short from_memory)
BPY_modules_load_user(C);
}
#endif
-
+
WM_event_add_notifier(C, NC_WM|ND_FILEREAD, NULL);
- CTX_wm_window_set(C, NULL); /* exits queues */
+
+ /* in background mode the scene will stay NULL */
+ if(!G.background) {
+ CTX_wm_window_set(C, NULL); /* exits queues */
+ }
return TRUE;
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index 5aa2f6c1c50..36e770db91a 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1350,7 +1350,7 @@ static void WM_OT_read_homefile(wmOperatorType *ot)
ot->invoke= WM_operator_confirm;
ot->exec= WM_read_homefile_exec;
- ot->poll= WM_operator_winactive;
+ /* ommit poll to run in background mode */
}
static void WM_OT_read_factory_settings(wmOperatorType *ot)
@@ -1361,7 +1361,7 @@ static void WM_OT_read_factory_settings(wmOperatorType *ot)
ot->invoke= WM_operator_confirm;
ot->exec= WM_read_homefile_exec;
- ot->poll= WM_operator_winactive;
+ /* ommit poll to run in background mode */
}
/* *************** open file **************** */
@@ -1721,7 +1721,14 @@ static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *UNUS
save_set_compress(op);
- BLI_strncpy(name, G.main->name, FILE_MAX);
+ /* if not saved before, get the name of the most recently used .blend file */
+ if(G.main->name[0]==0 && G.recent_files.first) {
+ struct RecentFile *recent = G.recent_files.first;
+ BLI_strncpy(name, recent->filepath, FILE_MAX);
+ }
+ else
+ BLI_strncpy(name, G.main->name, FILE_MAX);
+
untitled(name);
RNA_string_set(op->ptr, "filepath", name);
@@ -1786,8 +1793,8 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot)
ot->invoke= wm_save_as_mainfile_invoke;
ot->exec= wm_save_as_mainfile_exec;
ot->check= blend_save_check;
- ot->poll= WM_operator_winactive;
-
+ /* ommit window poll so this can work in background mode */
+
WM_operator_properties_filesel(ot, FOLDERFILE|BLENDERFILE, FILE_BLENDER, FILE_SAVE, WM_FILESEL_FILEPATH);
RNA_def_boolean(ot->srna, "compress", 0, "Compress", "Write compressed .blend file");
RNA_def_boolean(ot->srna, "relative_remap", 1, "Remap Relative", "Remap relative paths when saving in a different directory");
@@ -1806,9 +1813,17 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(
return OPERATOR_CANCELLED;
save_set_compress(op);
-
- BLI_strncpy(name, G.main->name, FILE_MAX);
+
+ /* if not saved before, get the name of the most recently used .blend file */
+ if(G.main->name[0]==0 && G.recent_files.first) {
+ struct RecentFile *recent = G.recent_files.first;
+ BLI_strncpy(name, recent->filepath, FILE_MAX);
+ }
+ else
+ BLI_strncpy(name, G.main->name, FILE_MAX);
+
untitled(name);
+
RNA_string_set(op->ptr, "filepath", name);
if (RNA_struct_find_property(op->ptr, "check_existing"))
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 5fd58128f6a..c831c2a477e 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -431,6 +431,7 @@ float sculpt_get_brush_unprojected_radius(struct Brush *brush){return 0.0f;}
void sculpt_set_brush_unprojected_radius(struct Brush *brush, float unprojected_radius){}
float sculpt_get_brush_alpha(struct Brush *brush){return 0.0f;}
void sculpt_set_brush_alpha(struct Brush *brush, float alpha){}
+void ED_sculpt_modifiers_changed(struct Object *ob){};
char blender_path[] = "";
diff --git a/source/tests/batch_import.py b/source/tests/batch_import.py
new file mode 100644
index 00000000000..29b6bb8b9aa
--- /dev/null
+++ b/source/tests/batch_import.py
@@ -0,0 +1,177 @@
+# ##### 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>
+
+"""
+Example Usage:
+
+./blender.bin --background --python source/tests/batch_import.py -- \
+ --operator="bpy.ops.import_scene.obj" \
+ --path="/fe/obj" \
+ --match="*.obj" \
+ --start=0 --end=10 \
+ --save_path=/tmp/test
+
+./blender.bin --background --python source/tests/batch_import.py -- \
+ --operator="bpy.ops.import_scene.autodesk_3ds" \
+ --path="/fe/" \
+ --match="*.3ds" \
+ --start=0 --end=1000 \
+ --save_path=/tmp/test
+"""
+
+import os
+import sys
+
+def clear_scene():
+ import bpy
+ unique_obs = set()
+ for scene in bpy.data.scenes:
+ for obj in scene.objects[:]:
+ scene.objects.unlink(obj)
+ unique_obs.add(obj)
+
+ # remove obdata, for now only worry about the startup scene
+ for bpy_data_iter in (bpy.data.objects, bpy.data.meshes, bpy.data.lamps, bpy.data.cameras):
+ for id_data in bpy_data_iter:
+ bpy_data_iter.remove(id_data)
+
+
+def batch_import(operator="",
+ path="",
+ save_path="",
+ match="",
+ start=0,
+ end=sys.maxsize,
+ ):
+
+ print(list(globals().keys()))
+ import fnmatch
+
+ path = os.path.normpath(path)
+ path = os.path.abspath(path)
+
+ match_upper = match.upper()
+ pattern_match = lambda a: fnmatch.fnmatchcase(a.upper(), match_upper)
+
+ def file_generator(path):
+ for dirpath, dirnames, filenames in os.walk(path):
+
+ # skip '.svn'
+ if dirpath.startswith("."):
+ continue
+
+ for filename in filenames:
+ if pattern_match(filename):
+ yield os.path.join(dirpath, filename)
+
+ print("Collecting %r files in %s" % (match, path), end="")
+
+ files = list(file_generator(path))
+ files_len = len(files)
+ end = min(end, len(files))
+ print(" found %d" % files_len, end="")
+
+ files.sort()
+ files = files[start:end]
+ if len(files) != files_len:
+ print(" using a subset in (%d, %d), total %d" % (start, end, len(files)), end="")
+
+ print("")
+
+ import bpy
+ op = eval(operator)
+ for i, f in enumerate(files):
+ print(" %s(filepath=%r) # %d of %d" % (operator, f, i + start, len(files)))
+ bpy.ops.wm.read_factory_settings()
+ clear_scene()
+
+ op(filepath=f)
+
+ if save_path:
+ fout = os.path.join(save_path, os.path.relpath(f, path))
+ fout_blend = os.path.splitext(fout)[0] + ".blend"
+
+ print("\tSaving: %r" % fout_blend)
+
+ fout_dir = os.path.dirname(fout_blend)
+ if not os.path.exists(fout_dir):
+ os.makedirs(fout_dir)
+
+ bpy.ops.wm.save_as_mainfile(filepath=fout_blend)
+
+
+def main():
+ import optparse
+
+ # 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("-o", "--operator", dest="operator", help="This text will be used to render an image", type="string")
+ parser.add_option("-p", "--path", dest="path", help="Path to use for searching for files", type='string')
+ parser.add_option("-m", "--match", dest="match", help="Wildcard to match filename", type="string")
+ parser.add_option("-s", "--save_path", dest="save_path", help="Save the input file to a blend file in a new location", metavar='string')
+ parser.add_option("-S", "--start", dest="start", help="From collected files, start with this index", metavar='int')
+ parser.add_option("-E", "--end", dest="end", help="From collected files, end with this index", metavar='int')
+
+ options, args = parser.parse_args(argv) # In this example we wont use the args
+
+ if not argv:
+ parser.print_help()
+ return
+
+ if not options.operator:
+ print("Error: --operator=\"some string\" argument not given, aborting.")
+ parser.print_help()
+ return
+
+ if options.start is None:
+ options.start = 0
+
+ if options.end is None:
+ options.end = sys.maxsize
+
+ # Run the example function
+ batch_import(operator=options.operator,
+ path=options.path,
+ save_path=options.save_path,
+ match=options.match,
+ start=int(options.start),
+ end=int(options.end),
+ )
+
+ print("batch job finished, exiting")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/source/tests/pep8.py b/source/tests/pep8.py
index 2932d55d815..ee71c877533 100644
--- a/source/tests/pep8.py
+++ b/source/tests/pep8.py
@@ -50,6 +50,12 @@ def is_pep8(path):
print(path)
if open(path, 'rb').read(3) == b'\xef\xbb\xbf':
print("\nfile contains BOM, remove first 3 bytes: %r\n" % path)
+
+ # templates dont have a header but should be pep8
+ for d in ("presets", "templates", "examples"):
+ if ("%s%s%s" % (os.sep, d, os.sep)) in path:
+ return 1
+
f = open(path, 'r', encoding="utf8")
for i in range(PEP8_SEEK_COMMENT):
line = f.readline()