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:
authorJulian Eisel <eiseljulian@gmail.com>2016-09-08 13:16:41 +0300
committerJulian Eisel <eiseljulian@gmail.com>2016-09-08 13:16:41 +0300
commit788c75ed879fb25a35c0a0e9245df7aeaae2f4ab (patch)
tree3b1c315078e257e0401904860f9ec90fe60390ee
parent1ffd9714b930dbef8059403d69650476f625f554 (diff)
parent45f833c21dcfad4d1d7045987bb8b69d6aab05be (diff)
Merge branch 'master' into viewport_bvh_selectviewport_bvh_select
-rw-r--r--CMakeLists.txt11
-rw-r--r--build_files/cmake/macros.cmake23
-rw-r--r--build_files/cmake/packaging.cmake6
-rw-r--r--build_files/cmake/platform/platform_unix.cmake3
-rw-r--r--build_files/cmake/platform/platform_win32_msvc.cmake12
-rw-r--r--doc/doxygen/Doxyfile2
-rwxr-xr-xdoc/python_api/sphinx_doc_update.py182
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp10
-rw-r--r--extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp4
-rw-r--r--extern/curve_fit_nd/intern/curve_fit_cubic_refit.c22
-rw-r--r--intern/cycles/blender/blender_particles.cpp2
-rw-r--r--intern/cycles/kernel/CMakeLists.txt1
-rw-r--r--intern/cycles/kernel/geom/geom_volume.h2
-rw-r--r--intern/cycles/kernel/kernel_compat_cpu.h2
-rw-r--r--intern/cycles/kernel/kernel_types.h17
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h1
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp7
-rw-r--r--intern/cycles/kernel/osl/osl_services.h1
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp42
-rw-r--r--intern/cycles/kernel/shaders/node_normal_map.osl16
-rw-r--r--intern/cycles/kernel/svm/svm.h9
-rw-r--r--intern/cycles/kernel/svm/svm_bump.h54
-rw-r--r--intern/cycles/kernel/svm/svm_image.h2
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h12
-rw-r--r--intern/cycles/kernel/svm/svm_types.h10
-rw-r--r--intern/cycles/kernel/svm/svm_voxel.h2
-rw-r--r--intern/cycles/render/graph.cpp23
-rw-r--r--intern/cycles/render/light.cpp10
-rw-r--r--intern/cycles/render/light.h3
-rw-r--r--intern/cycles/render/mesh.cpp37
-rw-r--r--intern/cycles/render/mesh.h1
-rw-r--r--intern/cycles/render/nodes.h1
-rw-r--r--intern/cycles/render/object.cpp63
-rw-r--r--intern/cycles/render/object.h1
-rw-r--r--intern/cycles/render/osl.cpp22
-rw-r--r--intern/cycles/render/shader.cpp37
-rw-r--r--intern/cycles/render/shader.h2
-rw-r--r--intern/cycles/render/svm.cpp60
-rw-r--r--intern/cycles/render/svm.h1
-rw-r--r--intern/cycles/util/util_static_assert.h4
-rw-r--r--intern/elbeem/intern/controlparticles.cpp3
-rw-r--r--intern/elbeem/intern/isosurface.h6
-rw-r--r--intern/ghost/intern/GHOST_ContextWGL.cpp1
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp41
-rw-r--r--intern/itasc/ConstraintSet.cpp26
-rw-r--r--intern/itasc/Scene.cpp20
-rw-r--r--intern/itasc/WSDLSSolver.cpp8
m---------release/datafiles/locale0
-rw-r--r--release/datafiles/splash.pngbin230768 -> 283527 bytes
-rw-r--r--release/datafiles/splash_2x.pngbin812837 -> 988186 bytes
-rwxr-xr-xrelease/datafiles/splash_scale.sh18
-rw-r--r--release/datafiles/splash_template.xcfbin1274820 -> 1267126 bytes
m---------release/scripts/addons0
m---------release/scripts/addons_contrib0
-rw-r--r--release/scripts/modules/bl_i18n_utils/utils_spell_check.py2
-rw-r--r--release/scripts/startup/bl_ui/properties_grease_pencil_common.py92
-rw-r--r--release/scripts/startup/bl_ui/properties_render.py4
-rw-r--r--release/scripts/startup/bl_ui/space_view3d.py34
-rw-r--r--source/blender/alembic/intern/abc_hair.cc2
-rw-r--r--source/blender/alembic/intern/abc_points.cc2
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc7
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h1
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h4
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c52
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c5
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c20
-rw-r--r--source/blender/blenkernel/intern/image.c2
-rw-r--r--source/blender/blenkernel/intern/lamp.c2
-rw-r--r--source/blender/blenkernel/intern/library_remap.c4
-rw-r--r--source/blender/blenkernel/intern/mesh.c23
-rw-r--r--source/blender/blenkernel/intern/movieclip.c3
-rw-r--r--source/blender/blenkernel/intern/object.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c26
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c88
-rw-r--r--source/blender/blenkernel/intern/world.c2
-rw-r--r--source/blender/blenlib/intern/math_geom.c4
-rw-r--r--source/blender/blenlib/intern/task.c5
-rw-r--r--source/blender/blenloader/intern/readfile.c13
-rw-r--r--source/blender/blenloader/intern/versioning_270.c17
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc2
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c35
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c830
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h32
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c12
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c25
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c52
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c63
-rw-r--r--source/blender/editors/include/ED_gpencil.h30
-rw-r--r--source/blender/editors/include/ED_numinput.h2
-rw-r--r--source/blender/editors/include/UI_interface.h8
-rw-r--r--source/blender/editors/interface/interface_handlers.c17
-rw-r--r--source/blender/editors/interface/interface_ops.c73
-rw-r--r--source/blender/editors/interface/interface_panel.c76
-rw-r--r--source/blender/editors/interface/interface_regions.c35
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c1
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c2
-rw-r--r--source/blender/editors/object/object_add.c2
-rw-r--r--source/blender/editors/object/object_edit.c2
-rw-r--r--source/blender/editors/object/object_relations.c2
-rw-r--r--source/blender/editors/render/render_preview.c5
-rw-r--r--source/blender/editors/screen/screen_ops.c8
-rw-r--r--source/blender/editors/sound/sound_ops.c73
-rw-r--r--source/blender/editors/space_file/file_intern.h1
-rw-r--r--source/blender/editors/space_file/file_ops.c6
-rw-r--r--source/blender/editors/space_file/file_utils.c14
-rw-r--r--source/blender/editors/space_file/filelist.c39
-rw-r--r--source/blender/editors/space_file/filelist.h1
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_image/image_ops.c16
-rw-r--r--source/blender/editors/space_node/node_draw.c6
-rw-r--r--source/blender/editors/space_view3d/drawobject.c2
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c193
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c2
-rw-r--r--source/blender/gpu/CMakeLists.txt2
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c2
-rw-r--r--source/blender/gpu/intern/gpu_shader.c5
-rw-r--r--source/blender/gpu/shaders/gpu_shader_fire_frag.glsl17
-rw-r--r--source/blender/gpu/shaders/gpu_shader_geometry.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl4
-rw-r--r--source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl12
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h2
-rw-r--r--source/blender/makesdna/DNA_scene_types.h10
-rw-r--r--source/blender/makesrna/RNA_access.h1
-rw-r--r--source/blender/makesrna/intern/rna_access.c39
-rw-r--r--source/blender/makesrna/intern/rna_material.c2
-rw-r--r--source/blender/makesrna/intern/rna_movieclip.c2
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/makesrna/intern/rna_scene.c7
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c10
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c26
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_material.c41
-rw-r--r--source/blender/python/intern/bpy_library_write.c2
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c19
-rw-r--r--source/blenderplayer/CMakeLists.txt2
-rw-r--r--source/creator/CMakeLists.txt4
-rw-r--r--source/gameengine/GamePlayer/ghost/CMakeLists.txt4
m---------source/tools0
139 files changed, 2528 insertions, 636 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d7276f4417a..352712e5ca9 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -220,6 +220,8 @@ if(${CMAKE_VERSION} VERSION_LESS 2.8.8)
endif()
set(BUILDINFO_OVERRIDE_DATE "" CACHE STRING "Use instead of the current date for reproducable builds (empty string disables this option)")
set(BUILDINFO_OVERRIDE_TIME "" CACHE STRING "Use instead of the current time for reproducable builds (empty string disables this option)")
+set(CPACK_OVERRIDE_PACKAGENAME "" CACHE STRING "Use instead of the standard packagename (empty string disables this option)")
+mark_as_advanced(CPACK_OVERRIDE_PACKAGENAME)
mark_as_advanced(BUILDINFO_OVERRIDE_DATE)
mark_as_advanced(BUILDINFO_OVERRIDE_TIME)
@@ -512,6 +514,15 @@ mark_as_advanced(WITH_LEGACY_DEPSGRAPH)
option(WITH_WINDOWS_FIND_MODULES "Use find_package to locate libraries" OFF)
mark_as_advanced(WITH_WINDOWS_FIND_MODULES)
+option(WITH_WINDOWS_CODESIGN "Use signtool to sign the final binary." OFF)
+mark_as_advanced(WITH_WINDOWS_CODESIGN)
+
+set(WINDOWS_CODESIGN_PFX CACHE FILEPATH "Path to pfx file to use for codesigning.")
+mark_as_advanced(WINDOWS_CODESIGN_PFX)
+
+set(WINDOWS_CODESIGN_PFX_PASSWORD CACHE STRING "password for pfx file used for codesigning.")
+mark_as_advanced(WINDOWS_CODESIGN_PFX_PASSWORD)
+
# avoid using again
option_defaults_clear()
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index dc8b158f5c0..fabb35c539e 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -1578,3 +1578,26 @@ macro(openmp_delayload
endif(WITH_OPENMP)
endif(MSVC)
endmacro()
+
+MACRO(WINDOWS_SIGN_TARGET target)
+ if (WITH_WINDOWS_CODESIGN)
+ if (!SIGNTOOL_EXE)
+ error("Codesigning is enabled, but signtool is not found")
+ else()
+ if (WINDOWS_CODESIGN_PFX_PASSWORD)
+ set(CODESIGNPASSWORD /p ${WINDOWS_CODESIGN_PFX_PASSWORD})
+ else()
+ if ($ENV{PFXPASSWORD})
+ set(CODESIGNPASSWORD /p $ENV{PFXPASSWORD})
+ else()
+ message( FATAL_ERROR "WITH_WINDOWS_CODESIGN is on but WINDOWS_CODESIGN_PFX_PASSWORD not set, and environment variable PFXPASSWORD not found, unable to sign code.")
+ endif()
+ endif()
+ add_custom_command(TARGET ${target}
+ POST_BUILD
+ COMMAND ${SIGNTOOL_EXE} sign /f ${WINDOWS_CODESIGN_PFX} ${CODESIGNPASSWORD} $<TARGET_FILE:${target}>
+ VERBATIM
+ )
+ endif()
+ endif()
+ENDMACRO() \ No newline at end of file
diff --git a/build_files/cmake/packaging.cmake b/build_files/cmake/packaging.cmake
index bc1d64f7494..1563331387f 100644
--- a/build_files/cmake/packaging.cmake
+++ b/build_files/cmake/packaging.cmake
@@ -48,7 +48,11 @@ else(MSVC)
set(PACKAGE_ARCH ${CMAKE_SYSTEM_PROCESSOR})
endif()
-set(CPACK_PACKAGE_FILE_NAME ${PROJECT_NAME_LOWER}-${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}-git${CPACK_DATE}.${BUILD_REV}-${PACKAGE_ARCH})
+if (CPACK_OVERRIDE_PACKAGENAME)
+ set(CPACK_PACKAGE_FILE_NAME ${CPACK_OVERRIDE_PACKAGENAME}-${PACKAGE_ARCH})
+else()
+ set(CPACK_PACKAGE_FILE_NAME ${PROJECT_NAME_LOWER}-${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}-git${CPACK_DATE}.${BUILD_REV}-${PACKAGE_ARCH})
+endif()
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
# RPM packages
diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake
index 0e0dc382ca3..1ec9b00d4ca 100644
--- a/build_files/cmake/platform/platform_unix.cmake
+++ b/build_files/cmake/platform/platform_unix.cmake
@@ -245,7 +245,7 @@ if(WITH_BOOST)
set(Boost_USE_STATIC_LIBS ON)
endif()
set(Boost_USE_MULTITHREADED ON)
- set(__boost_packages filesystem regex system thread date_time)
+ set(__boost_packages filesystem regex thread date_time)
if(WITH_CYCLES_OSL)
if(NOT (${OSL_LIBRARY_VERSION_MAJOR} EQUAL "1" AND ${OSL_LIBRARY_VERSION_MINOR} LESS "6"))
list(APPEND __boost_packages wave)
@@ -261,6 +261,7 @@ if(WITH_BOOST)
if(WITH_OPENVDB)
list(APPEND __boost_packages iostreams)
endif()
+ list(APPEND __boost_packages system)
find_package(Boost 1.48 COMPONENTS ${__boost_packages})
if(NOT Boost_FOUND)
# try to find non-multithreaded if -mt not found, this flag
diff --git a/build_files/cmake/platform/platform_win32_msvc.cmake b/build_files/cmake/platform/platform_win32_msvc.cmake
index eaa6e41c9c3..2772944214b 100644
--- a/build_files/cmake/platform/platform_win32_msvc.cmake
+++ b/build_files/cmake/platform/platform_win32_msvc.cmake
@@ -471,3 +471,15 @@ endif()
# used in many places so include globally, like OpenGL
blender_include_dirs_sys("${PTHREADS_INCLUDE_DIRS}")
+
+#find signtool
+SET(ProgramFilesX86_NAME "ProgramFiles(x86)") #env dislikes the ( )
+find_program(SIGNTOOL_EXE signtool
+HINTS
+ "$ENV{${ProgramFilesX86_NAME}}/Windows Kits/10/bin/x86/"
+ "$ENV{ProgramFiles}/Windows Kits/10/bin/x86/"
+ "$ENV{${ProgramFilesX86_NAME}}/Windows Kits/8.1/bin/x86/"
+ "$ENV{ProgramFiles}/Windows Kits/8.1/bin/x86/"
+ "$ENV{${ProgramFilesX86_NAME}}/Windows Kits/8.0/bin/x86/"
+ "$ENV{ProgramFiles}/Windows Kits/8.0/bin/x86/"
+)
diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile
index b34d4dfe6f1..9834cda43bc 100644
--- a/doc/doxygen/Doxyfile
+++ b/doc/doxygen/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Blender
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = "V2.7x"
+PROJECT_NUMBER = "V2.8x"
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/doc/python_api/sphinx_doc_update.py b/doc/python_api/sphinx_doc_update.py
new file mode 100755
index 00000000000..c93f1676d52
--- /dev/null
+++ b/doc/python_api/sphinx_doc_update.py
@@ -0,0 +1,182 @@
+#!/usr/bin/env python3
+
+# ##### 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.
+#
+# Contributor(s): Bastien Montagne
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+"""
+This is a helper script to generate Blender Python API documentation (using Sphinx), and update server data using rsync.
+
+You'll need to specify your user login and password, obviously.
+
+Example usage:
+
+ ./sphinx_doc_update.py --mirror ../../../docs/remote_api_backup/ --source ../.. --blender ../../../build_cmake/bin/blender --user foobar --password barfoo
+
+"""
+
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import zipfile
+
+
+DEFAULT_RSYNC_SERVER = "www.blender.org"
+DEFAULT_RSYNC_ROOT = "/api/"
+DEFAULT_SYMLINK_ROOT = "/data/www/vhosts/www.blender.org/api"
+
+
+def argparse_create():
+ import argparse
+ global __doc__
+
+ # When --help or no args are given, print this help
+ usage_text = __doc__
+
+ parser = argparse.ArgumentParser(description=usage_text,
+ formatter_class=argparse.RawDescriptionHelpFormatter)
+
+ parser.add_argument(
+ "--mirror", dest="mirror_dir",
+ metavar='PATH', required=True,
+ help="Path to local rsync mirror of api doc server")
+ parser.add_argument(
+ "--source", dest="source_dir",
+ metavar='PATH', required=True,
+ help="Path to Blender git repository")
+ parser.add_argument(
+ "--blender", dest="blender",
+ metavar='PATH', required=True,
+ help="Path to Blender executable")
+ parser.add_argument(
+ "--rsync-server", dest="rsync_server", default=DEFAULT_RSYNC_SERVER,
+ metavar='RSYNCSERVER', type=str, required=False,
+ help=("rsync server address"))
+ parser.add_argument(
+ "--rsync-root", dest="rsync_root", default=DEFAULT_RSYNC_ROOT,
+ metavar='RSYNCROOT', type=str, required=False,
+ help=("Root path of API doc on rsync server"))
+ parser.add_argument(
+ "--user", dest="user",
+ metavar='USER', type=str, required=True,
+ help=("User to login on rsync server"))
+ parser.add_argument(
+ "--password", dest="password",
+ metavar='PASSWORD', type=str, required=True,
+ help=("Password to login on rsync server"))
+
+ return parser
+
+
+def main():
+ # ----------
+ # Parse Args
+
+ args = argparse_create().parse_args()
+
+ rsync_base = "rsync://%s@%s:%s" % (args.user, args.rsync_server, args.rsync_root)
+
+ # I) Update local mirror using rsync.
+ rsync_mirror_cmd = ("rsync", "--delete-after", "-avzz", rsync_base, args.mirror_dir)
+ subprocess.run(rsync_mirror_cmd, env=dict(os.environ, RSYNC_PASSWORD=args.password))
+
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ # II) Generate doc source in temp dir.
+ doc_gen_cmd = (args.blender, "--background", "-noaudio", "--factory-startup", "--python-exit-code", "1",
+ "--python", "%s/doc/python_api/sphinx_doc_gen.py" % args.source_dir, "--",
+ "--output", tmp_dir)
+ subprocess.run(doc_gen_cmd)
+
+ # III) Get Blender version info.
+ blenver = ""
+ getver_file = os.path.join(tmp_dir, "blendver.txt")
+ getver_script = (""
+ "import sys, bpy\n"
+ "with open(sys.argv[-1], 'w') as f:\n"
+ " f.write('%d_%d%s_release' % (bpy.app.version[0], bpy.app.version[1], bpy.app.version_char)\n"
+ " if bpy.app.version_cycle in {'rc', 'release'} else '%d_%d_%d' % bpy.app.version)\n")
+ get_ver_cmd = (args.blender, "--background", "-noaudio", "--factory-startup", "--python-exit-code", "1",
+ "--python-expr", getver_script, "--", getver_file)
+ subprocess.run(get_ver_cmd)
+ with open(getver_file) as f:
+ blenver = f.read()
+ os.remove(getver_file)
+
+ # IV) Build doc.
+ curr_dir = os.getcwd()
+ os.chdir(tmp_dir)
+ sphinx_cmd = ("sphinx-build", "-b", "html", "sphinx-in", "sphinx-out")
+ subprocess.run(sphinx_cmd)
+ shutil.rmtree(os.path.join("sphinx-out", ".doctrees"))
+ os.chdir(curr_dir)
+
+ # V) Cleanup existing matching dir in server mirror (if any), and copy new doc.
+ api_name = "blender_python_api_%s" % blenver
+ api_dir = os.path.join(args.mirror_dir, api_name)
+ if os.path.exists(api_dir):
+ shutil.rmtree(api_dir)
+ os.rename(os.path.join(tmp_dir, "sphinx-out"), api_dir)
+
+ # VI) Create zip archive.
+ zip_name = "blender_python_reference_%s" % blenver
+ zip_path = os.path.join(args.mirror_dir, zip_name)
+ with zipfile.ZipFile(zip_path, 'w') as zf:
+ for de in os.scandir(api_dir):
+ zf.write(de.path, arcname=os.path.join(zip_name, de.name))
+ os.rename(zip_path, os.path.join(api_dir, "%s.zip" % zip_name))
+
+ # VII) Create symlinks and html redirects.
+ #~ os.symlink(os.path.join(DEFAULT_SYMLINK_ROOT, api_name, "contents.html"), os.path.join(api_dir, "index.html"))
+ os.symlink("./contents.html", os.path.join(api_dir, "index.html"))
+ if blenver.endswith("release"):
+ symlink = os.path.join(args.mirror_dir, "blender_python_api_current")
+ os.remove(symlink)
+ os.symlink("./%s" % api_name, symlink)
+ with open(os.path.join(args.mirror_dir, "250PythonDoc/index.html"), 'w') as f:
+ f.write("<html><head><title>Redirecting...</title><meta http-equiv=\"REFRESH\""
+ "content=\"0;url=../%s/\"></head><body>Redirecting...</body></html>" % api_name)
+ else:
+ symlink = os.path.join(args.mirror_dir, "blender_python_api_master")
+ os.remove(symlink)
+ os.symlink("./%s" % api_name, symlink)
+ with open(os.path.join(args.mirror_dir, "blender_python_api/index.html"), 'w') as f:
+ f.write("<html><head><title>Redirecting...</title><meta http-equiv=\"REFRESH\""
+ "content=\"0;url=../%s/\"></head><body>Redirecting...</body></html>" % api_name)
+
+ # VIII) Upload (first do a dry-run so user can ensure everything is OK).
+ print("Doc generated in local mirror %s, please check it before uploading "
+ "(hit [Enter] to continue, [Ctrl-C] to exit):" % api_dir)
+ sys.stdin.read(1)
+
+ rsync_mirror_cmd = ("rsync", "--dry-run", "--delete-after", "-avzz", args.mirror_dir, rsync_base)
+ subprocess.run(rsync_mirror_cmd, env=dict(os.environ, RSYNC_PASSWORD=args.password))
+
+ print("Rsync upload simulated, please check every thing is OK (hit [Enter] to continue, [Ctrl-C] to exit):")
+ sys.stdin.read(1)
+
+ rsync_mirror_cmd = ("rsync", "--delete-after", "-avzz", args.mirror_dir, rsync_base)
+ subprocess.run(rsync_mirror_cmd, env=dict(os.environ, RSYNC_PASSWORD=args.password))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
index 2c362778210..c1da9f36cfb 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp
@@ -151,8 +151,8 @@ static btScalar EdgeSeparation(const btBox2dShape* poly1, const btTransform& xf1
int index = 0;
btScalar minDot = BT_LARGE_FLOAT;
- if( count2 > 0 )
- index = (int) normal1.minDot( vertices2, count2, minDot);
+ if( count2 > 0 )
+ index = (int) normal1.minDot( vertices2, count2, minDot);
btVector3 v1 = b2Mul(xf1, vertices1[edge1]);
btVector3 v2 = b2Mul(xf2, vertices2[index]);
@@ -174,9 +174,9 @@ static btScalar FindMaxSeparation(int* edgeIndex,
// Find edge normal on poly1 that has the largest projection onto d.
int edge = 0;
- btScalar maxDot;
- if( count1 > 0 )
- edge = (int) dLocal1.maxDot( normals1, count1, maxDot);
+ btScalar maxDot;
+ if( count1 > 0 )
+ edge = (int) dLocal1.maxDot( normals1, count1, maxDot);
// Get the separation for the edge normal.
btScalar s = EdgeSeparation(poly1, xf1, edge, poly2, xf2);
diff --git a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
index a80c438d12a..589a7f55f2b 100644
--- a/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
+++ b/extern/bullet2/src/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp
@@ -232,8 +232,8 @@ void btCompoundCollisionAlgorithm::processCollision (const btCollisionObjectWrap
m_compoundShapeRevision = compoundShape->getUpdateRevision();
}
- if (m_childCollisionAlgorithms.size()==0)
- return;
+ if (m_childCollisionAlgorithms.size()==0)
+ return;
const btDbvt* tree = compoundShape->getDynamicAabbTree();
//use a dynamic aabb tree to cull potential child-overlaps
diff --git a/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
index b51535bab10..d22d042bff5 100644
--- a/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
+++ b/extern/curve_fit_nd/intern/curve_fit_cubic_refit.c
@@ -1048,7 +1048,6 @@ int curve_fit_cubic_to_points_refit_db(
{
const uint knots_len = points_len;
struct Knot *knots = malloc(sizeof(Knot) * knots_len);
- knots[0].next = NULL;
#ifndef USE_CORNER_DETECT
(void)r_corner_index_array;
@@ -1085,7 +1084,6 @@ int curve_fit_cubic_to_points_refit_db(
knots[i].heap_node = NULL;
knots[i].index = i;
- knots[i].index = i;
knots[i].can_remove = true;
knots[i].is_removed = false;
knots[i].is_corner = false;
@@ -1155,8 +1153,8 @@ int curve_fit_cubic_to_points_refit_db(
add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims);
normalize_vn(k->tan[0], dims);
copy_vnvn(k->tan[1], k->tan[0], dims);
- k->handles[0] = len_prev / 3;
- k->handles[1] = len_next / 3;
+ k->handles[0] = len_prev / 3;
+ k->handles[1] = len_next / -3;
}
#else
if (knots_len < 2) {
@@ -1185,8 +1183,8 @@ int curve_fit_cubic_to_points_refit_db(
add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims);
normalize_vn(k->tan[0], dims);
copy_vnvn(k->tan[1], k->tan[0], dims);
- k->handles[0] = len_prev / 3;
- k->handles[1] = len_next / 3;
+ k->handles[0] = len_prev / 3;
+ k->handles[1] = len_next / -3;
copy_vnvn(tan_prev, tan_next, dims);
len_prev = len_next;
@@ -1201,8 +1199,8 @@ int curve_fit_cubic_to_points_refit_db(
tan_prev, &points[0 * dims], &points[1 * dims], dims);
copy_vnvn(knots[0].tan[0], tan_prev, dims);
copy_vnvn(knots[0].tan[1], tan_prev, dims);
- knots[0].handles[0] = len_prev / 3;
- knots[0].handles[1] = len_prev / 3;
+ knots[0].handles[0] = len_prev / 3;
+ knots[0].handles[1] = len_prev / -3;
for (uint i_curr = 1, i_next = 2; i_next < knots_len; i_curr = i_next++) {
struct Knot *k = &knots[i_curr];
@@ -1215,8 +1213,8 @@ int curve_fit_cubic_to_points_refit_db(
add_vn_vnvn(k->tan[0], tan_prev, tan_next, dims);
normalize_vn(k->tan[0], dims);
copy_vnvn(k->tan[1], k->tan[0], dims);
- k->handles[0] = len_prev / 3;
- k->handles[1] = len_next / 3;
+ k->handles[0] = len_prev / 3;
+ k->handles[1] = len_next / -3;
copy_vnvn(tan_prev, tan_next, dims);
len_prev = len_next;
@@ -1224,8 +1222,8 @@ int curve_fit_cubic_to_points_refit_db(
copy_vnvn(knots[knots_len - 1].tan[0], tan_next, dims);
copy_vnvn(knots[knots_len - 1].tan[1], tan_next, dims);
- knots[knots_len - 1].handles[0] = len_next / 3;
- knots[knots_len - 1].handles[1] = len_next / 3;
+ knots[knots_len - 1].handles[0] = len_next / 3;
+ knots[knots_len - 1].handles[1] = len_next / -3;
}
#endif
}
diff --git a/intern/cycles/blender/blender_particles.cpp b/intern/cycles/blender/blender_particles.cpp
index b9876cd604f..dd2900a8d5b 100644
--- a/intern/cycles/blender/blender_particles.cpp
+++ b/intern/cycles/blender/blender_particles.cpp
@@ -36,6 +36,8 @@ bool BlenderSync::sync_dupli_particle(BL::Object& b_ob,
if(!b_psys)
return false;
+ object->hide_on_missing_motion = true;
+
/* test if we need particle data */
if(!object->mesh->need_attribute(scene, ATTR_STD_PARTICLE))
return false;
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
index 9317bfbb703..3c37bc0b045 100644
--- a/intern/cycles/kernel/CMakeLists.txt
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -113,6 +113,7 @@ set(SRC_SVM_HEADERS
svm/svm.h
svm/svm_attribute.h
svm/svm_blackbody.h
+ svm/svm_bump.h
svm/svm_camera.h
svm/svm_closure.h
svm/svm_convert.h
diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h
index efe540a8518..fd97a63efb5 100644
--- a/intern/cycles/kernel/geom/geom_volume.h
+++ b/intern/cycles/kernel/geom/geom_volume.h
@@ -69,7 +69,7 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd,
# if __CUDA_ARCH__ >= 300
CUtexObject tex = kernel_tex_fetch(__bindless_mapping, desc.offset);
float f = kernel_tex_image_interp_3d_float(tex, P.x, P.y, P.z);
- float4 r = make_float4(f, f, f, 1.0);
+ float4 r = make_float4(f, f, f, 1.0f);
# else
float4 r = volume_image_texture_3d(desc.offset, P.x, P.y, P.z);
# endif
diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h
index 3775934f293..7b30df04550 100644
--- a/intern/cycles/kernel/kernel_compat_cpu.h
+++ b/intern/cycles/kernel/kernel_compat_cpu.h
@@ -112,7 +112,7 @@ template<typename T> struct texture_image {
ccl_always_inline float4 read(uchar r)
{
float f = r*(1.0f/255.0f);
- return make_float4(f, f, f, 1.0);
+ return make_float4(f, f, f, 1.0f);
}
ccl_always_inline float4 read(float r)
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
index deebf87c75f..0646148f6a0 100644
--- a/intern/cycles/kernel/kernel_types.h
+++ b/intern/cycles/kernel/kernel_types.h
@@ -714,20 +714,21 @@ enum ShaderDataFlag {
SD_VOLUME_MIS = (1 << 19), /* use multiple importance sampling */
SD_VOLUME_CUBIC = (1 << 20), /* use cubic interpolation for voxels */
SD_HAS_BUMP = (1 << 21), /* has data connected to the displacement input */
+ SD_HAS_DISPLACEMENT = (1 << 22), /* has true displacement */
SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME|
SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME|
SD_HAS_BSSRDF_BUMP|SD_VOLUME_EQUIANGULAR|SD_VOLUME_MIS|
- SD_VOLUME_CUBIC|SD_HAS_BUMP),
+ SD_VOLUME_CUBIC|SD_HAS_BUMP|SD_HAS_DISPLACEMENT),
/* object flags */
- SD_HOLDOUT_MASK = (1 << 22), /* holdout for camera rays */
- SD_OBJECT_MOTION = (1 << 23), /* has object motion blur */
- SD_TRANSFORM_APPLIED = (1 << 24), /* vertices have transform applied */
- SD_NEGATIVE_SCALE_APPLIED = (1 << 25), /* vertices have negative scale applied */
- SD_OBJECT_HAS_VOLUME = (1 << 26), /* object has a volume shader */
- SD_OBJECT_INTERSECTS_VOLUME = (1 << 27), /* object intersects AABB of an object with volume shader */
- SD_OBJECT_HAS_VERTEX_MOTION = (1 << 28), /* has position for motion vertices */
+ SD_HOLDOUT_MASK = (1 << 23), /* holdout for camera rays */
+ SD_OBJECT_MOTION = (1 << 24), /* has object motion blur */
+ SD_TRANSFORM_APPLIED = (1 << 25), /* vertices have transform applied */
+ SD_NEGATIVE_SCALE_APPLIED = (1 << 26), /* vertices have negative scale applied */
+ SD_OBJECT_HAS_VOLUME = (1 << 27), /* object has a volume shader */
+ SD_OBJECT_INTERSECTS_VOLUME = (1 << 28), /* object intersects AABB of an object with volume shader */
+ SD_OBJECT_HAS_VERTEX_MOTION = (1 << 29), /* has position for motion vertices */
SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED|
SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME|
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h
index 8353c4e434b..65cb7ecc6b4 100644
--- a/intern/cycles/kernel/osl/osl_globals.h
+++ b/intern/cycles/kernel/osl/osl_globals.h
@@ -54,6 +54,7 @@ struct OSLGlobals {
vector<OSL::ShaderGroupRef> surface_state;
vector<OSL::ShaderGroupRef> volume_state;
vector<OSL::ShaderGroupRef> displacement_state;
+ vector<OSL::ShaderGroupRef> bump_state;
OSL::ShaderGroupRef background_state;
/* attributes */
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
index 153ebad6cd2..f61a9ec0fb1 100644
--- a/intern/cycles/kernel/osl/osl_services.cpp
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -93,6 +93,7 @@ ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
ustring OSLRenderServices::u_geom_name("geom:name");
+ustring OSLRenderServices::u_geom_undisplaced("geom:undisplaced");
ustring OSLRenderServices::u_is_smooth("geom:is_smooth");
#ifdef __HAIR__
ustring OSLRenderServices::u_is_curve("geom:is_curve");
@@ -127,8 +128,10 @@ OSLRenderServices::OSLRenderServices()
OSLRenderServices::~OSLRenderServices()
{
- VLOG(2) << "OSL texture system stats:\n"
- << osl_ts->getstats();
+ if(osl_ts) {
+ VLOG(2) << "OSL texture system stats:\n"
+ << osl_ts->getstats();
+ }
#ifdef WITH_PTEX
ptex_cache->release();
#endif
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
index 2701abb483c..0f2e02c62b0 100644
--- a/intern/cycles/kernel/osl/osl_services.h
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -158,6 +158,7 @@ public:
static ustring u_geom_trianglevertices;
static ustring u_geom_polyvertices;
static ustring u_geom_name;
+ static ustring u_geom_undisplaced;
static ustring u_is_smooth;
static ustring u_is_curve;
static ustring u_curve_thickness;
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
index 20dd167708c..0d762bbdb38 100644
--- a/intern/cycles/kernel/osl/osl_shader.cpp
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -184,6 +184,48 @@ void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, PathState *state
OSL::ShadingContext *octx = tdata->context[(int)ctx];
int shader = sd->shader & SHADER_MASK;
+ /* automatic bump shader */
+ if(kg->osl->bump_state[shader]) {
+ /* save state */
+ float3 P = sd->P;
+ float3 dPdx = sd->dP.dx;
+ float3 dPdy = sd->dP.dy;
+
+ /* set state as if undisplaced */
+ if(sd->flag & SD_HAS_DISPLACEMENT) {
+ float data[9];
+ bool found = kg->osl->services->get_attribute(sd, true, OSLRenderServices::u_empty, TypeDesc::TypeVector,
+ OSLRenderServices::u_geom_undisplaced, data);
+ (void)found;
+ assert(found);
+
+ memcpy(&sd->P, data, sizeof(float)*3);
+ memcpy(&sd->dP.dx, data+3, sizeof(float)*3);
+ memcpy(&sd->dP.dy, data+6, sizeof(float)*3);
+
+ object_position_transform(kg, sd, &sd->P);
+ object_dir_transform(kg, sd, &sd->dP.dx);
+ object_dir_transform(kg, sd, &sd->dP.dy);
+
+ globals->P = TO_VEC3(sd->P);
+ globals->dPdx = TO_VEC3(sd->dP.dx);
+ globals->dPdy = TO_VEC3(sd->dP.dy);
+ }
+
+ /* execute bump shader */
+ ss->execute(octx, *(kg->osl->bump_state[shader]), *globals);
+
+ /* reset state */
+ sd->P = P;
+ sd->dP.dx = dPdx;
+ sd->dP.dy = dPdy;
+
+ globals->P = TO_VEC3(P);
+ globals->dPdx = TO_VEC3(dPdx);
+ globals->dPdy = TO_VEC3(dPdy);
+ }
+
+ /* surface shader */
if(kg->osl->surface_state[shader]) {
ss->execute(octx, *(kg->osl->surface_state[shader]), *globals);
}
diff --git a/intern/cycles/kernel/shaders/node_normal_map.osl b/intern/cycles/kernel/shaders/node_normal_map.osl
index f95e9fcfe3c..41bcac4fb10 100644
--- a/intern/cycles/kernel/shaders/node_normal_map.osl
+++ b/intern/cycles/kernel/shaders/node_normal_map.osl
@@ -26,6 +26,7 @@ shader node_normal_map(
output normal Normal = NormalIn)
{
color mcolor = 2.0 * color(Color[0] - 0.5, Color[1] - 0.5, Color[2] - 0.5);
+ int is_backfacing = backfacing();
if (space == "tangent") {
vector tangent;
@@ -34,9 +35,15 @@ shader node_normal_map(
float is_smooth;
getattribute("geom:is_smooth", is_smooth);
- if (!is_smooth)
+ if (!is_smooth) {
ninterp = normalize(transform("world", "object", Ng));
+ /* the normal is already inverted, which is too soon for the math here */
+ if (is_backfacing) {
+ ninterp = -ninterp;
+ }
+ }
+
// get _unnormalized_ interpolated normal and tangent
if (getattribute(attr_name, tangent) &&
getattribute(attr_sign_name, tangent_sign) &&
@@ -73,7 +80,12 @@ shader node_normal_map(
Normal = normalize(vector(mcolor));
}
-
+
+ /* invert normal for backfacing polygons */
+ if (is_backfacing) {
+ Normal = -Normal;
+ }
+
if (Strength != 1.0)
Normal = normalize(NormalIn + (Normal - NormalIn) * max(Strength, 0.0));
}
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
index 502994e71f1..9ca8917d327 100644
--- a/intern/cycles/kernel/svm/svm.h
+++ b/intern/cycles/kernel/svm/svm.h
@@ -181,6 +181,7 @@ CCL_NAMESPACE_END
#include "svm_brick.h"
#include "svm_vector_transform.h"
#include "svm_voxel.h"
+#include "svm_bump.h"
CCL_NAMESPACE_BEGIN
@@ -294,6 +295,14 @@ ccl_device_noinline void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ccl_a
case NODE_CLOSURE_SET_NORMAL:
svm_node_set_normal(kg, sd, stack, node.y, node.z);
break;
+# if NODES_FEATURE(NODE_FEATURE_BUMP_STATE)
+ case NODE_ENTER_BUMP_EVAL:
+ svm_node_enter_bump_eval(kg, sd, stack, node.y);
+ break;
+ case NODE_LEAVE_BUMP_EVAL:
+ svm_node_leave_bump_eval(kg, sd, stack, node.y);
+ break;
+# endif /* NODES_FEATURE(NODE_FEATURE_BUMP_STATE) */
# endif /* NODES_FEATURE(NODE_FEATURE_BUMP) */
case NODE_HSV:
svm_node_hsv(kg, sd, stack, node, &offset);
diff --git a/intern/cycles/kernel/svm/svm_bump.h b/intern/cycles/kernel/svm/svm_bump.h
new file mode 100644
index 00000000000..04a8c7b64e5
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_bump.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2011-2016 Blender Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Bump Eval Nodes */
+
+ccl_device void svm_node_enter_bump_eval(KernelGlobals *kg, ShaderData *sd, float *stack, uint offset)
+{
+ /* save state */
+ stack_store_float3(stack, offset+0, ccl_fetch(sd, P));
+ stack_store_float3(stack, offset+3, ccl_fetch(sd, dP).dx);
+ stack_store_float3(stack, offset+6, ccl_fetch(sd, dP).dy);
+
+ /* set state as if undisplaced */
+ const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_POSITION_UNDISPLACED);
+
+ if(desc.offset != ATTR_STD_NOT_FOUND) {
+ float3 P, dPdx, dPdy;
+ P = primitive_attribute_float3(kg, sd, desc, &dPdx, &dPdy);
+
+ object_position_transform(kg, sd, &P);
+ object_dir_transform(kg, sd, &dPdx);
+ object_dir_transform(kg, sd, &dPdy);
+
+ ccl_fetch(sd, P) = P;
+ ccl_fetch(sd, dP).dx = dPdx;
+ ccl_fetch(sd, dP).dy = dPdy;
+ }
+}
+
+ccl_device void svm_node_leave_bump_eval(KernelGlobals *kg, ShaderData *sd, float *stack, uint offset)
+{
+ /* restore state */
+ ccl_fetch(sd, P) = stack_load_float3(stack, offset+0);
+ ccl_fetch(sd, dP).dx = stack_load_float3(stack, offset+3);
+ ccl_fetch(sd, dP).dy = stack_load_float3(stack, offset+6);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
index 5d02be1fa2f..378ce650129 100644
--- a/intern/cycles/kernel/svm/svm_image.h
+++ b/intern/cycles/kernel/svm/svm_image.h
@@ -296,7 +296,7 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y,
/* float, byte and half */
else {
float f = kernel_tex_image_interp_float(tex, x, y);
- r = make_float4(f, f, f, 1.0);
+ r = make_float4(f, f, f, 1.0f);
}
# endif
#endif
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
index 01dede3fff5..6ea2539c543 100644
--- a/intern/cycles/kernel/svm/svm_tex_coord.h
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -277,6 +277,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
float3 color = stack_load_float3(stack, color_offset);
color = 2.0f*make_float3(color.x - 0.5f, color.y - 0.5f, color.z - 0.5f);
+ bool is_backfacing = (ccl_fetch(sd, flag) & SD_BACKFACING) != 0;
float3 N;
if(space == NODE_NORMAL_MAP_TANGENT) {
@@ -306,6 +307,12 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
}
else {
normal = ccl_fetch(sd, Ng);
+
+ /* the normal is already inverted, which is too soon for the math here */
+ if(is_backfacing) {
+ normal = -normal;
+ }
+
object_inverse_normal_transform(kg, sd, &normal);
}
@@ -332,6 +339,11 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st
N = safe_normalize(N);
}
+ /* invert normal for backfacing polygons */
+ if(is_backfacing) {
+ N = -N;
+ }
+
float strength = stack_load_float(stack, strength_offset);
if(strength != 1.0f) {
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
index 51083c31708..5adf7d34f7f 100644
--- a/intern/cycles/kernel/svm/svm_types.h
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -26,6 +26,8 @@ CCL_NAMESPACE_BEGIN
/* SVM stack offsets with this value indicate that it's not on the stack */
#define SVM_STACK_INVALID 255
+#define SVM_BUMP_EVAL_STATE_SIZE 9
+
/* Nodes */
/* Known frequencies of used nodes, used for selective nodes compilation
@@ -45,11 +47,12 @@ CCL_NAMESPACE_BEGIN
#define NODE_FEATURE_VOLUME (1 << 0)
#define NODE_FEATURE_HAIR (1 << 1)
#define NODE_FEATURE_BUMP (1 << 2)
+#define NODE_FEATURE_BUMP_STATE (1 << 3)
/* TODO(sergey): Consider using something like ((uint)(-1)).
* Need to check carefully operand types around usage of this
* define first.
*/
-#define NODE_FEATURE_ALL (NODE_FEATURE_VOLUME|NODE_FEATURE_HAIR|NODE_FEATURE_BUMP)
+#define NODE_FEATURE_ALL (NODE_FEATURE_VOLUME|NODE_FEATURE_HAIR|NODE_FEATURE_BUMP|NODE_FEATURE_BUMP_STATE)
typedef enum ShaderNodeType {
NODE_END = 0,
@@ -127,6 +130,8 @@ typedef enum ShaderNodeType {
NODE_HAIR_INFO,
NODE_UVMAP,
NODE_TEX_VOXEL,
+ NODE_ENTER_BUMP_EVAL,
+ NODE_LEAVE_BUMP_EVAL,
} ShaderNodeType;
typedef enum NodeAttributeType {
@@ -374,7 +379,8 @@ typedef enum NodeTexVoxelSpace {
typedef enum ShaderType {
SHADER_TYPE_SURFACE,
SHADER_TYPE_VOLUME,
- SHADER_TYPE_DISPLACEMENT
+ SHADER_TYPE_DISPLACEMENT,
+ SHADER_TYPE_BUMP,
} ShaderType;
/* Closure */
diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h
index d2cc2c3730e..f54f4e8e888 100644
--- a/intern/cycles/kernel/svm/svm_voxel.h
+++ b/intern/cycles/kernel/svm/svm_voxel.h
@@ -50,7 +50,7 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg,
r = kernel_tex_image_interp_3d_float4(tex, co.x, co.y, co.z);
else {
float f = kernel_tex_image_interp_3d_float(tex, co.x, co.y, co.z);
- r = make_float4(f, f, f, 1.0);
+ r = make_float4(f, f, f, 1.0f);
}
# else /* __CUDA_ARCH__ >= 300 */
r = volume_image_texture_3d(id, co.x, co.y, co.z);
diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp
index 6e795ef896a..57256ceecd3 100644
--- a/intern/cycles/render/graph.cpp
+++ b/intern/cycles/render/graph.cpp
@@ -856,27 +856,8 @@ void ShaderGraph::bump_from_displacement()
/* connect the bump out to the set normal in: */
connect(bump->output("Normal"), set_normal->input("Direction"));
- /* connect bump output to normal input nodes that aren't set yet. actually
- * this will only set the normal input to the geometry node that we created
- * and connected to all other normal inputs already. */
- foreach(ShaderNode *node, nodes) {
- /* Don't connect normal to the bump node we're coming from,
- * otherwise it'll be a cycle in graph.
- */
- if(node == bump) {
- continue;
- }
- foreach(ShaderInput *input, node->inputs) {
- if(!input->link && (input->flags() & SocketType::LINK_NORMAL))
- connect(set_normal->output("Normal"), input);
- }
- }
-
- /* for displacement bump, clear the normal input in case the above loop
- * connected the setnormal out to the bump normalin */
- ShaderInput *bump_normal_in = bump->input("Normal");
- if(bump_normal_in)
- bump_normal_in->link = NULL;
+ /* connect to output node */
+ connect(set_normal->output("Normal"), output()->input("Normal"));
/* finally, add the copied nodes to the graph. we can't do this earlier
* because we would create dependency cycles in the above loop */
diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp
index 4cd77f8c6e1..787e5cf07b2 100644
--- a/intern/cycles/render/light.cpp
+++ b/intern/cycles/render/light.cpp
@@ -177,6 +177,16 @@ LightManager::~LightManager()
{
}
+bool LightManager::has_background_light(Scene *scene)
+{
+ foreach(Light *light, scene->lights) {
+ if(light->type == LIGHT_BACKGROUND) {
+ return true;
+ }
+ }
+ return false;
+}
+
void LightManager::disable_ineffective_light(Device *device, Scene *scene)
{
/* Make all lights enabled by default, and perform some preliminary checks
diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h
index 745caa96159..040a672937d 100644
--- a/intern/cycles/render/light.h
+++ b/intern/cycles/render/light.h
@@ -91,6 +91,9 @@ public:
void tag_update(Scene *scene);
+ /* Check whether there is a background light. */
+ bool has_background_light(Scene *scene);
+
protected:
/* Optimization: disable light which is either unsupported or
* which doesn't contribute to the scene or which is only used for MIS
diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp
index 35d1a441975..2d297c33446 100644
--- a/intern/cycles/render/mesh.cpp
+++ b/intern/cycles/render/mesh.cpp
@@ -567,10 +567,11 @@ void Mesh::add_vertex_normals()
for(size_t i = 0; i < subd_faces.size(); i++) {
SubdFace& face = subd_faces[i];
+ float3 fN = face.normal(this);
for(size_t j = 0; j < face.num_corners; j++) {
size_t corner = subd_face_corners[face.start_corner+j];
- vN[corner] += verts[corner];
+ vN[corner] += fN;
}
}
@@ -583,6 +584,28 @@ void Mesh::add_vertex_normals()
}
}
+void Mesh::add_undisplaced()
+{
+ AttributeSet& attrs = (subdivision_type == SUBDIVISION_NONE) ? attributes : subd_attributes;
+
+ /* don't compute if already there */
+ if(attrs.find(ATTR_STD_POSITION_UNDISPLACED)) {
+ return;
+ }
+
+ /* get attribute */
+ Attribute *attr = attrs.add(ATTR_STD_POSITION_UNDISPLACED);
+ attr->flags |= ATTR_SUBDIVIDED;
+
+ float3 *data = attr->data_float3();
+
+ /* copy verts */
+ size_t size = attr->buffer_size(this, (subdivision_type == SUBDIVISION_NONE) ? ATTR_PRIM_TRIANGLE : ATTR_PRIM_SUBD);
+ if(size) {
+ memcpy(data, verts.data(), size);
+ }
+}
+
void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
{
Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL);
@@ -609,7 +632,7 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal)
last_smooth = smooth[i];
Shader *shader = (last_shader < used_shaders.size()) ?
used_shaders[last_shader] : scene->default_surface;
- shader_id = scene->shader_manager->get_shader_id(shader, this, last_smooth);
+ shader_id = scene->shader_manager->get_shader_id(shader, last_smooth);
}
tri_shader[i] = shader_id;
@@ -678,7 +701,7 @@ void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, s
int shader_id = curve_shader[i];
Shader *shader = (shader_id < used_shaders.size()) ?
used_shaders[shader_id] : scene->default_surface;
- shader_id = scene->shader_manager->get_shader_id(shader, this, false);
+ shader_id = scene->shader_manager->get_shader_id(shader, false);
curve_data[i] = make_float4(
__int_as_float(curve.first_key + curvekey_offset),
@@ -1627,10 +1650,10 @@ void MeshManager::device_update_displacement_images(Device *device,
foreach(Mesh *mesh, scene->meshes) {
if(mesh->need_update) {
foreach(Shader *shader, mesh->used_shaders) {
- if(shader->graph_bump == NULL) {
+ if(!shader->has_displacement || shader->displacement_method == DISPLACE_BUMP) {
continue;
}
- foreach(ShaderNode* node, shader->graph_bump->nodes) {
+ foreach(ShaderNode* node, shader->graph->nodes) {
if(node->special_type != SHADER_SPECIAL_TYPE_IMAGE_SLOT) {
continue;
}
@@ -1681,6 +1704,10 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen
mesh->add_face_normals();
mesh->add_vertex_normals();
+ if(mesh->need_attribute(scene, ATTR_STD_POSITION_UNDISPLACED)) {
+ mesh->add_undisplaced();
+ }
+
if(progress.get_cancel()) return;
}
}
diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h
index a77e296ea4a..c0310f45840 100644
--- a/intern/cycles/render/mesh.h
+++ b/intern/cycles/render/mesh.h
@@ -215,6 +215,7 @@ public:
void compute_bounds();
void add_face_normals();
void add_vertex_normals();
+ void add_undisplaced();
void pack_normals(Scene *scene, uint *shader, float4 *vnormal);
void pack_verts(const vector<uint>& tri_prim_index,
diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h
index b0eb2395adf..fd349f4b7e8 100644
--- a/intern/cycles/render/nodes.h
+++ b/intern/cycles/render/nodes.h
@@ -770,6 +770,7 @@ class CameraNode : public ShaderNode {
public:
SHADER_NODE_CLASS(CameraNode)
bool has_spatial_varying() { return true; }
+ virtual int get_group() { return NODE_GROUP_LEVEL_2; }
};
class FresnelNode : public ShaderNode {
diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp
index db44327e24c..d8f3ce58505 100644
--- a/intern/cycles/render/object.cpp
+++ b/intern/cycles/render/object.cpp
@@ -45,6 +45,7 @@ NODE_DEFINE(Object)
SOCKET_UINT(random_id, "Random ID", 0);
SOCKET_INT(pass_id, "Pass ID", 0);
SOCKET_BOOLEAN(use_holdout, "Use Holdout", false);
+ SOCKET_BOOLEAN(hide_on_missing_motion, "Hide on Missing Motion", false);
SOCKET_POINT(dupli_generated, "Dupli Generated", make_float3(0.0f, 0.0f, 0.0f));
SOCKET_POINT2(dupli_uv, "Dupli UV", make_float2(0.0f, 0.0f));
@@ -72,28 +73,41 @@ void Object::compute_bounds(bool motion_blur)
BoundBox mbounds = mesh->bounds;
if(motion_blur && use_motion) {
- if(motion.pre == transform_empty() ||
- motion.post == transform_empty()) {
+ MotionTransform mtfm = motion;
+
+ if(hide_on_missing_motion) {
/* Hide objects that have no valid previous or next transform, for
* example particle that stop existing. TODO: add support for this
* case in the kernel so we don't get render artifacts. */
- bounds = BoundBox::empty;
+ if(mtfm.pre == transform_empty() ||
+ mtfm.post == transform_empty()) {
+ bounds = BoundBox::empty;
+ return;
+ }
+ }
+
+ /* In case of missing motion information for previous/next frame,
+ * assume there is no motion. */
+ if(mtfm.pre == transform_empty()) {
+ mtfm.pre = tfm;
+ }
+ if(mtfm.post == transform_empty()) {
+ mtfm.post = tfm;
}
- else {
- DecompMotionTransform decomp;
- transform_motion_decompose(&decomp, &motion, &tfm);
- bounds = BoundBox::empty;
+ DecompMotionTransform decomp;
+ transform_motion_decompose(&decomp, &mtfm, &tfm);
- /* todo: this is really terrible. according to pbrt there is a better
- * way to find this iteratively, but did not find implementation yet
- * or try to implement myself */
- for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
- Transform ttfm;
+ bounds = BoundBox::empty;
- transform_motion_interpolate(&ttfm, &decomp, t);
- bounds.grow(mbounds.transformed(&ttfm));
- }
+ /* todo: this is really terrible. according to pbrt there is a better
+ * way to find this iteratively, but did not find implementation yet
+ * or try to implement myself */
+ for(float t = 0.0f; t < 1.0f; t += (1.0f/128.0f)) {
+ Transform ttfm;
+
+ transform_motion_interpolate(&ttfm, &decomp, t);
+ bounds.grow(mbounds.transformed(&ttfm));
}
}
else {
@@ -345,28 +359,27 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s
* comes with deformed position in object space, or if we transform
* the shading point in world space.
*/
- Transform mtfm_pre = ob->motion.pre;
- Transform mtfm_post = ob->motion.post;
+ MotionTransform mtfm = ob->motion;
/* In case of missing motion information for previous/next frame,
* assume there is no motion. */
- if(!ob->use_motion || mtfm_pre == transform_empty()) {
- mtfm_pre = ob->tfm;
+ if(!ob->use_motion || mtfm.pre == transform_empty()) {
+ mtfm.pre = ob->tfm;
}
- if(!ob->use_motion || mtfm_post == transform_empty()) {
- mtfm_post = ob->tfm;
+ if(!ob->use_motion || mtfm.post == transform_empty()) {
+ mtfm.post = ob->tfm;
}
if(!mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION)) {
- mtfm_pre = mtfm_pre * itfm;
- mtfm_post = mtfm_post * itfm;
+ mtfm.pre = mtfm.pre * itfm;
+ mtfm.post = mtfm.post * itfm;
}
else {
flag |= SD_OBJECT_HAS_VERTEX_MOTION;
}
- memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+0], &mtfm_pre, sizeof(float4)*3);
- memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+3], &mtfm_post, sizeof(float4)*3);
+ memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+0], &mtfm.pre, sizeof(float4)*3);
+ memcpy(&objects_vector[object_index*OBJECT_VECTOR_SIZE+3], &mtfm.post, sizeof(float4)*3);
}
#ifdef __OBJECT_MOTION__
else if(state->need_motion == Scene::MOTION_BLUR) {
diff --git a/intern/cycles/render/object.h b/intern/cycles/render/object.h
index 2e5837f672f..7e306fab2a8 100644
--- a/intern/cycles/render/object.h
+++ b/intern/cycles/render/object.h
@@ -51,6 +51,7 @@ public:
uint visibility;
MotionTransform motion;
bool use_motion;
+ bool hide_on_missing_motion;
bool use_holdout;
float3 dupli_generated;
diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp
index 1a6ae5f9277..f83aab47e84 100644
--- a/intern/cycles/render/osl.cpp
+++ b/intern/cycles/render/osl.cpp
@@ -609,7 +609,7 @@ bool OSLCompiler::node_skip_input(ShaderNode *node, ShaderInput *input)
return true;
if(input->name() == "Displacement" && current_type != SHADER_TYPE_DISPLACEMENT)
return true;
- if(input->name() == "Normal")
+ if(input->name() == "Normal" && current_type != SHADER_TYPE_BUMP)
return true;
}
else if(node->special_type == SHADER_SPECIAL_TYPE_BUMP) {
@@ -684,6 +684,8 @@ void OSLCompiler::add(ShaderNode *node, const char *name, bool isfilepath)
ss->Shader("surface", name, id(node).c_str());
else if(current_type == SHADER_TYPE_DISPLACEMENT)
ss->Shader("displacement", name, id(node).c_str());
+ else if(current_type == SHADER_TYPE_BUMP)
+ ss->Shader("displacement", name, id(node).c_str());
else
assert(0);
@@ -1055,6 +1057,12 @@ OSL::ShaderGroupRef OSLCompiler::compile_type(Shader *shader, ShaderGraph *graph
generate_nodes(dependencies);
output->compile(*this);
}
+ else if(type == SHADER_TYPE_BUMP) {
+ /* generate bump shader */
+ find_dependencies(dependencies, output->input("Normal"));
+ generate_nodes(dependencies);
+ output->compile(*this);
+ }
else if(type == SHADER_TYPE_VOLUME) {
/* generate volume shader */
find_dependencies(dependencies, output->input("Volume"));
@@ -1116,10 +1124,10 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
if(shader->used && graph && output->input("Surface")->link) {
shader->osl_surface_ref = compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
- if(shader->graph_bump)
- shader->osl_surface_bump_ref = compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE);
+ if(shader->graph_bump && shader->displacement_method != DISPLACE_TRUE)
+ shader->osl_surface_bump_ref = compile_type(shader, shader->graph_bump, SHADER_TYPE_BUMP);
else
- shader->osl_surface_bump_ref = shader->osl_surface_ref;
+ shader->osl_surface_bump_ref = OSL::ShaderGroupRef();
shader->has_surface = true;
}
@@ -1147,13 +1155,9 @@ void OSLCompiler::compile(Scene *scene, OSLGlobals *og, Shader *shader)
/* push state to array for lookup */
og->surface_state.push_back(shader->osl_surface_ref);
- og->surface_state.push_back(shader->osl_surface_bump_ref);
-
- og->volume_state.push_back(shader->osl_volume_ref);
og->volume_state.push_back(shader->osl_volume_ref);
-
- og->displacement_state.push_back(shader->osl_displacement_ref);
og->displacement_state.push_back(shader->osl_displacement_ref);
+ og->bump_state.push_back(shader->osl_surface_bump_ref);
}
#else
diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp
index d000cca5a45..70e1443be2c 100644
--- a/intern/cycles/render/shader.cpp
+++ b/intern/cycles/render/shader.cpp
@@ -221,6 +221,16 @@ void Shader::tag_update(Scene *scene)
if(use_mis && has_surface_emission)
scene->light_manager->need_update = true;
+ /* Special handle of background MIS light for now: for some reason it
+ * has use_mis set to false. We are quite close to release now, so
+ * better to be safe.
+ */
+ if(this == scene->default_background &&
+ scene->light_manager->has_background_light(scene))
+ {
+ scene->light_manager->need_update = true;
+ }
+
/* quick detection of which kind of shaders we have to avoid loading
* e.g. surface attributes when there is only a volume shader. this could
* be more fine grained but it's better than nothing */
@@ -240,6 +250,10 @@ void Shader::tag_update(Scene *scene)
attributes.clear();
foreach(ShaderNode *node, graph->nodes)
node->attributes(this, &attributes);
+
+ if(has_displacement && displacement_method == DISPLACE_BOTH) {
+ attributes.add(ATTR_STD_POSITION_UNDISPLACED);
+ }
/* compare if the attributes changed, mesh manager will check
* need_update_attributes, update the relevant meshes and clear it. */
@@ -312,14 +326,11 @@ uint ShaderManager::get_attribute_id(AttributeStandard std)
return (uint)std;
}
-int ShaderManager::get_shader_id(Shader *shader, Mesh *mesh, bool smooth)
+int ShaderManager::get_shader_id(Shader *shader, bool smooth)
{
/* get a shader id to pass to the kernel */
- int id = shader->id*2;
-
- /* index depends bump since this setting is not in the shader */
- if(mesh && shader->displacement_method != DISPLACE_TRUE)
- id += 1;
+ int id = shader->id;
+
/* smooth flag */
if(smooth)
id |= SHADER_SMOOTH_NORMAL;
@@ -368,7 +379,7 @@ void ShaderManager::device_update_common(Device *device,
if(scene->shaders.size() == 0)
return;
- uint shader_flag_size = scene->shaders.size()*4;
+ uint shader_flag_size = scene->shaders.size()*2;
uint *shader_flag = dscene->shader_flag.resize(shader_flag_size);
uint i = 0;
bool has_volumes = false;
@@ -406,15 +417,14 @@ void ShaderManager::device_update_common(Device *device,
flag |= SD_VOLUME_CUBIC;
if(shader->graph_bump)
flag |= SD_HAS_BUMP;
-
- /* regular shader */
- shader_flag[i++] = flag;
- shader_flag[i++] = shader->pass_id;
+ if(shader->displacement_method != DISPLACE_BUMP)
+ flag |= SD_HAS_DISPLACEMENT;
/* shader with bump mapping */
- if(shader->graph_bump)
+ if(shader->displacement_method != DISPLACE_TRUE && shader->graph_bump)
flag |= SD_HAS_BSSRDF_BUMP;
+ /* regular shader */
shader_flag[i++] = flag;
shader_flag[i++] = shader->pass_id;
@@ -551,6 +561,9 @@ void ShaderManager::get_requested_features(Scene *scene,
ShaderNode *output_node = shader->graph->output();
if(output_node->input("Displacement")->link != NULL) {
requested_features->nodes_features |= NODE_FEATURE_BUMP;
+ if(shader->displacement_method == DISPLACE_BOTH && requested_features->experimental) {
+ requested_features->nodes_features |= NODE_FEATURE_BUMP_STATE;
+ }
}
/* On top of volume nodes, also check if we need volume sampling because
* e.g. an Emission node would slip through the NODE_FEATURE_VOLUME check */
diff --git a/intern/cycles/render/shader.h b/intern/cycles/render/shader.h
index 060ad7056bc..696e22bc3c9 100644
--- a/intern/cycles/render/shader.h
+++ b/intern/cycles/render/shader.h
@@ -173,7 +173,7 @@ public:
uint get_attribute_id(AttributeStandard std);
/* get shader id for mesh faces */
- int get_shader_id(Shader *shader, Mesh *mesh = NULL, bool smooth = false);
+ int get_shader_id(Shader *shader, bool smooth = false);
/* add default shaders to scene, to use as default for things that don't
* have any shader assigned explicitly */
diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp
index 1a166885e2b..352bed8f0f2 100644
--- a/intern/cycles/render/svm.cpp
+++ b/intern/cycles/render/svm.cpp
@@ -63,7 +63,6 @@ void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene
for(i = 0; i < scene->shaders.size(); i++) {
svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
- svm_nodes.push_back(make_int4(NODE_SHADER_JUMP, 0, 0, 0));
}
foreach(Shader *shader, scene->shaders) {
@@ -147,9 +146,8 @@ int SVMCompiler::stack_size(SocketType::Type type)
return size;
}
-int SVMCompiler::stack_find_offset(SocketType::Type type)
+int SVMCompiler::stack_find_offset(int size)
{
- int size = stack_size(type);
int offset = -1;
/* find free space in stack & mark as used */
@@ -176,6 +174,11 @@ int SVMCompiler::stack_find_offset(SocketType::Type type)
return 0;
}
+int SVMCompiler::stack_find_offset(SocketType::Type type)
+{
+ return stack_find_offset(stack_size(type));
+}
+
void SVMCompiler::stack_clear_offset(SocketType::Type type, int offset)
{
int size = stack_size(type);
@@ -648,6 +651,9 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
case SHADER_TYPE_DISPLACEMENT:
clin = node->input("Displacement");
break;
+ case SHADER_TYPE_BUMP:
+ clin = node->input("Normal");
+ break;
default:
assert(0);
break;
@@ -664,6 +670,14 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
output->stack_offset = SVM_STACK_INVALID;
}
+ /* for the bump shader we need add a node to store the shader state */
+ bool need_bump_state = (type == SHADER_TYPE_BUMP) && (shader->displacement_method == DISPLACE_BOTH);
+ int bump_state_offset = SVM_STACK_INVALID;
+ if(need_bump_state) {
+ bump_state_offset = stack_find_offset(SVM_BUMP_EVAL_STATE_SIZE);
+ add_node(NODE_ENTER_BUMP_EVAL, bump_state_offset);
+ }
+
if(shader->used) {
if(clin->link) {
bool generate = false;
@@ -681,6 +695,9 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
generate = true;
shader->has_displacement = true;
break;
+ case SHADER_TYPE_BUMP: /* generate bump shader */
+ generate = true;
+ break;
default:
break;
}
@@ -697,13 +714,21 @@ void SVMCompiler::compile_type(Shader *shader, ShaderGraph *graph, ShaderType ty
node->compile(*this);
}
+ /* add node to restore state after bump shader has finished */
+ if(need_bump_state) {
+ add_node(NODE_LEAVE_BUMP_EVAL, bump_state_offset);
+ }
+
/* if compile failed, generate empty shader */
if(compile_failed) {
svm_nodes.clear();
compile_failed = false;
}
- add_node(NODE_END, 0, 0, 0);
+ /* for bump shaders we fall thru to the surface shader, but if this is any other kind of shader it ends here */
+ if(type != SHADER_TYPE_BUMP) {
+ add_node(NODE_END, 0, 0, 0);
+ }
}
void SVMCompiler::compile(Scene *scene,
@@ -753,19 +778,22 @@ void SVMCompiler::compile(Scene *scene,
shader->has_object_dependency = false;
shader->has_integrator_dependency = false;
+ /* generate bump shader */
+ if(shader->displacement_method != DISPLACE_TRUE && shader->graph_bump) {
+ scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL);
+ compile_type(shader, shader->graph_bump, SHADER_TYPE_BUMP);
+ global_svm_nodes[index].y = global_svm_nodes.size();
+ global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
+ }
+
/* generate surface shader */
{
scoped_timer timer((summary != NULL)? &summary->time_generate_surface: NULL);
compile_type(shader, shader->graph, SHADER_TYPE_SURFACE);
- global_svm_nodes[index*2 + 0].y = global_svm_nodes.size();
- global_svm_nodes[index*2 + 1].y = global_svm_nodes.size();
- global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
- }
-
- if(shader->graph_bump) {
- scoped_timer timer((summary != NULL)? &summary->time_generate_bump: NULL);
- compile_type(shader, shader->graph_bump, SHADER_TYPE_SURFACE);
- global_svm_nodes[index*2 + 1].y = global_svm_nodes.size();
+ /* only set jump offset if there's no bump shader, as the bump shader will fall thru to this one if it exists */
+ if(shader->displacement_method == DISPLACE_TRUE || !shader->graph_bump) {
+ global_svm_nodes[index].y = global_svm_nodes.size();
+ }
global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
}
@@ -773,8 +801,7 @@ void SVMCompiler::compile(Scene *scene,
{
scoped_timer timer((summary != NULL)? &summary->time_generate_volume: NULL);
compile_type(shader, shader->graph, SHADER_TYPE_VOLUME);
- global_svm_nodes[index*2 + 0].z = global_svm_nodes.size();
- global_svm_nodes[index*2 + 1].z = global_svm_nodes.size();
+ global_svm_nodes[index].z = global_svm_nodes.size();
global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
}
@@ -782,8 +809,7 @@ void SVMCompiler::compile(Scene *scene,
{
scoped_timer timer((summary != NULL)? &summary->time_generate_displacement: NULL);
compile_type(shader, shader->graph, SHADER_TYPE_DISPLACEMENT);
- global_svm_nodes[index*2 + 0].w = global_svm_nodes.size();
- global_svm_nodes[index*2 + 1].w = global_svm_nodes.size();
+ global_svm_nodes[index].w = global_svm_nodes.size();
global_svm_nodes.insert(global_svm_nodes.end(), svm_nodes.begin(), svm_nodes.end());
}
diff --git a/intern/cycles/render/svm.h b/intern/cycles/render/svm.h
index e14d57d7601..99e91ca0c3e 100644
--- a/intern/cycles/render/svm.h
+++ b/intern/cycles/render/svm.h
@@ -99,6 +99,7 @@ public:
int stack_assign(ShaderInput *input);
int stack_assign_if_linked(ShaderInput *input);
int stack_assign_if_linked(ShaderOutput *output);
+ int stack_find_offset(int size);
int stack_find_offset(SocketType::Type type);
void stack_clear_offset(SocketType::Type type, int offset);
void stack_link(ShaderInput *input, ShaderOutput *output);
diff --git a/intern/cycles/util/util_static_assert.h b/intern/cycles/util/util_static_assert.h
index 1b945705145..033d85e8ec6 100644
--- a/intern/cycles/util/util_static_assert.h
+++ b/intern/cycles/util/util_static_assert.h
@@ -25,6 +25,10 @@ CCL_NAMESPACE_BEGIN
#ifndef __KERNEL_GPU__
# if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
/* C++11 has built-in static_assert() */
+# elif defined(static_assert)
+/* Some platforms might have static_assert() defined even tho their
+ * C++ support wouldn't be declared to be C++11.
+ */
# else /* C++11 or MSVC2015 */
template <bool Test> class StaticAssertFailure;
template <> class StaticAssertFailure<true> {};
diff --git a/intern/elbeem/intern/controlparticles.cpp b/intern/elbeem/intern/controlparticles.cpp
index 526fac0cc6b..f6329ad4b67 100644
--- a/intern/elbeem/intern/controlparticles.cpp
+++ b/intern/elbeem/intern/controlparticles.cpp
@@ -1316,7 +1316,8 @@ void ControlParticles::finishControl(std::vector<ControlForces> &forces, LbmFloa
if(cvweight>1.) { cvweight = 1.; }
// thus cvweight is in the range of 0..influenceVelocity, currently not normalized by numCParts
cvweight *= ivel;
- if(cvweight<0.) cvweight=0.; if(cvweight>1.) cvweight=1.;
+ if(cvweight<0.) cvweight=0.;
+ if(cvweight>1.) cvweight=1.;
// LBM, FIXME todo use relaxation factor
//pvel = (cvel*0.5 * cvweight) + (pvel * (1.0-cvweight));
forces[i].weightVel = cvweight;
diff --git a/intern/elbeem/intern/isosurface.h b/intern/elbeem/intern/isosurface.h
index 15b923866d3..30fd9adfee1 100644
--- a/intern/elbeem/intern/isosurface.h
+++ b/intern/elbeem/intern/isosurface.h
@@ -67,8 +67,10 @@ class IsoSurface :
/*! set # of subdivisions, this has to be done before init! */
void setSubdivs(int s) {
if(mInitDone) errFatal("IsoSurface::setSubdivs","Changing subdivs after init!", SIMWORLD_INITERROR);
- if(s<1) s=1; if(s>10) s=10;
- mSubdivs = s; }
+ if(s<1) s=1;
+ if(s>10) s=10;
+ mSubdivs = s;
+ }
int getSubdivs() { return mSubdivs;}
/*! set full edge settings, this has to be done before init! */
void setUseFulledgeArrays(bool set) {
diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp
index abce3ea6588..64ee692797b 100644
--- a/intern/ghost/intern/GHOST_ContextWGL.cpp
+++ b/intern/ghost/intern/GHOST_ContextWGL.cpp
@@ -183,6 +183,7 @@ static int weight_pixel_format(PIXELFORMATDESCRIPTOR &pfd, PIXELFORMATDESCRIPTOR
!(pfd.dwFlags & PFD_DOUBLEBUFFER) || /* Blender _needs_ this */
!(pfd.iPixelType == PFD_TYPE_RGBA) ||
(pfd.cDepthBits < 16) ||
+ (pfd.cColorBits > 32) || /* 64 bit formats disable aero */
(pfd.dwFlags & PFD_GENERIC_FORMAT)) /* no software renderers */
{
return 0;
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index 727bc9a01fb..9a2dcfc9687 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -870,18 +870,25 @@ GHOST_SystemX11::processEvent(XEvent *xe)
*
* To address this, we:
*
- * - Try to get a 'number' key_sym using XLookupKeysym (with or without shift modifier).
+ * - Try to get a 'number' key_sym using XLookupKeysym (with virtual shift modifier),
+ * in a very restrictive set of cases.
* - Fallback to XLookupString to get a key_sym from active user-defined keymap.
*
- * Note that this enforces users to use an ascii-compatible keymap with Blender - but at least it gives
- * predictable and consistent results.
+ * Note that:
+ * - This effectively 'lock' main number keys to always output number events (except when using alt-gr).
+ * - This enforces users to use an ascii-compatible keymap with Blender - but at least it gives
+ * predictable and consistent results.
*
* Also, note that nothing in XLib sources [1] makes it obvious why those two functions give different
* key_sym results...
*
* [1] http://cgit.freedesktop.org/xorg/lib/libX11/tree/src/KeyBind.c
*/
- if ((xke->keycode >= 10 && xke->keycode < 20)) {
+ /* Mode_switch 'modifier' is AltGr - when this one or Shift are enabled, we do not want to apply
+ * that 'forced number' hack. */
+ const unsigned int mode_switch_mask = XkbKeysymToModifiers(xke->display, XK_Mode_switch);
+ const unsigned int number_hack_forbidden_kmods_mask = mode_switch_mask | ShiftMask;
+ if ((xke->keycode >= 10 && xke->keycode < 20) && ((xke->state & number_hack_forbidden_kmods_mask) == 0)) {
key_sym = XLookupKeysym(xke, ShiftMask);
if (!((key_sym >= XK_0) && (key_sym <= XK_9))) {
key_sym = XLookupKeysym(xke, 0);
@@ -895,8 +902,29 @@ GHOST_SystemX11::processEvent(XEvent *xe)
ascii = '\0';
}
- if ((gkey = convertXKey(key_sym)) == GHOST_kKeyUnknown) {
- gkey = convertXKey(key_sym_str);
+ /* Only allow a very limited set of keys from XLookupKeysym, all others we take from XLookupString... */
+ gkey = convertXKey(key_sym);
+ switch (gkey) {
+ case GHOST_kKeyRightAlt:
+ case GHOST_kKeyLeftAlt:
+ case GHOST_kKeyRightShift:
+ case GHOST_kKeyLeftShift:
+ case GHOST_kKeyRightControl:
+ case GHOST_kKeyLeftControl:
+ case GHOST_kKeyOS:
+ case GHOST_kKey0:
+ case GHOST_kKey1:
+ case GHOST_kKey2:
+ case GHOST_kKey3:
+ case GHOST_kKey4:
+ case GHOST_kKey5:
+ case GHOST_kKey6:
+ case GHOST_kKey7:
+ case GHOST_kKey8:
+ case GHOST_kKey9:
+ break;
+ default:
+ gkey = convertXKey(key_sym_str);
}
#else
/* In keyboards like latin ones,
@@ -1578,6 +1606,7 @@ convertXKey(KeySym key)
switch (key) {
GXMAP(type, XK_BackSpace, GHOST_kKeyBackSpace);
GXMAP(type, XK_Tab, GHOST_kKeyTab);
+ GXMAP(type, XK_ISO_Left_Tab, GHOST_kKeyTab);
GXMAP(type, XK_Return, GHOST_kKeyEnter);
GXMAP(type, XK_Escape, GHOST_kKeyEsc);
GXMAP(type, XK_space, GHOST_kKeySpace);
diff --git a/intern/itasc/ConstraintSet.cpp b/intern/itasc/ConstraintSet.cpp
index e21cd36e4c8..0baf580ca68 100644
--- a/intern/itasc/ConstraintSet.cpp
+++ b/intern/itasc/ConstraintSet.cpp
@@ -145,27 +145,29 @@ bool ConstraintSet::closeLoop(){
//toggle=!toggle;
//svd_boost_Macie(Jf,U,S,V,B,temp,1e-3*threshold,toggle);
int ret = KDL::svd_eigen_HH(m_Jf,m_U,m_S,m_V,m_temp);
- if(ret<0)
- return false;
+ if(ret<0)
+ return false;
// the reference point and frame of the jacobian is the base frame
// m_externalPose-m_internalPose is the twist to extend the end effector
// to get the required pose => change the reference point to the base frame
Twist twist_delta(diff(m_internalPose,m_externalPose));
twist_delta=twist_delta.RefPoint(-m_internalPose.p);
- for(unsigned int i=0;i<6;i++)
- m_tdelta(i)=twist_delta(i);
- //TODO: use damping in constraintset inversion?
- for(unsigned int i=0;i<6;i++)
- if(m_S(i)<m_threshold){
+ for(unsigned int i=0;i<6;i++)
+ m_tdelta(i)=twist_delta(i);
+ //TODO: use damping in constraintset inversion?
+ for(unsigned int i=0;i<6;i++) {
+ if(m_S(i)<m_threshold){
m_B.row(i).setConstant(0.0);
- }else
- m_B.row(i) = m_U.col(i)/m_S(i);
+ } else {
+ m_B.row(i) = m_U.col(i)/m_S(i);
+ }
+ }
- m_Jf_inv.noalias()=m_V*m_B;
+ m_Jf_inv.noalias()=m_V*m_B;
- m_chi.noalias()+=m_Jf_inv*m_tdelta;
- updateJacobian();
+ m_chi.noalias()+=m_Jf_inv*m_tdelta;
+ updateJacobian();
// m_externalPose-m_internalPose in end effector frame
// this is just to compare the pose, a different formula would work too
return Equal(m_internalPose.Inverse()*m_externalPose,F_identity,m_threshold);
diff --git a/intern/itasc/Scene.cpp b/intern/itasc/Scene.cpp
index 7ed8fc4e63c..5768a994970 100644
--- a/intern/itasc/Scene.cpp
+++ b/intern/itasc/Scene.cpp
@@ -146,11 +146,11 @@ bool Scene::addObject(const std::string& name, Object* object, UncontrolledObjec
bool Scene::addConstraintSet(const std::string& name,ConstraintSet* task,const std::string& object1,const std::string& object2, const std::string& ee1, const std::string& ee2)
{
- //Check if objects exist:
- ObjectMap::iterator object1_it = objects.find(object1);
- ObjectMap::iterator object2_it = objects.find(object2);
- if(object1_it==objects.end()||object2_it==objects.end())
- return false;
+ //Check if objects exist:
+ ObjectMap::iterator object1_it = objects.find(object1);
+ ObjectMap::iterator object2_it = objects.find(object2);
+ if(object1_it==objects.end()||object2_it==objects.end())
+ return false;
int ee1_index = object1_it->second->object->addEndEffector(ee1);
int ee2_index = object2_it->second->object->addEndEffector(ee2);
if (ee1_index < 0 || ee2_index < 0)
@@ -159,11 +159,11 @@ bool Scene::addConstraintSet(const std::string& name,ConstraintSet* task,const s
constraints.insert(ConstraintMap::value_type(name,new ConstraintSet_struct(
task,object1_it,ee1_index,object2_it,ee2_index,
Range(m_ncTotal,task->getNrOfConstraints()),Range(6*m_nsets,6))));
- if(!result.second)
- return false;
- m_ncTotal+=task->getNrOfConstraints();
- m_nsets+=1;
- return true;
+ if(!result.second)
+ return false;
+ m_ncTotal+=task->getNrOfConstraints();
+ m_nsets+=1;
+ return true;
}
bool Scene::addSolver(Solver* _solver){
diff --git a/intern/itasc/WSDLSSolver.cpp b/intern/itasc/WSDLSSolver.cpp
index 6fdd8e6e06c..2514dbb9041 100644
--- a/intern/itasc/WSDLSSolver.cpp
+++ b/intern/itasc/WSDLSSolver.cpp
@@ -60,7 +60,7 @@ bool WSDLSSolver::solve(const e_matrix& A, const e_vector& Wy, const e_vector& y
e_scalar N, M;
// Create the Weighted jacobian
- m_AWq.noalias() = A*Wq;
+ m_AWq.noalias() = A*Wq;
for (i=0; i<m_nc; i++)
m_WyAWq.row(i) = Wy(i)*m_AWq.row(i);
@@ -72,11 +72,11 @@ bool WSDLSSolver::solve(const e_matrix& A, const e_vector& Wy, const e_vector& y
} else {
ret = KDL::svd_eigen_HH(m_WyAWq,m_U,m_S,m_V,m_temp);
}
- if(ret<0)
- return false;
+ if(ret<0)
+ return false;
m_Wy_ydot = Wy.array() * ydot.array();
- m_WqV.noalias() = Wq*m_V;
+ m_WqV.noalias() = Wq*m_V;
qdot.setZero();
e_scalar maxDeltaS = e_scalar(0.0);
e_scalar prevS = e_scalar(0.0);
diff --git a/release/datafiles/locale b/release/datafiles/locale
-Subproject 9628dc1922be2fb6281bc66f5f7512c2a57c294
+Subproject dc166057192ea882b5cc70484d4c8bacd7cb41b
diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png
index fa893b4be0d..60956db2576 100644
--- a/release/datafiles/splash.png
+++ b/release/datafiles/splash.png
Binary files differ
diff --git a/release/datafiles/splash_2x.png b/release/datafiles/splash_2x.png
index f8dd2bbeaf3..3a5000c6bbc 100644
--- a/release/datafiles/splash_2x.png
+++ b/release/datafiles/splash_2x.png
Binary files differ
diff --git a/release/datafiles/splash_scale.sh b/release/datafiles/splash_scale.sh
new file mode 100755
index 00000000000..8a3f2c6d1eb
--- /dev/null
+++ b/release/datafiles/splash_scale.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+# Use this script to generate splash.png from splash_2x.png.
+# Supposed to give best quality image.
+#
+# Based on ImageMagic documentation, which is interesting
+# to read anyway:
+#
+# http://www.imagemagick.org/Usage/filter
+# http://www.imagemagick.org/Usage/filter/nicolas/
+
+convert \
+ splash_2x.png \
+ -colorspace RGB \
+ -filter Cosine \
+ -resize 50% \
+ -colorspace sRGB \
+ splash.png
diff --git a/release/datafiles/splash_template.xcf b/release/datafiles/splash_template.xcf
index b3141471c51..12719b5c155 100644
--- a/release/datafiles/splash_template.xcf
+++ b/release/datafiles/splash_template.xcf
Binary files differ
diff --git a/release/scripts/addons b/release/scripts/addons
-Subproject 407d0ea752b3af73d3f13ba072671bd09eefecb
+Subproject 06dad53c80801e0e0919f086040e3d9c31bbd0a
diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib
-Subproject 9f29e18707917ec5be262431d2e09dbb85332f4
+Subproject 04af69be141a5757fc60b44cc1a5b72db524af3
diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
index c3b72b7075a..fa42778b53f 100644
--- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
+++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py
@@ -153,7 +153,7 @@ class SpellChecker:
"realtime",
"rekey",
"remesh",
- "reprojection",
+ "reprojection", "reproject",
"resize",
"restpose",
"retarget", "retargets", "retargeting", "retargeted",
diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
index 677c7b9960e..4299cf6035d 100644
--- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
+++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py
@@ -20,6 +20,7 @@
from bpy.types import Menu, UIList
+from bpy.app.translations import pgettext_iface as iface_
def gpencil_stroke_placement_settings(context, layout):
@@ -52,6 +53,34 @@ def gpencil_stroke_placement_settings(context, layout):
row.prop(ts, "use_gpencil_stroke_endpoints")
+def gpencil_active_brush_settings_simple(context, layout):
+ brush = context.active_gpencil_brush
+
+ col = layout.column()
+ col.label("Active Brush: ")
+
+ row = col.row(align=True)
+ row.operator_context = 'EXEC_REGION_WIN'
+ row.operator_menu_enum("gpencil.brush_change", "brush", text="", icon='BRUSH_DATA')
+ row.prop(brush, "name", text="")
+
+ col.prop(brush, "line_width", slider=True)
+ row = col.row(align=True)
+ row.prop(brush, "use_random_pressure", text='', icon='RNDCURVE')
+ row.prop(brush, "pen_sensitivity_factor", slider=True)
+ row.prop(brush, "use_pressure", text='', icon='STYLUS_PRESSURE')
+ row = col.row(align=True)
+ row.prop(brush, "use_random_strength", text='', icon='RNDCURVE')
+ row.prop(brush, "strength", slider=True)
+ row.prop(brush, "use_strength_pressure", text='', icon='STYLUS_PRESSURE')
+ row = col.row(align=True)
+ row.prop(brush, "jitter", slider=True)
+ row.prop(brush, "use_jitter_pressure", text='', icon='STYLUS_PRESSURE')
+ row = col.row()
+ row.prop(brush, "angle", slider=True)
+ row.prop(brush, "angle_factor", text="Factor", slider=True)
+
+
class GreasePencilDrawingToolsPanel:
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
@@ -187,6 +216,15 @@ class GreasePencilStrokeEditPanel:
col.operator_menu_enum("gpencil.stroke_arrange", text="Arrange Strokes...", property="direction")
col.operator("gpencil.stroke_change_color", text="Move to Color")
+ if is_3d_view:
+ layout.separator()
+ col = layout.column(align=True)
+ col.operator("gpencil.interpolate", text="Interpolate")
+ col.operator("gpencil.interpolate_sequence", text="Sequence")
+ settings = context.tool_settings.gpencil_sculpt
+ col.prop(settings, "interpolate_all_layers")
+ col.prop(settings, "interpolate_selected_only")
+
layout.separator()
col = layout.column(align=True)
col.operator("gpencil.stroke_join", text="Join").type = 'JOIN'
@@ -197,6 +235,10 @@ class GreasePencilStrokeEditPanel:
if gpd:
col.prop(gpd, "show_stroke_direction", text="Show Directions")
+ if is_3d_view:
+ layout.separator()
+ layout.operator("gpencil.reproject")
+
class GreasePencilBrushPanel:
# subclass must set
@@ -460,29 +502,7 @@ class GPENCIL_PIE_settings_palette(Menu):
col.prop(palcolor, "fill_alpha", text="", slider=True)
# S Brush settings
- col = pie.column()
- col.label("Active Brush: ")
-
- row = col.row()
- row.operator_context = 'EXEC_REGION_WIN'
- row.operator_menu_enum("gpencil.brush_change", "brush", text="", icon='BRUSH_DATA')
- row.prop(brush, "name", text="")
-
- col.prop(brush, "line_width", slider=True)
- row = col.row(align=True)
- row.prop(brush, "use_random_pressure", text='', icon='RNDCURVE')
- row.prop(brush, "pen_sensitivity_factor", slider=True)
- row.prop(brush, "use_pressure", text='', icon='STYLUS_PRESSURE')
- row = col.row(align=True)
- row.prop(brush, "use_random_strength", text='', icon='RNDCURVE')
- row.prop(brush, "strength", slider=True)
- row.prop(brush, "use_strength_pressure", text='', icon='STYLUS_PRESSURE')
- row = col.row(align=True)
- row.prop(brush, "jitter", slider=True)
- row.prop(brush, "use_jitter_pressure", text='', icon='STYLUS_PRESSURE')
- row = col.row()
- row.prop(brush, "angle", slider=True)
- row.prop(brush, "angle_factor", text="Factor", slider=True)
+ gpencil_active_brush_settings_simple(context, pie)
# N - Active Layer
col = pie.column()
@@ -752,6 +772,7 @@ class GPENCIL_MT_palettecolor_specials(Menu):
layout.separator()
layout.operator("gpencil.palettecolor_select", icon='COLOR', text="Select Strokes")
+ layout.operator("gpencil.stroke_change_color", icon='MAN_TRANS', text="Move to Color")
class GreasePencilDataPanel:
@@ -834,7 +855,10 @@ class GreasePencilDataPanel:
split.prop(gpl, "show_points")
# Offsets + Parenting (where available)
- split = layout.split(percentage=0.5)
+ if context.space_data.type == 'VIEW_3D':
+ split = layout.split(percentage=0.5)
+ else:
+ split = layout.column() # parenting is not available in 2D editors...
split.active = not gpl.lock
# Offsets - Color Tint
@@ -868,10 +892,10 @@ class GreasePencilDataPanel:
row.active = not gpl.lock
if gpl.active_frame:
- lock_status = "Locked" if gpl.lock_frame else "Unlocked"
- lock_label = "Frame: %d (%s)" % (gpl.active_frame.frame_number, lock_status)
+ lock_status = iface_("Locked") if gpl.lock_frame else iface_("Unlocked")
+ lock_label = iface_("Frame: %d (%s)") % (gpl.active_frame.frame_number, lock_status)
else:
- lock_label = "Lock Frame"
+ lock_label = iface_("Lock Frame")
row.prop(gpl, "lock_frame", text=lock_label, icon='UNLOCKED')
row.operator("gpencil.active_frame_delete", text="", icon='X')
@@ -956,10 +980,13 @@ class GreasePencilPaletteColorPanel:
sub.operator("gpencil.palettecolor_move", icon='TRIA_UP', text="").direction = 'UP'
sub.operator("gpencil.palettecolor_move", icon='TRIA_DOWN', text="").direction = 'DOWN'
- col.separator()
- sub = col.column(align=True)
+ row = layout.row()
+ sub = row.row(align=True)
+ sub.label(text="Isolate:") # based on active color only
sub.operator("gpencil.palettecolor_isolate", icon='LOCKED', text="").affect_visibility = False
sub.operator("gpencil.palettecolor_isolate", icon='RESTRICT_VIEW_OFF', text="").affect_visibility = True
+ sub = row.row(align=True)
+ sub.label(text="Lock:") # based on other stuff...
sub.operator("gpencil.stroke_lock_color", icon='BORDER_RECT', text="")
sub.operator("gpencil.palette_lock_layer", icon='COLOR', text="")
@@ -967,9 +994,7 @@ class GreasePencilPaletteColorPanel:
if pcolor:
self.draw_palettecolors(layout, pcolor)
- # ----------------------------------------------
# Draw palette colors
- # ----------------------------------------------
def draw_palettecolors(self, layout, pcolor):
# color settings
split = layout.split(percentage=0.5)
@@ -1002,6 +1027,7 @@ class GreasePencilPaletteColorPanel:
class GreasePencilToolsPanel:
+ # For use in "2D" Editors without their own toolbar
# subclass must set
# bl_space_type = 'IMAGE_EDITOR'
# bl_options = {'DEFAULT_CLOSED'}
@@ -1031,4 +1057,8 @@ class GreasePencilToolsPanel:
layout.separator()
layout.separator()
+ gpencil_active_brush_settings_simple(context, layout)
+
+ layout.separator()
+
gpencil_stroke_placement_settings(context, layout)
diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py
index 794ef5189d6..152d4e96d5d 100644
--- a/release/scripts/startup/bl_ui/properties_render.py
+++ b/release/scripts/startup/bl_ui/properties_render.py
@@ -345,7 +345,9 @@ class RENDER_PT_stamp(RenderButtonsPanel, Panel):
layout.prop(rd, "use_stamp")
col = layout.column()
col.active = rd.use_stamp
- col.prop(rd, "stamp_font_size", text="Font Size")
+ row = col.row()
+ row.prop(rd, "stamp_font_size", text="Font Size")
+ row.prop(rd, "use_stamp_labels", text="Draw labels")
row = col.row()
row.column().prop(rd, "stamp_foreground", slider=True)
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index b9cb7f24ebd..1748d1d3738 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -411,6 +411,20 @@ class VIEW3D_MT_uv_map(Menu):
layout.operator("uv.reset")
+class VIEW3D_MT_edit_proportional(Menu):
+ bl_label = "Proportional Editing"
+
+ def draw(self, context):
+ layout = self.layout
+
+ layout.props_enum(context.tool_settings, "proportional_edit")
+
+ layout.separator()
+
+ layout.label("Falloff:")
+ layout.props_enum(context.tool_settings, "proportional_edit_falloff")
+
+
# ********** View menus **********
@@ -2311,8 +2325,7 @@ class VIEW3D_MT_edit_mesh(Menu):
layout.separator()
layout.prop(toolsettings, "use_mesh_automerge")
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("VIEW3D_MT_edit_proportional")
layout.separator()
@@ -2427,6 +2440,8 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
+ with_bullet = bpy.app.build_options.bullet
+
layout.operator("mesh.merge")
layout.operator("mesh.rip_move")
layout.operator("mesh.rip_move_fill")
@@ -2447,7 +2462,8 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
layout.separator()
layout.operator("mesh.bevel").vertex_only = True
- layout.operator("mesh.convex_hull")
+ if with_bullet:
+ layout.operator("mesh.convex_hull")
layout.operator("mesh.vertices_smooth")
layout.operator("mesh.remove_doubles")
@@ -2681,8 +2697,7 @@ def draw_curve(self, context):
layout.separator()
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("VIEW3D_MT_edit_proportional")
layout.separator()
@@ -2841,8 +2856,7 @@ class VIEW3D_MT_edit_meta(Menu):
layout.separator()
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("VIEW3D_MT_edit_proportional")
layout.separator()
@@ -2879,8 +2893,7 @@ class VIEW3D_MT_edit_lattice(Menu):
layout.separator()
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("VIEW3D_MT_edit_proportional")
class VIEW3D_MT_edit_armature(Menu):
@@ -3040,8 +3053,7 @@ class VIEW3D_MT_edit_gpencil(Menu):
layout.separator()
- layout.prop_menu_enum(toolsettings, "proportional_edit")
- layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
+ layout.menu("VIEW3D_MT_edit_proportional")
layout.separator()
diff --git a/source/blender/alembic/intern/abc_hair.cc b/source/blender/alembic/intern/abc_hair.cc
index 45bf9b7ab8a..14bcf6731ea 100644
--- a/source/blender/alembic/intern/abc_hair.cc
+++ b/source/blender/alembic/intern/abc_hair.cc
@@ -59,7 +59,7 @@ AbcHairWriter::AbcHairWriter(Scene *scene,
{
m_psys = psys;
- OCurves curves(parent->alembicXform(), m_name, m_time_sampling);
+ OCurves curves(parent->alembicXform(), psys->name, m_time_sampling);
m_schema = curves.getSchema();
}
diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc
index 322bb906bf5..03014547416 100644
--- a/source/blender/alembic/intern/abc_points.cc
+++ b/source/blender/alembic/intern/abc_points.cc
@@ -67,7 +67,7 @@ AbcPointsWriter::AbcPointsWriter(Scene *scene,
{
m_psys = psys;
- OPoints points(parent->alembicXform(), m_name, m_time_sampling);
+ OPoints points(parent->alembicXform(), psys->name, m_time_sampling);
m_schema = points.getSchema();
}
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index d057cc341f6..477448f1835 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -599,10 +599,6 @@ struct ImportJobData {
ABC_INLINE bool is_mesh_and_strands(const IObject &object)
{
- if (object.getNumChildren() != 2) {
- return false;
- }
-
bool has_mesh = false;
bool has_curve = false;
@@ -624,6 +620,9 @@ ABC_INLINE bool is_mesh_and_strands(const IObject &object)
else if (ICurves::matches(md)) {
has_curve = true;
}
+ else if (IPoints::matches(md)) {
+ has_curve = true;
+ }
}
return has_mesh && has_curve;
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 606488f85cc..789bc8df7e5 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -783,6 +783,7 @@ void DM_vertex_attributes_from_gpu(
struct GPUVertexAttribs *gattribs, DMVertexAttribs *attribs);
void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert, int loop);
+void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs);
void DM_calc_tangents_names_from_gpu(
const struct GPUVertexAttribs *gattribs,
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 483fefbd89c..3ae01d8148a 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -27,8 +27,8 @@
/* these lines are grep'd, watch out for our not-so-awesome regex
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
-#define BLENDER_VERSION 277
-#define BLENDER_SUBVERSION 3
+#define BLENDER_VERSION 278
+#define BLENDER_SUBVERSION 0
/* Several breakages with 270, e.g. constraint deg vs rad */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 6
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 79e500f8ceb..5f759c61bcb 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -80,6 +80,7 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#include "GPU_shader.h"
#ifdef WITH_OPENSUBDIV
+# include "BKE_depsgraph.h"
# include "DNA_userdef_types.h"
#endif
@@ -2282,7 +2283,7 @@ static void editbmesh_calc_modifiers(
{
ModifierData *md, *previewmd = NULL;
float (*deformedVerts)[3] = NULL;
- CustomDataMask mask, previewmask = 0, append_mask = 0;
+ CustomDataMask mask = 0, previewmask = 0, append_mask = 0;
DerivedMesh *dm = NULL, *orcodm = NULL;
int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
CDMaskLink *datamasks, *curr;
@@ -2565,15 +2566,28 @@ static void editbmesh_calc_modifiers(
* we'll be using GPU backend of OpenSubdiv. This is so
* playback performance is kept as high as possible.
*/
-static bool calc_modifiers_skip_orco(const Object *ob)
+static bool calc_modifiers_skip_orco(Scene *scene,
+ Object *ob,
+ bool use_render_params)
{
- const ModifierData *last_md = ob->modifiers.last;
+ ModifierData *last_md = ob->modifiers.last;
+ const int required_mode = use_render_params ? eModifierMode_Render : eModifierMode_Realtime;
if (last_md != NULL &&
- last_md->type == eModifierType_Subsurf)
+ last_md->type == eModifierType_Subsurf &&
+ modifier_isEnabled(scene, last_md, required_mode))
{
+ if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) {
+ return false;
+ }
+ else if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) != 0) {
+ return false;
+ }
+ else if ((DAG_get_eval_flags_for_object(scene, ob) & DAG_EVAL_NEED_CPU) != 0) {
+ return false;
+ }
SubsurfModifierData *smd = (SubsurfModifierData *)last_md;
/* TODO(sergey): Deduplicate this with checks from subsurf_ccg.c. */
- return smd->use_opensubdiv && U.opensubdiv_compute_type != USER_OPENSUBDIV_COMPUTE_NONE;
+ return smd->use_opensubdiv != 0;
}
return false;
}
@@ -2589,7 +2603,7 @@ static void mesh_build_data(
BKE_object_sculpt_modifiers_changed(ob);
#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(ob)) {
+ if (calc_modifiers_skip_orco(scene, ob, false)) {
dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
}
#endif
@@ -2624,7 +2638,7 @@ static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, C
BKE_editmesh_free_derivedmesh(em);
#ifdef WITH_OPENSUBDIV
- if (calc_modifiers_skip_orco(obedit)) {
+ if (calc_modifiers_skip_orco(scene, obedit, false)) {
dataMask &= ~(CD_MASK_ORCO | CD_MASK_PREVIEW_MCOL);
}
#endif
@@ -3793,7 +3807,6 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
glTexCoord3fv(orco);
else
glVertexAttrib3fv(attribs->orco.gl_index, orco);
- glUniform1i(attribs->orco.gl_info_index, 0);
}
/* uv texture coordinates */
@@ -3812,7 +3825,6 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
glTexCoord2fv(uv);
else
glVertexAttrib2fv(attribs->tface[b].gl_index, uv);
- glUniform1i(attribs->tface[b].gl_info_index, 0);
}
/* vertex colors */
@@ -3828,17 +3840,33 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
}
glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
- glUniform1i(attribs->mcol[b].gl_info_index, GPU_ATTR_INFO_SRGB);
}
/* tangent for normal mapping */
for (b = 0; b < attribs->tottang; b++) {
if (attribs->tang[b].array) {
/*const*/ float (*array)[4] = attribs->tang[b].array;
- const float *tang = (array) ? array[a * 4 + vert] : zero;
+ const float *tang = (array) ? array[loop] : zero;
glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
}
- glUniform1i(attribs->tang[b].gl_info_index, 0);
+ }
+}
+
+void DM_draw_attrib_vertex_uniforms(const DMVertexAttribs *attribs)
+{
+ int i;
+ if (attribs->totorco) {
+ glUniform1i(attribs->orco.gl_info_index, 0);
+ }
+ for (i = 0; i < attribs->tottface; i++) {
+ glUniform1i(attribs->tface[i].gl_info_index, 0);
+ }
+ for (i = 0; i < attribs->totmcol; i++) {
+ glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
+ }
+
+ for (i = 0; i < attribs->tottang; i++) {
+ glUniform1i(attribs->tang[i].gl_info_index, 0);
}
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 2d06bc88aa7..f2dd2a3fcf6 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -941,8 +941,10 @@ static void cdDM_drawMappedFacesGLSL(
matnr = new_matnr;
do_draw = setMaterial(matnr + 1, &gattribs);
- if (do_draw)
+ if (do_draw) {
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ DM_draw_attrib_vertex_uniforms(&attribs);
+ }
glBegin(GL_TRIANGLES);
}
@@ -1210,6 +1212,7 @@ static void cdDM_drawMappedFacesMat(
setMaterial(userData, matnr = new_matnr, &gattribs);
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+ DM_draw_attrib_vertex_uniforms(&attribs);
glBegin(GL_TRIANGLES);
}
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 1aba76baa2c..e51a3c3c4b0 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -1410,24 +1410,6 @@ static void emDM_drawMappedFacesTex(
emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
}
-static void emdm_pass_attrib_update_uniforms(const DMVertexAttribs *attribs)
-{
- int i;
- if (attribs->totorco) {
- glUniform1i(attribs->orco.gl_info_index, 0);
- }
- for (i = 0; i < attribs->tottface; i++) {
- glUniform1i(attribs->tface[i].gl_info_index, 0);
- }
- for (i = 0; i < attribs->totmcol; i++) {
- glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
- }
-
- for (i = 0; i < attribs->tottang; i++) {
- glUniform1i(attribs->tang[i].gl_info_index, 0);
- }
-}
-
/**
* \note
*
@@ -1548,7 +1530,7 @@ static void emDM_drawMappedFacesGLSL(
do_draw = setMaterial(matnr = new_matnr, &gattribs);
if (do_draw) {
DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
- emdm_pass_attrib_update_uniforms(&attribs);
+ DM_draw_attrib_vertex_uniforms(&attribs);
if (UNLIKELY(attribs.tottang && bm->elem_index_dirty & BM_LOOP)) {
BM_mesh_elem_index_ensure(bm, BM_LOOP);
}
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 626d389ac2d..8a9cb73c8c9 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -1866,7 +1866,7 @@ void BKE_image_stamp_buf(
display = IMB_colormanagement_display_get_named(display_device);
if (stamp_data_template == NULL) {
- stampdata(scene, camera, &stamp_data, 1);
+ stampdata(scene, camera, &stamp_data, (scene->r.stamp & R_STAMP_HIDE_LABELS) == 0);
}
else {
stampdata_from_template(&stamp_data, scene, stamp_data_template);
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 1a404604eb6..cad5394155d 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -155,8 +155,6 @@ Lamp *localize_lamp(Lamp *la)
if (lan->mtex[a]) {
lan->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_lamp");
memcpy(lan->mtex[a], la->mtex[a], sizeof(MTex));
- /* free lamp decrements */
- id_us_plus((ID *)lan->mtex[a]->tex);
}
}
diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c
index 1830ca0bd90..9b89a2fb807 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -875,8 +875,8 @@ void BKE_libblock_delete(Main *bmain, void *idv)
BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false);
/* First tag all datablocks directly from target lib.
- * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
- * Avoids to have to loop twice. */
+ * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects).
+ * Avoids to have to loop twice. */
for (i = 0; i < base_count; i++) {
ListBase *lb = lbarray[i];
ID *id;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 733e9030056..ba3aef81514 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -2197,8 +2197,10 @@ Mesh *BKE_mesh_new_from_object(
{
Mesh *tmpmesh;
Curve *tmpcu = NULL, *copycu;
- int render = settings == eModifierMode_Render, i;
- int cage = !apply_modifiers;
+ int i;
+ const bool render = (settings == eModifierMode_Render);
+ const bool cage = !apply_modifiers;
+ bool do_mat_id_us = true;
/* perform the mesh extraction based on type */
switch (ob->type) {
@@ -2268,6 +2270,12 @@ Mesh *BKE_mesh_new_from_object(
BKE_mesh_texspace_copy_from_object(tmpmesh, ob);
BKE_libblock_free_us(bmain, tmpobj);
+
+ /* XXX The curve to mesh conversion is convoluted... But essentially, BKE_mesh_from_nurbs_displist()
+ * already transfers the ownership of materials from the temp copy of the Curve ID to the new
+ * Mesh ID, so we do not want to increase materials' usercount later. */
+ do_mat_id_us = false;
+
break;
}
@@ -2315,8 +2323,11 @@ Mesh *BKE_mesh_new_from_object(
if (cage) {
/* copies the data */
tmpmesh = BKE_mesh_copy(bmain, ob->data);
- /* if not getting the original caged mesh, get final derived mesh */
+
+ /* XXX BKE_mesh_copy() already handles materials usercount. */
+ do_mat_id_us = false;
}
+ /* if not getting the original caged mesh, get final derived mesh */
else {
/* Make a dummy mesh, saves copying */
DerivedMesh *dm;
@@ -2360,7 +2371,7 @@ Mesh *BKE_mesh_new_from_object(
tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpcu->mat[i];
- if (tmpmesh->mat[i]) {
+ if (do_mat_id_us && tmpmesh->mat[i]) {
id_us_plus(&tmpmesh->mat[i]->id);
}
}
@@ -2379,7 +2390,7 @@ Mesh *BKE_mesh_new_from_object(
/* are we an object material or data based? */
tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : tmpmb->mat[i];
- if (tmpmesh->mat[i]) {
+ if (do_mat_id_us && tmpmesh->mat[i]) {
id_us_plus(&tmpmesh->mat[i]->id);
}
}
@@ -2399,7 +2410,7 @@ Mesh *BKE_mesh_new_from_object(
/* are we an object material or data based? */
tmpmesh->mat[i] = ob->matbits[i] ? ob->mat[i] : origmesh->mat[i];
- if (tmpmesh->mat[i]) {
+ if (do_mat_id_us && tmpmesh->mat[i]) {
id_us_plus(&tmpmesh->mat[i]->id);
}
}
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 482015d3b26..6794a8e8f93 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -1247,8 +1247,6 @@ static void free_buffers(MovieClip *clip)
IMB_free_anim(clip->anim);
clip->anim = NULL;
}
-
- BKE_animdata_free((ID *) clip, false);
}
void BKE_movieclip_clear_cache(MovieClip *clip)
@@ -1487,6 +1485,7 @@ void BKE_movieclip_free(MovieClip *clip)
free_buffers(clip);
BKE_tracking_free(&clip->tracking);
+ BKE_animdata_free((ID *) clip, false);
}
MovieClip *BKE_movieclip_copy(Main *bmain, MovieClip *clip)
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index b7a25006d08..d9301e2d3d0 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -1139,7 +1139,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
/* increase user numbers */
id_us_plus((ID *)obn->data);
id_us_plus((ID *)obn->gpd);
- id_lib_extern((ID *)obn->dup_group);
+ id_us_plus((ID *)obn->dup_group);
for (a = 0; a < obn->totcol; a++) id_us_plus((ID *)obn->mat[a]);
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index aecaf8537bb..907721b09b6 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -318,16 +318,24 @@ void psys_check_group_weights(ParticleSettings *part)
int current = 0;
if (part->ren_as == PART_DRAW_GR && part->dup_group && part->dup_group->gobject.first) {
- /* first remove all weights that don't have an object in the group */
+ /* First try to find NULL objects from their index,
+ * and remove all weights that don't have an object in the group. */
dw = part->dupliweights.first;
while (dw) {
- if (!BKE_group_object_exists(part->dup_group, dw->ob)) {
- tdw = dw->next;
- BLI_freelinkN(&part->dupliweights, dw);
- dw = tdw;
+ if (dw->ob == NULL || !BKE_group_object_exists(part->dup_group, dw->ob)) {
+ go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
+ if (go) {
+ dw->ob = go->ob;
+ }
+ else {
+ tdw = dw->next;
+ BLI_freelinkN(&part->dupliweights, dw);
+ dw = tdw;
+ }
}
- else
+ else {
dw = dw->next;
+ }
}
/* then add objects in the group to new list */
@@ -877,6 +885,9 @@ static void get_pointcache_keys_for_time(Object *UNUSED(ob), PointCache *cache,
index2 = BKE_ptcache_mem_index_find(pm, index);
index1 = BKE_ptcache_mem_index_find(pm->prev, index);
+ if (index2 < 0) {
+ return;
+ }
BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
if (index1 < 0)
@@ -887,6 +898,9 @@ static void get_pointcache_keys_for_time(Object *UNUSED(ob), PointCache *cache,
else if (cache->mem_cache.first) {
pm = cache->mem_cache.first;
index2 = BKE_ptcache_mem_index_find(pm, index);
+ if (index2 < 0) {
+ return;
+ }
BKE_ptcache_make_particle_key(key2, index2, pm->data, (float)pm->frame);
copy_particle_key(key1, key2, 1);
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 60f1eb6b98c..6d57c5f09e8 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -2820,12 +2820,13 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
int matnr = -1;
int do_draw = 0;
-#define PASSATTRIB(dx, dy, vert) { \
- if (attribs.totorco) \
- index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
- else \
- index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
+#define PASSATTRIB(dx, dy, vert) { \
+ if (attribs.totorco) \
+ index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
+ else \
+ index = 0; \
+ DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
+ DM_draw_attrib_vertex_uniforms(&attribs); \
} (void)0
totpoly = ccgSubSurf_getNumFaces(ss);
@@ -3194,24 +3195,62 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
#ifdef WITH_OPENSUBDIV
if (ccgdm->useGpuBackend) {
- int new_matnr;
- bool draw_smooth;
+ const int level = ccgSubSurf_getSubdivisionLevels(ss);
+ const int face_side = 1 << level;
+ const int grid_side = 1 << (level - 1);
+ const int face_patches = face_side * face_side;
+ const int grid_patches = grid_side * grid_side;
+ const int num_base_faces = ccgSubSurf_getNumGLMeshBaseFaces(ss);
+ int current_patch = 0;
+ int mat_nr = -1;
+ bool draw_smooth = false;
+ int start_draw_patch = -1, num_draw_patches = 0;
GPU_draw_update_fvar_offset(dm);
if (UNLIKELY(ccgSubSurf_prepareGLMesh(ss, true, -1) == false)) {
return;
}
- /* TODO(sergey): Single matierial currently. */
- if (faceFlags) {
- draw_smooth = (faceFlags[0].flag & ME_SMOOTH);
- new_matnr = (faceFlags[0].mat_nr + 1);
+ for (i = 0; i < num_base_faces; ++i) {
+ const int num_face_verts = ccgSubSurf_getNumGLMeshBaseFaceVerts(ss, i);
+ const int num_patches = (num_face_verts == 4) ? face_patches
+ : num_face_verts * grid_patches;
+ int new_matnr;
+ bool new_draw_smooth;
+
+ if (faceFlags) {
+ new_draw_smooth = (faceFlags[i].flag & ME_SMOOTH);
+ new_matnr = (faceFlags[i].mat_nr + 1);
+ }
+ else {
+ new_draw_smooth = true;
+ new_matnr = 1;
+ }
+ if (new_draw_smooth != draw_smooth || new_matnr != mat_nr) {
+ if (num_draw_patches != 0) {
+ setMaterial(userData, mat_nr, &gattribs);
+ glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
+ ccgSubSurf_drawGLMesh(ss,
+ true,
+ start_draw_patch,
+ num_draw_patches);
+ }
+ start_draw_patch = current_patch;
+ num_draw_patches = num_patches;
+ mat_nr = new_matnr;
+ draw_smooth = new_draw_smooth;
+ }
+ else {
+ num_draw_patches += num_patches;
+ }
+ current_patch += num_patches;
}
- else {
- draw_smooth = true;
- new_matnr = 1;
+ if (num_draw_patches != 0) {
+ setMaterial(userData, mat_nr, &gattribs);
+ glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
+ ccgSubSurf_drawGLMesh(ss,
+ true,
+ start_draw_patch,
+ num_draw_patches);
}
- glShadeModel(draw_smooth ? GL_SMOOTH : GL_FLAT);
- setMaterial(userData, new_matnr, &gattribs);
- ccgSubSurf_drawGLMesh(ss, true, -1, -1);
glShadeModel(GL_SMOOTH);
return;
}
@@ -3222,12 +3261,13 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
matnr = -1;
-#define PASSATTRIB(dx, dy, vert) { \
- if (attribs.totorco) \
- index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
- else \
- index = 0; \
- DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
+#define PASSATTRIB(dx, dy, vert) { \
+ if (attribs.totorco) \
+ index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
+ else \
+ index = 0; \
+ DM_draw_attrib_vertex(&attribs, a, index, vert, ((a) * 4) + vert); \
+ DM_draw_attrib_vertex_uniforms(&attribs); \
} (void)0
totface = ccgSubSurf_getNumFaces(ss);
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index de1e3187a70..caa9a1e357f 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -158,8 +158,6 @@ World *localize_world(World *wrld)
if (wrld->mtex[a]) {
wrldn->mtex[a] = MEM_mallocN(sizeof(MTex), "localize_world");
memcpy(wrldn->mtex[a], wrld->mtex[a], sizeof(MTex));
- /* free world decrements */
- id_us_plus((ID *)wrldn->mtex[a]->tex);
}
}
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 40454a93ec8..dd30f267f78 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -2892,8 +2892,8 @@ void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int
int x2 = p2[0];
int y2 = p2[1];
- signed char ix;
- signed char iy;
+ int ix;
+ int iy;
/* if x1 == x2 or y1 == y2, then it does not matter what we set here */
int delta_x = (x2 > x1 ? ((void)(ix = 1), x2 - x1) : ((void)(ix = -1), x1 - x2)) << 1;
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index bd7b7f9cdbd..9d4d40e1eae 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -780,9 +780,10 @@ BLI_INLINE bool parallel_range_next_iter_get(
ParallelRangeState * __restrict state,
int * __restrict iter, int * __restrict count)
{
- uint32_t previter = atomic_fetch_and_add_uint32((uint32_t *)(&state->iter), state->chunk_size);
+ uint32_t uval = atomic_fetch_and_add_uint32((uint32_t *)(&state->iter), state->chunk_size);
+ int previter = *(int32_t*)&uval;
- *iter = (int)previter;
+ *iter = previter;
*count = max_ii(0, min_ii(state->chunk_size, state->stop - previter));
return (previter < state->stop);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index a6c05e9b85c..972520af201 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4106,8 +4106,14 @@ static void lib_link_particlesettings(FileData *fd, Main *main)
if (index_ok) {
/* if we have indexes, let's use them */
for (dw = part->dupliweights.first; dw; dw = dw->next) {
- GroupObject *go = (GroupObject *)BLI_findlink(&part->dup_group->gobject, dw->index);
- dw->ob = go ? go->ob : NULL;
+ /* Do not try to restore pointer here, we have to search for group objects in another
+ * separated step.
+ * Reason is, the used group may be linked from another library, which has not yet
+ * been 'lib_linked'.
+ * Since dw->ob is not considered as an object user (it does not make objet directly linked),
+ * we may have no valid way to retrieve it yet.
+ * See T49273. */
+ dw->ob = NULL;
}
}
else {
@@ -5304,6 +5310,9 @@ static void direct_link_object(FileData *fd, Object *ob)
*/
ob->recalc = 0;
+ /* XXX This should not be needed - but seems like it can happen in some cases, so for now play safe... */
+ ob->proxy_from = NULL;
+
/* loading saved files with editmode enabled works, but for undo we like
* to stay in object mode during undo presses so keep editmode disabled.
*
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 49ef8baa184..dfaa59c4e3f 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -1306,12 +1306,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* set color attributes */
copy_v4_v4(palcolor->color, gpl->color);
copy_v4_v4(palcolor->fill, gpl->fill);
- palcolor->flag = gpl->flag;
+
+ if (gpl->flag & GP_LAYER_HIDE) palcolor->flag |= PC_COLOR_HIDE;
+ if (gpl->flag & GP_LAYER_LOCKED) palcolor->flag |= PC_COLOR_LOCKED;
+ if (gpl->flag & GP_LAYER_ONIONSKIN) palcolor->flag |= PC_COLOR_ONIONSKIN;
+ if (gpl->flag & GP_LAYER_VOLUMETRIC) palcolor->flag |= PC_COLOR_VOLUMETRIC;
+ if (gpl->flag & GP_LAYER_HQ_FILL) palcolor->flag |= PC_COLOR_HQ_FILL;
+
/* set layer opacity to 1 */
gpl->opacity = 1.0f;
+
/* set tint color */
ARRAY_SET_ITEMS(gpl->tintcolor, 0.0f, 0.0f, 0.0f, 0.0f);
-
+
+ /* flush relevant layer-settings to strokes */
for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
/* set stroke to palette and force recalculation */
@@ -1319,14 +1327,15 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
gps->palcolor = NULL;
gps->flag |= GP_STROKE_RECALC_COLOR;
gps->thickness = gpl->thickness;
+
/* set alpha strength to 1 */
for (int i = 0; i < gps->totpoints; i++) {
gps->points[i].strength = 1.0f;
}
-
}
}
}
+
/* set thickness to 0 (now it is a factor to override stroke thickness) */
gpl->thickness = 0.0f;
}
@@ -1339,7 +1348,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
/* ------- end of grease pencil initialization --------------- */
}
- {
+ if (!MAIN_VERSION_ATLEAST(main, 278, 0)) {
if (!DNA_struct_elem_find(fd->filesdna, "MovieTrackingTrack", "float", "weight_stab")) {
MovieClip *clip;
for (clip = main->movieclip.first; clip; clip = clip->id.next) {
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index f8cca5393e2..c3fd202d832 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval.cc
@@ -304,7 +304,7 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers,
deg_task_run_func,
node,
false,
- TASK_PRIORITY_HIGH,
+ TASK_PRIORITY_LOW,
thread_id);
}
}
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 4ef76f5ee25..48786e08f85 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -66,6 +66,7 @@
#include "ED_gpencil.h"
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_space_api.h"
#include "UI_interface_icons.h"
#include "UI_resources.h"
@@ -74,7 +75,6 @@
/* GREASE PENCIL DRAWING */
/* ----- General Defines ------ */
-
/* flags for sflag */
typedef enum eDrawStrokeFlags {
GP_DRAWDATA_NOSTATUS = (1 << 0), /* don't draw status info */
@@ -1338,6 +1338,39 @@ static void gp_draw_onionskins(
}
+/* draw interpolate strokes (used only while operator is running) */
+void ED_gp_draw_interpolation(tGPDinterpolate *tgpi, const int type)
+{
+ tGPDinterpolate_layer *tgpil;
+ float diff_mat[4][4];
+ float color[4];
+
+ int offsx = 0;
+ int offsy = 0;
+ int winx = tgpi->ar->winx;
+ int winy = tgpi->ar->winy;
+
+ UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, color);
+ color[3] = 0.6f;
+ int dflag = 0;
+ /* if 3d stuff, enable flags */
+ if (type == REGION_DRAW_POST_VIEW) {
+ dflag |= (GP_DRAWDATA_ONLY3D | GP_DRAWDATA_NOSTATUS);
+ }
+
+ /* turn on alpha-blending */
+ glEnable(GL_BLEND);
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ /* calculate parent position */
+ ED_gpencil_parent_location(tgpil->gpl, diff_mat);
+ if (tgpil->interFrame) {
+ gp_draw_strokes(tgpi->gpd, tgpil->interFrame, offsx, offsy, winx, winy, dflag, false,
+ tgpil->gpl->thickness, 1.0f, color, true, true, diff_mat);
+ }
+ }
+ glDisable(GL_BLEND);
+}
+
/* loop over gpencil data layers, drawing them */
static void gp_draw_data_layers(
bGPDbrush *brush, float alpha, bGPdata *gpd,
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 3fe53e3d0ab..3d0323dbfb1 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -18,7 +18,7 @@
* The Original Code is Copyright (C) 2008, Blender Foundation, Joshua Leung
* This is a new part of Blender
*
- * Contributor(s): Joshua Leung
+ * Contributor(s): Joshua Leung, Antonio Vazquez
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -72,7 +72,10 @@
#include "ED_gpencil.h"
#include "ED_object.h"
+#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_screen.h"
+#include "ED_space_api.h"
#include "gpencil_intern.h"
@@ -431,16 +434,18 @@ void GPENCIL_OT_copy(wmOperatorType *ot)
static int gp_strokes_paste_poll(bContext *C)
{
- /* 1) Must have GP layer to paste to...
+ /* 1) Must have GP datablock to paste to
+ * - We don't need to have an active layer though, as that can easily get added
+ * - If the active layer is locked, we can't paste there, but that should prompt a warning instead
* 2) Copy buffer must at least have something (though it may be the wrong sort...)
*/
- return (CTX_data_active_gpencil_layer(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
+ return (ED_gpencil_data_get_active(C) != NULL) && (!BLI_listbase_is_empty(&gp_strokes_copypastebuf));
}
-enum {
+typedef enum eGP_PasteMode {
GP_COPY_ONLY = -1,
GP_COPY_MERGE = 1
-};
+} eGP_PasteMode;
static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
{
@@ -448,9 +453,9 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); /* only use active for copy merge */
bGPDframe *gpf;
-
- int type = RNA_enum_get(op->ptr, "type");
-
+
+ eGP_PasteMode type = RNA_enum_get(op->ptr, "type");
+
/* check for various error conditions */
if (gpd == NULL) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data");
@@ -507,39 +512,37 @@ static int gp_strokes_paste_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- /* Ensure we have a frame to draw into
- * NOTE: Since this is an op which creates strokes,
- * we are obliged to add a new frame if one
- * doesn't exist already
- */
-
- bGPDstroke *gps;
- /* Copy each stroke into the layer */
- for (gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
- if (ED_gpencil_stroke_can_use(C, gps)) {
- /* need to verify if layer exist nad frame */
- if (type != GP_COPY_MERGE) {
- gpl = BLI_findstring(&gpd->layers, gps->tmp_layerinfo, offsetof(bGPDlayer, info));
- if (gpl == NULL) {
- /* no layer - use active (only if layer deleted before paste) */
- gpl = CTX_data_active_gpencil_layer(C);
- }
- }
- gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
- if (gpf) {
- bGPDstroke *new_stroke = MEM_dupallocN(gps);
- new_stroke->tmp_layerinfo[0] = '\0';
-
- new_stroke->points = MEM_dupallocN(gps->points);
-
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
- new_stroke->triangles = NULL;
-
- new_stroke->next = new_stroke->prev = NULL;
- BLI_addtail(&gpf->strokes, new_stroke);
+ for (bGPDstroke *gps = gp_strokes_copypastebuf.first; gps; gps = gps->next) {
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ /* Need to verify if layer exists */
+ if (type != GP_COPY_MERGE) {
+ gpl = BLI_findstring(&gpd->layers, gps->tmp_layerinfo, offsetof(bGPDlayer, info));
+ if (gpl == NULL) {
+ /* no layer - use active (only if layer deleted before paste) */
+ gpl = CTX_data_active_gpencil_layer(C);
}
}
+
+ /* Ensure we have a frame to draw into
+ * NOTE: Since this is an op which creates strokes,
+ * we are obliged to add a new frame if one
+ * doesn't exist already
+ */
+ gpf = BKE_gpencil_layer_getframe(gpl, CFRA, true);
+ if (gpf) {
+ bGPDstroke *new_stroke = MEM_dupallocN(gps);
+ new_stroke->tmp_layerinfo[0] = '\0';
+
+ new_stroke->points = MEM_dupallocN(gps->points);
+
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ new_stroke->triangles = NULL;
+
+ new_stroke->next = new_stroke->prev = NULL;
+ BLI_addtail(&gpf->strokes, new_stroke);
+ }
}
+ }
/* updates */
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
@@ -554,7 +557,7 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
{GP_COPY_MERGE, "MERGE", 0, "Merge", ""},
{0, NULL, 0, NULL, NULL}
};
-
+
/* identifiers */
ot->name = "Paste Strokes";
ot->idname = "GPENCIL_OT_paste";
@@ -566,7 +569,8 @@ void GPENCIL_OT_paste(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
+ /* properties */
ot->prop = RNA_def_enum(ot->srna, "type", copy_type, 0, "Type", "");
}
@@ -1881,4 +1885,748 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ************************************************ */
+/* ***************** Reproject Strokes ********************** */
+
+static int gp_strokes_reproject_poll(bContext *C)
+{
+ /* 2 Requirements:
+ * - 1) Editable GP data
+ * - 2) 3D View only (2D editors don't have projection issues)
+ */
+ return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C));
+}
+
+static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ GP_SpaceConversion gsc = {NULL};
+
+ /* init space conversion stuff */
+ gp_point_conversion_init(C, &gsc);
+
+ /* Go through each editable + selected stroke, adjusting each of its points one by one... */
+ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ bGPDspoint *pt;
+ int i;
+ float inverse_diff_mat[4][4];
+
+ /* Compute inverse matrix for unapplying parenting once instead of doing per-point */
+ /* TODO: add this bit to the iteration macro? */
+ if (gpl->parent) {
+ invert_m4_m4(inverse_diff_mat, diff_mat);
+ }
+
+ /* Adjust each point */
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ float xy[2];
+
+ /* 3D to Screenspace */
+ /* Note: We can't use gp_point_to_xy() here because that uses ints for the screenspace
+ * coordinates, resulting in lost precision, which in turn causes stairstepping
+ * artifacts in the final points.
+ */
+ if (gpl->parent == NULL) {
+ gp_point_to_xy_fl(&gsc, gps, pt, &xy[0], &xy[1]);
+ }
+ else {
+ bGPDspoint pt2;
+ gp_point_to_parent_space(pt, diff_mat, &pt2);
+ gp_point_to_xy_fl(&gsc, gps, &pt2, &xy[0], &xy[1]);
+ }
+
+ /* Project screenspace back to 3D space (from current perspective)
+ * so that all points have been treated the same way
+ */
+ gp_point_xy_to_3d(&gsc, scene, xy, &pt->x);
+
+ /* Unapply parent corrections */
+ if (gpl->parent) {
+ mul_m4_v3(inverse_diff_mat, &pt->x);
+ }
+ }
+ }
+ }
+ GP_EDITABLE_STROKES_END;
+
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_reproject(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Reproject Strokes";
+ ot->idname = "GPENCIL_OT_reproject";
+ ot->description = "Reproject the selected strokes from the current viewpoint to get all points on the same plane again "
+ "(e.g. to fix problems from accidental 3D cursor movement, or viewport changes)";
+
+ /* callbacks */
+ ot->exec = gp_strokes_reproject_exec;
+ ot->poll = gp_strokes_reproject_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/* ========= Interpolation operators ========================== */
+/* Helper: Update point with interpolation */
+static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor)
+{
+ bGPDspoint *prev, *pt, *next;
+
+ /* update points */
+ for (int i = 0; i < new_stroke->totpoints; i++) {
+ prev = &gps_from->points[i];
+ pt = &new_stroke->points[i];
+ next = &gps_to->points[i];
+
+ /* Interpolate all values */
+ interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor);
+ pt->pressure = interpf(prev->pressure, next->pressure, factor);
+ pt->strength = interpf(prev->strength, next->strength, factor);
+ CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f);
+ }
+}
+
+/* Helper: Update all strokes interpolated */
+static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi)
+{
+ tGPDinterpolate_layer *tgpil;
+ bGPDstroke *new_stroke, *gps_from, *gps_to;
+ int cStroke;
+ float factor;
+ float shift = tgpi->shift;
+
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ factor = tgpil->factor + shift;
+ for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) {
+ if (new_stroke->totpoints == 0) {
+ continue;
+ }
+ /* get strokes to interpolate */
+ cStroke = BLI_findindex(&tgpil->interFrame->strokes, new_stroke);
+ gps_from = BLI_findlink(&tgpil->prevFrame->strokes, cStroke);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, cStroke);
+ /* update points position */
+ if ((gps_from) && (gps_to)) {
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+ }
+ }
+ }
+
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+}
+
+/* Helper: Verify valid strokes for interpolation */
+static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ int flag = ts->gp_sculpt.flag;
+
+ bGPDlayer *gpl;
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDstroke *gps_from, *gps_to;
+ int fFrame;
+
+ /* get layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* all layers or only active */
+ if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+ /* read strokes */
+ for (gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) {
+ /* only selected */
+ if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ continue;
+ }
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from);
+ gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame);
+ if (gps_to == NULL) {
+ continue;
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Helper: Create internal strokes interpolated */
+static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi)
+{
+ bGPDlayer *gpl;
+ bGPdata *gpd = tgpi->gpd;
+ tGPDinterpolate_layer *tgpil;
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDstroke *gps_from, *gps_to, *new_stroke;
+ int fFrame;
+
+ /* set layers */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* all layers or only active */
+ if (((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+ /* create temp data for each layer */
+ tgpil = NULL;
+ tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer");
+
+ tgpil->gpl = gpl;
+ tgpil->prevFrame = gpl->actframe;
+ tgpil->nextFrame = gpl->actframe->next;
+
+ BLI_addtail(&tgpi->ilayers, tgpil);
+ /* create a new temporary frame */
+ tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe");
+ tgpil->interFrame->framenum = tgpi->cframe;
+
+ /* get interpolation factor */
+ tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1);
+ /* create new strokes data with interpolated points reading original stroke */
+ for (gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
+ bool valid = true;
+ /* only selected */
+ if ((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ valid = false;
+ }
+
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ valid = false;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) {
+ valid = false;
+ }
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from);
+ gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame);
+ if (gps_to == NULL) {
+ valid = false;
+ }
+ /* create new stroke */
+ new_stroke = MEM_dupallocN(gps_from);
+ new_stroke->points = MEM_dupallocN(gps_from->points);
+ new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
+ if (valid) {
+ /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
+ if (gps_from->totpoints > gps_to->totpoints) {
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ new_stroke->totpoints = gps_to->totpoints;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ }
+ /* update points position */
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor);
+ }
+ else {
+ /* need an empty stroke to keep index correct for lookup, but resize to smallest size */
+ new_stroke->totpoints = 0;
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points));
+ new_stroke->tot_triangles = 0;
+ new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles));
+ }
+ /* add to strokes */
+ BLI_addtail(&tgpil->interFrame->strokes, new_stroke);
+ }
+ }
+}
+
+/* Helper: calculate shift based on position of mouse (we only use x-axis for now.
+* since this is more convenient for users to do), and store new shift value
+*/
+static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event)
+{
+ float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f;
+ float mpos = event->x - tgpi->ar->winrct.xmin;
+ if (mpos >= mid) {
+ tgpi->shift = (mpos - mid) / mid;
+ }
+ else {
+ tgpi->shift = -1.0f * (1.0f - (mpos / mid));
+ }
+
+ CLAMP(tgpi->shift, -1.0f, 1.0f);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+}
+
+/* Helper: Draw status message while the user is running the operator */
+static void gpencil_interpolate_status_indicators(tGPDinterpolate *p)
+{
+ Scene *scene = p->scene;
+ char status_str[UI_MAX_DRAW_STR];
+ char msg_str[UI_MAX_DRAW_STR];
+ BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust, Factor"), UI_MAX_DRAW_STR);
+
+ if (hasNumInput(&p->num)) {
+ char str_offs[NUM_STR_REP_LEN];
+
+ outputNumInput(&p->num, str_offs, &scene->unit);
+
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs);
+ }
+ else {
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %d", msg_str, (int)(p->shift * 100.0f));
+ }
+
+ ED_area_headerprint(p->sa, status_str);
+}
+
+/* Helper: Update screen and stroke */
+static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
+{
+ /* update shift indicator in header */
+ gpencil_interpolate_status_indicators(tgpi);
+ /* apply... */
+ tgpi->shift = RNA_float_get(op->ptr, "shift");
+ /* update points position */
+ gp_interpolate_update_strokes(C, tgpi);
+}
+
+/* init new temporary interpolation data */
+static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi)
+{
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata *gpd = CTX_data_gpencil_data(C);
+
+ /* set current scene and window */
+ tgpi->scene = CTX_data_scene(C);
+ tgpi->sa = CTX_wm_area(C);
+ tgpi->ar = CTX_wm_region(C);
+ tgpi->flag = ts->gp_sculpt.flag;
+
+ /* set current frame number */
+ tgpi->cframe = tgpi->scene->r.cfra;
+
+ /* set GP datablock */
+ tgpi->gpd = gpd;
+
+ /* set interpolation weight */
+ tgpi->shift = RNA_float_get(op->ptr, "shift");
+ /* set layers */
+ gp_interpolate_set_points(C, tgpi);
+
+ return 1;
+}
+
+/* Poll handler: check if context is suitable for interpolation */
+static int gpencil_interpolate_poll(bContext *C)
+{
+ bGPdata * gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ /* only 3D view */
+ if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) {
+ return 0;
+ }
+ /* need data to interpolate */
+ if (ELEM(NULL, gpd, gpl)) {
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Allocate memory and initialize values */
+static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi = NULL;
+
+ /* create new context data */
+ tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data");
+
+ /* define initial values */
+ gp_interpolate_set_init_values(C, op, tgpi);
+
+ /* return context data for running operator */
+ return tgpi;
+}
+
+/* Exit and free memory */
+static void gpencil_interpolate_exit(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi = op->customdata;
+ tGPDinterpolate_layer *tgpil;
+
+ /* don't assume that operator data exists at all */
+ if (tgpi) {
+ /* remove drawing handler */
+ if (tgpi->draw_handle_screen) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen);
+ }
+ if (tgpi->draw_handle_3d) {
+ ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d);
+ }
+ /* clear status message area */
+ ED_area_headerprint(tgpi->sa, NULL);
+ /* finally, free memory used by temp data */
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ BKE_gpencil_free_strokes(tgpil->interFrame);
+ MEM_freeN(tgpil->interFrame);
+ }
+
+ BLI_freelistN(&tgpi->ilayers);
+ MEM_freeN(tgpi);
+ }
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* clear pointer */
+ op->customdata = NULL;
+}
+
+/* Cancel handler */
+static void gpencil_interpolate_cancel(bContext *C, wmOperator *op)
+{
+ /* this is just a wrapper around exit() */
+ gpencil_interpolate_exit(C, op);
+}
+
+/* Init interpolation: Allocate memory and set init values */
+static int gpencil_interpolate_init(bContext *C, wmOperator *op)
+{
+ tGPDinterpolate *tgpi;
+ /* check context */
+ tgpi = op->customdata = gp_session_init_interpolation(C, op);
+ if (tgpi == NULL) {
+ /* something wasn't set correctly in context */
+ gpencil_interpolate_exit(C, op);
+ return 0;
+ }
+
+ /* everything is now setup ok */
+ return 1;
+}
+
+/* ********************** custom drawcall api ***************** */
+/* Helper: drawing callback for modal operator in screen mode */
+static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ wmOperator *op = arg;
+ struct tGPDinterpolate *tgpi = op->customdata;
+ ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL);
+}
+
+/* Helper: drawing callback for modal operator in 3d mode */
+static void gpencil_interpolate_draw_3d(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg)
+{
+ wmOperator *op = arg;
+ struct tGPDinterpolate *tgpi = op->customdata;
+ ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW);
+}
+
+/* Invoke handler: Initialize the operator */
+static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ wmWindow *win = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ bGPdata * gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *gpl = CTX_data_active_gpencil_layer(C);
+ tGPDinterpolate *tgpi = NULL;
+
+ /* cannot interpolate if not between 2 frames */
+ if ((gpl->actframe == NULL) || (gpl->actframe->next == NULL)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* cannot interpolate in extremes */
+ if ((gpl->actframe->framenum == scene->r.cfra) || (gpl->actframe->next->framenum == scene->r.cfra)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* need editable strokes */
+ if (!gp_interpolate_check_todo(C, gpd)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable stroke");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* try to initialize context data needed */
+ if (!gpencil_interpolate_init(C, op)) {
+ if (op->customdata)
+ MEM_freeN(op->customdata);
+ return OPERATOR_CANCELLED;
+ }
+ else
+ tgpi = op->customdata;
+
+ /* enable custom drawing handlers. It needs 2 handlers because can be strokes in 3d space and screen space and each handler use different
+ coord system */
+ tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, op, REGION_DRAW_POST_PIXEL);
+ tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, op, REGION_DRAW_POST_VIEW);
+ /* set cursor to indicate modal */
+ WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR);
+ /* update shift indicator in header */
+ gpencil_interpolate_status_indicators(tgpi);
+ WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL);
+
+ /* add a modal handler for this operator */
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Modal handler: Events handling during interactive part */
+static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ tGPDinterpolate *tgpi = op->customdata;
+ wmWindow *win = CTX_wm_window(C);
+ bGPDframe *gpf_dst;
+ bGPDstroke *gps_src, *gps_dst;
+ tGPDinterpolate_layer *tgpil;
+ const bool has_numinput = hasNumInput(&tgpi->num);
+
+ switch (event->type) {
+ case LEFTMOUSE: /* confirm */
+ case RETKEY:
+ {
+ /* return to normal cursor and header status */
+ ED_area_headerprint(tgpi->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* insert keyframes as required... */
+ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) {
+ gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW);
+ gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN;
+
+ /* copy strokes */
+ BLI_listbase_clear(&gpf_dst->strokes);
+ for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) {
+ if (gps_src->totpoints == 0) {
+ continue;
+ }
+ /* make copy of source stroke, then adjust pointer to points too */
+ gps_dst = MEM_dupallocN(gps_src);
+ gps_dst->points = MEM_dupallocN(gps_src->points);
+ gps_dst->triangles = MEM_dupallocN(gps_src->triangles);
+ gps_dst->flag |= GP_STROKE_RECALC_CACHES;
+ BLI_addtail(&gpf_dst->strokes, gps_dst);
+ }
+ }
+ /* clean up temp data */
+ gpencil_interpolate_exit(C, op);
+
+ /* done! */
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY: /* cancel */
+ case RIGHTMOUSE:
+ {
+ /* return to normal cursor and header status */
+ ED_area_headerprint(tgpi->sa, NULL);
+ WM_cursor_modal_restore(win);
+
+ /* clean up temp data */
+ gpencil_interpolate_exit(C, op);
+
+ /* canceled! */
+ return OPERATOR_CANCELLED;
+ }
+ case WHEELUPMOUSE:
+ {
+ tgpi->shift = tgpi->shift + 0.01f;
+ CLAMP(tgpi->shift, -1.0f, 1.0f);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ break;
+ }
+ case WHEELDOWNMOUSE:
+ {
+ tgpi->shift = tgpi->shift - 0.01f;
+ CLAMP(tgpi->shift, -1.0f, 1.0f);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ break;
+ }
+ case MOUSEMOVE: /* calculate new position */
+ {
+ /* only handle mousemove if not doing numinput */
+ if (has_numinput == false) {
+ /* update shift based on position of mouse */
+ gpencil_mouse_update_shift(tgpi, op, event);
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+ }
+ break;
+ }
+ default:
+ if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) {
+ float value;
+
+ /* Grab shift from numeric input, and store this new value (the user see an int) */
+ value = tgpi->shift * 100.0f;
+ applyNumInput(&tgpi->num, &value);
+
+ tgpi->shift = value / 100.0f;
+ CLAMP(tgpi->shift, -1.0f, 1.0f);
+ RNA_float_set(op->ptr, "shift", tgpi->shift);
+
+ /* update screen */
+ gpencil_interpolate_update(C, op, tgpi);
+
+ break;
+ }
+ else {
+ /* unhandled event - allow to pass through */
+ return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH;
+ }
+ }
+
+ /* still running... */
+ return OPERATOR_RUNNING_MODAL;
+}
+
+/* Define modal operator for interpolation */
+void GPENCIL_OT_interpolate(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Interpolation";
+ ot->idname = "GPENCIL_OT_interpolate";
+ ot->description = "Interpolate grease pencil strokes between frames";
+
+ /* api callbacks */
+ ot->invoke = gpencil_interpolate_invoke;
+ ot->modal = gpencil_interpolate_modal;
+ ot->cancel = gpencil_interpolate_cancel;
+ ot->poll = gpencil_interpolate_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
+
+ RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Displacement factor for the interpolate operation", -0.9f, 0.9f);
+}
+
+/* =============== Interpolate sequence ===============*/
+/* Create Sequence Interpolation */
+static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = CTX_data_tool_settings(C);
+ bGPdata * gpd = CTX_data_gpencil_data(C);
+ bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C);
+ bGPDlayer *gpl;
+ bGPDframe *prevFrame, *nextFrame, *interFrame;
+ bGPDstroke *gps_from, *gps_to, *new_stroke;
+ float factor;
+ int cframe, fFrame;
+ int flag = ts->gp_sculpt.flag;
+
+ /* cannot interpolate if not between 2 frames */
+ if ((active_gpl->actframe == NULL) || (active_gpl->actframe->next == NULL)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+ /* cannot interpolate in extremes */
+ if ((active_gpl->actframe->framenum == scene->r.cfra) || (active_gpl->actframe->next->framenum == scene->r.cfra)) {
+ BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* loop all layer to check if need interpolation */
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ /* all layers or only active */
+ if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) {
+ continue;
+ }
+ /* only editable and visible layers are considered */
+ if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) {
+ continue;
+ }
+ /* store extremes */
+ prevFrame = gpl->actframe;
+ nextFrame = gpl->actframe->next;
+ /* Loop over intermediary frames and create the interpolation */
+ for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) {
+ interFrame = NULL;
+
+ /* get interpolation factor */
+ factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1);
+
+ /* create new strokes data with interpolated points reading original stroke */
+ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) {
+ /* only selected */
+ if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) {
+ continue;
+ }
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps_from) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) {
+ continue;
+ }
+ /* get final stroke to interpolate */
+ fFrame = BLI_findindex(&prevFrame->strokes, gps_from);
+ gps_to = BLI_findlink(&nextFrame->strokes, fFrame);
+ if (gps_to == NULL) {
+ continue;
+ }
+ /* create a new frame if needed */
+ if (interFrame == NULL) {
+ interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW);
+ interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN;
+ }
+ /* create new stroke */
+ new_stroke = MEM_dupallocN(gps_from);
+ new_stroke->points = MEM_dupallocN(gps_from->points);
+ new_stroke->triangles = MEM_dupallocN(gps_from->triangles);
+ /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */
+ if (gps_from->totpoints > gps_to->totpoints) {
+ new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints);
+ new_stroke->totpoints = gps_to->totpoints;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+ }
+ /* update points position */
+ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor);
+
+ /* add to strokes */
+ BLI_addtail(&interFrame->strokes, new_stroke);
+ }
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+/* Define sequence interpolation */
+void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Grease Pencil Sequence Interpolation";
+ ot->idname = "GPENCIL_OT_interpolate_sequence";
+ ot->description = "Interpolate full grease pencil strokes sequence between frames";
+
+ /* api callbacks */
+ ot->exec = gpencil_interpolate_seq_exec;
+ ot->poll = gpencil_interpolate_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+/* ========= End Interpolation operators ========================== */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index 5f7cef9a852..c1ed603273a 100644
--- a/source/blender/editors/gpencil/gpencil_intern.h
+++ b/source/blender/editors/gpencil/gpencil_intern.h
@@ -101,6 +101,18 @@ void gp_point_to_xy(GP_SpaceConversion *settings, struct bGPDstroke *gps, struct
int *r_x, int *r_y);
/**
+ * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D)
+ *
+ * Just like gp_point_to_xy(), except the resulting coordinates are floats not ints.
+ * Use this version to solve "stair-step" artifacts which may arise when roundtripping the calculations.
+ *
+ * \param[out] r_x The screen-space x-coordinate of the point
+ * \param[out] r_y The screen-space y-coordinate of the point
+ */
+void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
+ float *r_x, float *r_y);
+
+/**
* Convert point to parent space
*
* \param pt Original point
@@ -183,7 +195,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints);
/**
* Add randomness to stroke
* \param gps Stroke data
-* \param brsuh Brush data
+* \param brush Brush data
*/
void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush);
@@ -199,6 +211,7 @@ EnumPropertyItem *ED_gpencil_brushes_enum_itemf(bContext *C, PointerRNA *UNUSED(
/* Enums of GP palettes */
EnumPropertyItem *ED_gpencil_palettes_enum_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
bool *r_free);
+
/* ***************************************************** */
/* Operator Defines */
@@ -249,6 +262,7 @@ void GPENCIL_OT_snap_to_cursor(struct wmOperatorType *ot);
void GPENCIL_OT_snap_cursor_to_selected(struct wmOperatorType *ot);
void GPENCIL_OT_snap_cursor_to_center(struct wmOperatorType *ot);
+void GPENCIL_OT_reproject(struct wmOperatorType *ot);
/* stroke sculpting -- */
@@ -303,10 +317,10 @@ void GPENCIL_OT_palette_add(struct wmOperatorType *ot);
void GPENCIL_OT_palette_remove(struct wmOperatorType *ot);
void GPENCIL_OT_palette_change(struct wmOperatorType *ot);
void GPENCIL_OT_palette_lock_layer(struct wmOperatorType *ot);
+
void GPENCIL_OT_palettecolor_add(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_remove(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_isolate(struct wmOperatorType *ot);
-
void GPENCIL_OT_palettecolor_hide(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_reveal(struct wmOperatorType *ot);
void GPENCIL_OT_palettecolor_lock_all(struct wmOperatorType *ot);
@@ -321,7 +335,12 @@ void gpencil_undo_init(struct bGPdata *gpd);
void gpencil_undo_push(struct bGPdata *gpd);
void gpencil_undo_finish(void);
-/******************************************************* */
+/* interpolation ---------- */
+
+void GPENCIL_OT_interpolate(struct wmOperatorType *ot);
+void GPENCIL_OT_interpolate_sequence(struct wmOperatorType *ot);
+
+/* ****************************************************** */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */
/* XXX - TODO: replace this with the modern bAnimListElem... */
@@ -343,7 +362,7 @@ typedef struct bActListElem {
short ownertype; /* type of owner */
} bActListElem;
-/******************************************************* */
+/* ****************************************************** */
/* FILTER ACTION DATA - METHODS/TYPES */
/* filtering flags - under what circumstances should a channel be added */
@@ -366,6 +385,9 @@ typedef enum ACTCONT_TYPES {
ACTCONT_GPENCIL
} ACTCONT_TYPES;
+/* ****************************************************** */
+/* Stroke Iteration Utilities */
+
/**
* Iterate over all editable strokes in the current context,
* stopping on each usable layer + stroke pair (i.e. gpl and gps)
@@ -401,4 +423,6 @@ typedef enum ACTCONT_TYPES {
CTX_DATA_END; \
} (void)0
+/* ****************************************************** */
+
#endif /* __GPENCIL_INTERN_H__ */
diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c
index 50f4e795d70..e5d5bdbc831 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -79,7 +79,6 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf)
RNA_enum_set(kmi->ptr, "mode", GP_PAINTMODE_ERASER);
RNA_boolean_set(kmi->ptr, "wait_for_input", false);
-
/* Tablet Mappings for Drawing ------------------ */
/* For now, only support direct drawing using the eraser, as most users using a tablet
* may still want to use that as their primary pointing device!
@@ -144,7 +143,10 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_radial_control", FKEY, KM_PRESS, KM_CTRL, 0);
RNA_string_set(kmi->ptr, "data_path_primary", "user_preferences.edit.grease_pencil_eraser_radius");
-
+ /* Interpolation */
+ WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate", EKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "GPENCIL_OT_interpolate_sequence", EKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+
/* Sculpting ------------------------------------- */
/* Brush-Based Editing:
@@ -375,6 +377,8 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_snap_to_cursor);
WM_operatortype_append(GPENCIL_OT_snap_cursor_to_selected);
+ WM_operatortype_append(GPENCIL_OT_reproject);
+
WM_operatortype_append(GPENCIL_OT_brush_paint);
/* Editing (Buttons) ------------ */
@@ -431,6 +435,10 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_brush_select);
/* Editing (Time) --------------- */
+
+ /* Interpolation */
+ WM_operatortype_append(GPENCIL_OT_interpolate);
+ WM_operatortype_append(GPENCIL_OT_interpolate_sequence);
}
void ED_operatormacros_gpencil(void)
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 70a4b2904ed..cc45cbd82af 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -2310,6 +2310,7 @@ static void gpencil_move_last_stroke_to_back(bContext *C)
static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
tGPsdata *p = op->customdata;
+ ToolSettings *ts = CTX_data_tool_settings(C);
int estate = OPERATOR_PASS_THROUGH; /* default exit state - pass through to support MMB view nav, etc. */
/* if (event->type == NDOF_MOTION)
@@ -2363,9 +2364,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* exit() ends the current stroke before cleaning up */
/* printf("\t\tGP - end of paint op + end of stroke\n"); */
/* if drawing polygon and enable on back, must move stroke */
- if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
}
}
p->status = GP_STATUS_DONE;
@@ -2425,9 +2428,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
else {
/* printf("\t\tGP - end of stroke + op\n"); */
/* if drawing polygon and enable on back, must move stroke */
- if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
}
}
p->status = GP_STATUS_DONE;
@@ -2511,9 +2516,11 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
* region (as above)
*/
/* if drawing polygon and enable on back, must move stroke */
- if ((p->scene->toolsettings->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
- if (p->flags & GP_PAINTFLAG_STROKEADDED) {
- gpencil_move_last_stroke_to_back(C);
+ if (ts) {
+ if ((ts->gpencil_flags & GP_TOOL_FLAG_PAINT_ONBACK) && (p->paintmode == GP_PAINTMODE_DRAW_POLY)) {
+ if (p->flags & GP_PAINTFLAG_STROKEADDED) {
+ gpencil_move_last_stroke_to_back(C);
+ }
}
}
p->status = GP_STATUS_DONE;
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 793ed2a07d0..7a9ad2b32c0 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -124,6 +124,17 @@ void gpencil_undo_init(bGPdata *gpd)
gpencil_undo_push(gpd);
}
+static void gpencil_undo_free_node(bGPundonode *undo_node)
+{
+ /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
+ * or else the real copy will segfault when accessed
+ */
+ undo_node->gpd->adt = NULL;
+
+ BKE_gpencil_free(undo_node->gpd, false);
+ MEM_freeN(undo_node->gpd);
+}
+
void gpencil_undo_push(bGPdata *gpd)
{
bGPundonode *undo_node;
@@ -137,20 +148,36 @@ void gpencil_undo_push(bGPdata *gpd)
while (undo_node) {
bGPundonode *next_node = undo_node->next;
- /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
- * or else the real copy will segfault when accessed
- */
- undo_node->gpd->adt = NULL;
-
- BKE_gpencil_free(undo_node->gpd, false);
- MEM_freeN(undo_node->gpd);
-
+ gpencil_undo_free_node(undo_node);
BLI_freelinkN(&undo_nodes, undo_node);
undo_node = next_node;
}
}
+ /* limit number of undo steps to the maximum undo steps
+ * - to prevent running out of memory during **really**
+ * long drawing sessions (triggering swapping)
+ */
+ /* TODO: Undo-memory constraint is not respected yet, but can be added if we have any need for it */
+ if (U.undosteps && !BLI_listbase_is_empty(&undo_nodes)) {
+ /* remove anything older than n-steps before cur_node */
+ int steps = 0;
+
+ undo_node = (cur_node) ? cur_node : undo_nodes.last;
+ while (undo_node) {
+ bGPundonode *prev_node = undo_node->prev;
+
+ if (steps >= U.undosteps) {
+ gpencil_undo_free_node(undo_node);
+ BLI_freelinkN(&undo_nodes, undo_node);
+ }
+
+ steps++;
+ undo_node = prev_node;
+ }
+ }
+
/* create new undo node */
undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node");
undo_node->gpd = BKE_gpencil_data_duplicate(G.main, gpd, true);
@@ -165,14 +192,7 @@ void gpencil_undo_finish(void)
bGPundonode *undo_node = undo_nodes.first;
while (undo_node) {
- /* HACK: animdata wasn't duplicated, so it shouldn't be freed here,
- * or else the real copy will segfault when accessed
- */
- undo_node->gpd->adt = NULL;
-
- BKE_gpencil_free(undo_node->gpd, false);
- MEM_freeN(undo_node->gpd);
-
+ gpencil_undo_free_node(undo_node);
undo_node = undo_node->next;
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index ed9a591dcbe..564ba639983 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -628,6 +628,63 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
}
}
+/* Convert Grease Pencil points to screen-space values (as floats)
+ * WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn
+ */
+void gp_point_to_xy_fl(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
+ float *r_x, float *r_y)
+{
+ ARegion *ar = gsc->ar;
+ View2D *v2d = gsc->v2d;
+ rctf *subrect = gsc->subrect;
+ float xyval[2];
+
+ /* sanity checks */
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+
+
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ if (ED_view3d_project_float_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
+ *r_x = xyval[0];
+ *r_y = xyval[1];
+ }
+ else {
+ *r_x = 0.0f;
+ *r_y = 0.0f;
+ }
+ }
+ else if (gps->flag & GP_STROKE_2DSPACE) {
+ float vec[3] = {pt->x, pt->y, 0.0f};
+ int t_x, t_y;
+
+ mul_m4_v3(gsc->mat, vec);
+ UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], &t_x, &t_y);
+
+ if ((t_x == t_y) && (t_x == V2D_IS_CLIPPED)) {
+ /* XXX: Or should we just always use the values as-is? */
+ *r_x = 0.0f;
+ *r_y = 0.0f;
+ }
+ else {
+ *r_x = (float)t_x;
+ *r_y = (float)t_y;
+ }
+ }
+ else {
+ if (subrect == NULL) {
+ /* normal 3D view (or view space) */
+ *r_x = (pt->x / 100.0f * ar->winx);
+ *r_y = (pt->y / 100.0f * ar->winy);
+ }
+ else {
+ /* camera view, use subrect */
+ *r_x = ((pt->x / 100.0f) * BLI_rctf_size_x(subrect)) + subrect->xmin;
+ *r_y = ((pt->y / 100.0f) * BLI_rctf_size_y(subrect)) + subrect->ymin;
+ }
+ }
+}
+
/**
* Project screenspace coordinates to 3D-space
*
@@ -883,10 +940,12 @@ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush)
float normal[3];
cross_v3_v3v3(normal, v1, v2);
normalize_v3(normal);
+
/* get orthogonal vector to plane to rotate random effect */
float ortho[3];
cross_v3_v3v3(ortho, v1, normal);
normalize_v3(ortho);
+
/* Read all points and apply shift vector (first and last point not modified) */
for (int i = 1; i < gps->totpoints - 1; ++i) {
bGPDspoint *pt = &gps->points[i];
@@ -955,8 +1014,8 @@ bool ED_gpencil_stroke_minmax(
}
return changed;
}
-/* Dynamic Enums of GP Brushes */
+/* Dynamic Enums of GP Brushes */
EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
bool *r_free)
@@ -990,8 +1049,8 @@ EnumPropertyItem *ED_gpencil_brushes_enum_itemf(
return item;
}
-/* Dynamic Enums of GP Palettes */
+/* Dynamic Enums of GP Palettes */
EnumPropertyItem *ED_gpencil_palettes_enum_itemf(
bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop),
bool *r_free)
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index d526b0841cc..e53f29ef6b7 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -30,6 +30,8 @@
#ifndef __ED_GPENCIL_H__
#define __ED_GPENCIL_H__
+#include "ED_numinput.h"
+
struct ID;
struct ListBase;
struct bContext;
@@ -51,6 +53,33 @@ struct wmKeyConfig;
/* ------------- Grease-Pencil Helpers ---------------- */
+typedef struct tGPDinterpolate_layer {
+ struct tGPDinterpolate_layer *next, *prev;
+
+ struct bGPDlayer *gpl; /* layer */
+ struct bGPDframe *prevFrame; /* frame before current frame (interpolate-from) */
+ struct bGPDframe *nextFrame; /* frame after current frame (interpolate-to) */
+ struct bGPDframe *interFrame; /* interpolated frame */
+ float factor; /* interpolate factor */
+
+} tGPDinterpolate_layer;
+
+/* Temporary interpolate operation data */
+typedef struct tGPDinterpolate {
+ struct Scene *scene; /* current scene from context */
+ struct ScrArea *sa; /* area where painting originated */
+ struct ARegion *ar; /* region where painting originated */
+ struct bGPdata *gpd; /* current GP datablock */
+
+ int cframe; /* current frame number */
+ ListBase ilayers; /* (tGPDinterpolate_layer) layers to be interpolated */
+ float shift; /* -1/1 value for determining the displacement influence */
+ int flag; /* flag from toolsettings */
+
+ NumInput num; /* numeric input */
+ void *draw_handle_3d; /* handle for drawing strokes while operator is running 3d stuff */
+ void *draw_handle_screen; /* handle for drawing strokes while operator is running screen stuff */
+} tGPDinterpolate;
/* Temporary 'Stroke Point' data
*
@@ -118,6 +147,7 @@ void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d);
void ED_gpencil_draw_view3d(struct wmWindowManager *wm, struct Scene *scene, struct View3D *v3d, struct ARegion *ar, bool only3d);
void ED_gpencil_draw_ex(struct Scene *scene, struct bGPdata *gpd, int winx, int winy,
const int cfra, const char spacetype);
+void ED_gp_draw_interpolation(struct tGPDinterpolate *tgpi, const int type);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
bool ED_gplayer_frames_looper(struct bGPDlayer *gpl, struct Scene *scene,
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index f9a22429fc2..00558a3a787 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -30,6 +30,8 @@
#define NUM_STR_REP_LEN 64
#define NUM_MAX_ELEMENTS 3
+struct wmEvent;
+
typedef struct NumInput {
short idx_max; /* idx_max < NUM_MAX_ELEMENTS */
int unit_sys;
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 1f053c806b0..26a6fdd7d1f 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -393,6 +393,8 @@ struct uiLayout *UI_popup_menu_layout(uiPopupMenu *head);
void UI_popup_menu_reports(struct bContext *C, struct ReportList *reports) ATTR_NONNULL();
int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportList *reports) ATTR_NONNULL(1, 2);
+void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable);
+
/* Pie menus */
typedef struct uiPieMenu uiPieMenu;
@@ -1019,6 +1021,12 @@ void ED_keymap_ui(struct wmKeyConfig *keyconf);
void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop);
int UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event);
+/* UI_OT_space_context_cycle direction */
+enum {
+ SPACE_CONTEXT_CYCLE_PREV,
+ SPACE_CONTEXT_CYCLE_NEXT,
+};
+
bool UI_context_copy_to_selected_list(
struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
struct ListBase *r_lb, bool *r_use_path_from_id, char **r_path);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index d05a80bed62..4972e16bf2e 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -9921,6 +9921,17 @@ static int ui_handle_menus_recursive(
return retval;
}
+/**
+ * Allow setting menu return value from externals. E.g. WM might need to do this for exiting files correctly.
+ */
+void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable)
+{
+ uiPopupBlockHandle *menu = block->handle;
+ if (menu) {
+ menu->menuretval = enable ? (menu->menuretval | retval) : (menu->menuretval & retval);
+ }
+}
+
/* *************** UI event handlers **************** */
static int ui_region_handler(bContext *C, const wmEvent *event, void *UNUSED(userdata))
@@ -10163,7 +10174,11 @@ static void ui_popup_handler_remove(bContext *C, void *userdata)
{
uiPopupBlockHandle *menu = userdata;
- if (menu->cancel_func) {
+ /* More correct would be to expect UI_RETURN_CANCEL here, but not wanting to
+ * cancel when removing handlers because of file exit is a rare exception.
+ * So instead of setting cancel flag for all menus before removing handlers,
+ * just explicitly flag menu with UI_RETURN_OK to avoid cancelling it. */
+ if ((menu->menuretval & UI_RETURN_OK) == 0 && menu->cancel_func) {
menu->cancel_func(C, menu->popup_arg);
}
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 1af6d902b18..cb539bb1c5d 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -1082,6 +1082,78 @@ static void UI_OT_drop_color(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected ");
}
+/* ------------------------------------------------------------------------- */
+
+static EnumPropertyItem space_context_cycle_direction[] = {
+ {SPACE_CONTEXT_CYCLE_PREV, "PREV", 0, "Previous", ""},
+ {SPACE_CONTEXT_CYCLE_NEXT, "NEXT", 0, "Next", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int space_context_cycle_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ return ELEM(sa->spacetype, SPACE_BUTS, SPACE_USERPREF);
+}
+
+/**
+ * Helper to get the correct RNA pointer/property pair for changing
+ * the display context of active space type in \sa.
+ */
+static void context_cycle_prop_get(
+ bScreen *screen, const ScrArea *sa,
+ PointerRNA *r_ptr, PropertyRNA **r_prop)
+{
+ const char *propname;
+
+ switch (sa->spacetype) {
+ case SPACE_BUTS:
+ RNA_pointer_create(&screen->id, &RNA_SpaceProperties, sa->spacedata.first, r_ptr);
+ propname = "context";
+ break;
+ case SPACE_USERPREF:
+ RNA_pointer_create(NULL, &RNA_UserPreferences, &U, r_ptr);
+ propname = "active_section";
+ break;
+ }
+
+ *r_prop = RNA_struct_find_property(r_ptr, propname);
+}
+
+static int space_context_cycle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ const int direction = RNA_enum_get(op->ptr, "direction");
+
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ context_cycle_prop_get(CTX_wm_screen(C), CTX_wm_area(C), &ptr, &prop);
+
+ const int old_context = RNA_property_enum_get(&ptr, prop);
+ const int new_context = RNA_property_enum_step(
+ C, &ptr, prop, old_context,
+ direction == SPACE_CONTEXT_CYCLE_PREV ? -1 : 1);
+ RNA_property_enum_set(&ptr, prop, new_context);
+ RNA_property_update(C, &ptr, prop);
+
+ return OPERATOR_FINISHED;
+}
+
+static void UI_OT_space_context_cycle(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Cycle Space Context";
+ ot->description = "Cycle through the editor context by activating the next/previous one";
+ ot->idname = "UI_OT_space_context_cycle";
+
+ /* api callbacks */
+ ot->invoke = space_context_cycle_invoke;
+ ot->poll = space_context_cycle_poll;
+
+ ot->flag = 0;
+
+ RNA_def_enum(ot->srna, "direction", space_context_cycle_direction, SPACE_CONTEXT_CYCLE_NEXT, "Direction",
+ "Direction to cycle through");
+}
/* ********************************************************* */
@@ -1102,6 +1174,7 @@ void ED_operatortypes_ui(void)
WM_operatortype_append(UI_OT_edittranslation_init);
#endif
WM_operatortype_append(UI_OT_reloadtranslation);
+ WM_operatortype_append(UI_OT_space_context_cycle);
/* external */
WM_operatortype_append(UI_OT_eyedropper_color);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 79961eae79d..c131bcb8e14 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1841,6 +1841,52 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
#undef USE_FLAT_INACTIVE
}
+static int ui_handle_panel_category_cycling(const wmEvent *event, ARegion *ar, const uiBut *active_but)
+{
+ const bool is_mousewheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE);
+ const bool inside_tabregion = (event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax);
+
+ /* if mouse is inside non-tab region, ctrl key is required */
+ if (is_mousewheel && !event->ctrl && !inside_tabregion)
+ return WM_UI_HANDLER_CONTINUE;
+
+
+ if (active_but && ui_but_supports_cycling(active_but)) {
+ /* skip - exception to make cycling buttons
+ * using ctrl+mousewheel work in tabbed regions */
+ }
+ else {
+ const char *category = UI_panel_category_active_get(ar, false);
+ if (LIKELY(category)) {
+ PanelCategoryDyn *pc_dyn = UI_panel_category_find(ar, category);
+ if (LIKELY(pc_dyn)) {
+ if (is_mousewheel) {
+ /* we can probably get rid of this and only allow ctrl+tabbing */
+ pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev;
+ }
+ else {
+ const bool backwards = event->shift;
+ pc_dyn = backwards ? pc_dyn->prev : pc_dyn->next;
+ if (!pc_dyn) {
+ /* proper cyclic behavior, back to first/last category (only used for ctrl+tab) */
+ pc_dyn = backwards ? ar->panels_category.last : ar->panels_category.first;
+ }
+ }
+
+ if (pc_dyn) {
+ /* intentionally don't reset scroll in this case,
+ * this allows for quick browsing between tabs */
+ UI_panel_category_active_set(ar, pc_dyn->idname);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ return WM_UI_HANDLER_CONTINUE;
+}
+
/* XXX should become modal keymap */
/* AKey is opening/closing panels, independent of button state now */
@@ -1853,6 +1899,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons
retval = WM_UI_HANDLER_CONTINUE;
+ /* handle category tabs */
if (has_category_tabs) {
if (event->val == KM_PRESS) {
if (event->type == LEFTMOUSE) {
@@ -1867,32 +1914,9 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar, cons
retval = WM_UI_HANDLER_BREAK;
}
}
- else if (ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
- /* mouse wheel cycle tabs */
-
- /* first check if the mouse is in the tab region */
- if (event->ctrl || (event->mval[0] < ((PanelCategoryDyn *)ar->panels_category.first)->rect.xmax)) {
- if (active_but && ui_but_supports_cycling(active_but)) {
- /* skip - exception to make cycling buttons
- * using ctrl+mousewheel work in tabbed regions */
- }
- else {
- const char *category = UI_panel_category_active_get(ar, false);
- if (LIKELY(category)) {
- PanelCategoryDyn *pc_dyn = UI_panel_category_find(ar, category);
- if (LIKELY(pc_dyn)) {
- pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev;
- if (pc_dyn) {
- /* intentionally don't reset scroll in this case,
- * this allows for quick browsing between tabs */
- UI_panel_category_active_set(ar, pc_dyn->idname);
- ED_region_tag_redraw(ar);
- }
- }
- }
- retval = WM_UI_HANDLER_BREAK;
- }
- }
+ else if ((event->type == TABKEY && event->ctrl) || ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) {
+ /* cycle tabs */
+ retval = ui_handle_panel_category_cycling(event, ar, active_but);
}
}
}
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index c507401b9a0..4ea5e2092b6 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -73,38 +73,6 @@
#define MENU_PADDING (int)(0.2f * UI_UNIT_Y)
#define MENU_BORDER (int)(0.3f * U.widget_unit)
-static int rna_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int direction)
-{
- EnumPropertyItem *item_array;
- int totitem;
- bool free;
- int value;
- int i, i_init;
- int step = (direction < 0) ? -1 : 1;
- int step_tot = 0;
-
- RNA_property_enum_items((bContext *)C, ptr, prop, &item_array, &totitem, &free);
- value = RNA_property_enum_get(ptr, prop);
- i = RNA_enum_from_value(item_array, value);
- i_init = i;
-
- do {
- i = mod_i(i + step, totitem);
- if (item_array[i].identifier[0]) {
- step_tot += step;
- }
- } while ((i != i_init) && (step_tot != direction));
-
- if (i != i_init) {
- value = item_array[i].value;
- }
-
- if (free) {
- MEM_freeN(item_array);
- }
-
- return value;
-}
bool ui_but_menu_step_poll(const uiBut *but)
{
@@ -122,7 +90,8 @@ int ui_but_menu_step(uiBut *but, int direction)
return but->menu_step_func(but->block->evil_C, direction, but->poin);
}
else {
- return rna_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, direction);
+ const int curval = RNA_property_enum_get(&but->rnapoin, but->rnaprop);
+ return RNA_property_enum_step(but->block->evil_C, &but->rnapoin, but->rnaprop, curval, direction);
}
}
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 302ca407add..a81add7a86e 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -145,6 +145,7 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->em = em;
opdata->is_modal = is_modal;
opdata->value_mode = OFFSET_VALUE;
+ opdata->segments = (float) RNA_int_get(op->ptr, "segments");
pixels_per_inch = U.dpi * U.pixelsize;
for (i = 0; i < NUM_VALUE_KINDS; i++) {
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 999d5b278ee..7e31deba2c7 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -3121,8 +3121,10 @@ static void mesh_separate_material_assign_mat_nr(Main *bmain, Object *ob, const
BKE_material_resize_id(bmain, obdata, 1, true);
ob->mat[0] = ma_ob;
+ id_us_plus((ID *)ma_ob);
ob->matbits[0] = matbit;
(*matarar)[0] = ma_obdata;
+ id_us_plus((ID *)ma_obdata);
}
else {
BKE_material_clear_id(bmain, obdata, true);
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 43f1b7b5e31..303846bb053 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -999,7 +999,7 @@ static int group_instance_add_exec(bContext *C, wmOperator *op)
Object *ob = ED_object_add_type(C, OB_EMPTY, group->id.name + 2, loc, rot, false, layer);
ob->dup_group = group;
ob->transflag |= OB_DUPLIGROUP;
- id_lib_extern(&group->id);
+ id_us_plus(&group->id);
/* works without this except if you try render right after, see: 22027 */
DAG_relations_tag_update(bmain);
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 3dc7d8ebd4b..111afcdc7a7 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -910,7 +910,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event)
base->object->dup_group = ob->dup_group;
if (ob->dup_group)
- id_lib_extern(&ob->dup_group->id);
+ id_us_plus(&ob->dup_group->id);
}
else if (event == 7) { /* mass */
base->object->mass = ob->mass;
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 067a5ad2b49..82c6a14eb7f 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1609,7 +1609,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
case MAKE_LINKS_DUPLIGROUP:
ob_dst->dup_group = ob_src->dup_group;
if (ob_dst->dup_group) {
- id_lib_extern(&ob_dst->dup_group->id);
+ id_us_plus(&ob_dst->dup_group->id);
ob_dst->transflag |= OB_DUPLIGROUP;
}
break;
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index b4f3426677a..ddbf59b2cf7 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -526,7 +526,7 @@ static Scene *preview_prepare_scene(Main *bmain, Scene *scene, ID *id, int id_ty
BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true);
}
}
-
+
return sce;
}
@@ -863,8 +863,6 @@ static void shader_preview_free(void *customdata)
/* get rid of copied world */
BLI_remlink(&pr_main->world, sp->worldcopy);
- /* T32865 - we need to unlink the texture copies, unlike for materials */
- BKE_libblock_relink_ex(pr_main, sp->worldcopy, NULL, NULL, true);
BKE_world_free(sp->worldcopy);
properties = IDP_GetProperties((ID *)sp->worldcopy, false);
@@ -881,7 +879,6 @@ static void shader_preview_free(void *customdata)
/* get rid of copied lamp */
BLI_remlink(&pr_main->lamp, sp->lampcopy);
- BKE_libblock_relink_ex(pr_main, sp->lampcopy, NULL, NULL, true);
BKE_lamp_free(sp->lampcopy);
properties = IDP_GetProperties((ID *)sp->lampcopy, false);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 6dbb5db53d0..e446194a1da 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -4331,7 +4331,13 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
-
+
+ /* UI */
+ kmi = WM_keymap_add_item(keymap, "UI_OT_space_context_cycle", TABKEY, KM_PRESS, KM_CTRL, 0);
+ RNA_enum_set(kmi->ptr, "direction", SPACE_CONTEXT_CYCLE_NEXT);
+ kmi = WM_keymap_add_item(keymap, "UI_OT_space_context_cycle", TABKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
+ RNA_enum_set(kmi->ptr, "direction", SPACE_CONTEXT_CYCLE_PREV);
+
/* tests */
WM_keymap_add_item(keymap, "SCREEN_OT_region_quadview", QKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 03f2e146b7d..52c39e5c7a1 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -217,32 +217,56 @@ static void SOUND_OT_open_mono(wmOperatorType *ot)
/* ******************************************************* */
-static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op))
+static void sound_update_animation_flags(Scene *scene);
+
+static int sound_update_animation_flags_cb(Sequence *seq, void *user_data)
{
- Sequence *seq;
- Scene *scene = CTX_data_scene(C);
struct FCurve *fcu;
+ Scene *scene = (Scene *)user_data;
bool driven;
- SEQ_BEGIN(scene->ed, seq)
- {
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, &driven);
- if (fcu || driven)
- seq->flag |= SEQ_AUDIO_VOLUME_ANIMATED;
- else
- seq->flag &= ~SEQ_AUDIO_VOLUME_ANIMATED;
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, &driven);
+ if (fcu || driven)
+ seq->flag |= SEQ_AUDIO_VOLUME_ANIMATED;
+ else
+ seq->flag &= ~SEQ_AUDIO_VOLUME_ANIMATED;
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pitch", 0, &driven);
- if (fcu || driven)
- seq->flag |= SEQ_AUDIO_PITCH_ANIMATED;
- else
- seq->flag &= ~SEQ_AUDIO_PITCH_ANIMATED;
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pitch", 0, &driven);
+ if (fcu || driven)
+ seq->flag |= SEQ_AUDIO_PITCH_ANIMATED;
+ else
+ seq->flag &= ~SEQ_AUDIO_PITCH_ANIMATED;
- fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pan", 0, &driven);
- if (fcu || driven)
- seq->flag |= SEQ_AUDIO_PAN_ANIMATED;
- else
- seq->flag &= ~SEQ_AUDIO_PAN_ANIMATED;
+ fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pan", 0, &driven);
+ if (fcu || driven)
+ seq->flag |= SEQ_AUDIO_PAN_ANIMATED;
+ else
+ seq->flag &= ~SEQ_AUDIO_PAN_ANIMATED;
+
+ if (seq->type == SEQ_TYPE_SCENE) {
+ /* TODO(sergey): For now we do manual recursion into the scene strips,
+ * but perhaps it should be covered by recursive_apply?
+ */
+ sound_update_animation_flags(seq->scene);
+ }
+
+ return 0;
+}
+
+static void sound_update_animation_flags(Scene *scene)
+{
+ struct FCurve *fcu;
+ bool driven;
+ Sequence *seq;
+
+ if (scene->id.tag & LIB_TAG_DOIT) {
+ return;
+ }
+ scene->id.tag |= LIB_TAG_DOIT;
+
+ SEQ_BEGIN(scene->ed, seq)
+ {
+ BKE_sequencer_recursive_apply(seq, sound_update_animation_flags_cb, scene);
}
SEQ_END
@@ -251,7 +275,12 @@ static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op)
scene->audio.flag |= AUDIO_VOLUME_ANIMATED;
else
scene->audio.flag &= ~AUDIO_VOLUME_ANIMATED;
+}
+static int sound_update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ BKE_main_id_tag_idcode(CTX_data_main(C), ID_SCE, LIB_TAG_DOIT, false);
+ sound_update_animation_flags(CTX_data_scene(C));
return OPERATOR_FINISHED;
}
@@ -348,10 +377,10 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
BLI_path_abs(filename, bmain->name);
if (split)
- result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS,
+ result = AUD_mixdown_per_channel(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS,
accuracy, filename, specs, container, codec, bitrate);
else
- result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS,
+ result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS,
accuracy, filename, specs, container, codec, bitrate);
if (result) {
diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h
index a55b18a2212..71e38f72a7a 100644
--- a/source/blender/editors/space_file/file_intern.h
+++ b/source/blender/editors/space_file/file_intern.h
@@ -128,7 +128,6 @@ void file_panels_register(struct ARegionType *art);
/* file_utils.c */
void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds);
-bool file_is_dir(struct SpaceFile *sfile, const char *path);
#endif /* __FILE_INTERN_H__ */
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index c42ff120102..9f5e98d2431 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1894,7 +1894,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
file_expand_directory(C);
/* special case, user may have pasted a filepath into the directory */
- if (!file_is_dir(sfile, sfile->params->dir)) {
+ if (!filelist_is_dir(sfile->files, sfile->params->dir)) {
char tdir[FILE_MAX_LIBEXTRA];
char *group, *name;
@@ -1920,7 +1920,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
BLI_cleanup_dir(G.main->name, sfile->params->dir);
- if (file_is_dir(sfile, sfile->params->dir)) {
+ if (filelist_is_dir(sfile->files, sfile->params->dir)) {
/* if directory exists, enter it immediately */
ED_file_change_dir(C);
@@ -1993,7 +1993,7 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg
BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file);
/* if directory, open it and empty filename field */
- if (file_is_dir(sfile, filepath)) {
+ if (filelist_is_dir(sfile->files, filepath)) {
BLI_cleanup_dir(G.main->name, filepath);
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
sfile->params->file[0] = '\0';
diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c
index f19e301064d..c1caf5ae8ac 100644
--- a/source/blender/editors/space_file/file_utils.c
+++ b/source/blender/editors/space_file/file_utils.c
@@ -48,17 +48,3 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r
BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x,
ymax - layout->tile_h - layout->tile_border_y, ymax);
}
-
-/* Cannot directly use BLI_is_dir in libloading context... */
-bool file_is_dir(struct SpaceFile *sfile, const char *path)
-{
- if (sfile->params->type == FILE_LOADLIB) {
- char tdir[FILE_MAX_LIBEXTRA];
- char *name;
- if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) {
- /* .blend file itself and group are considered as directories, not final datablock names. */
- return name ? false : true;
- }
- }
- return BLI_is_dir(path);
-}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index b6e4991bf52..14719322bf7 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -309,8 +309,9 @@ typedef struct FileList {
struct BlendHandle *libfiledata;
- /* Set given path as root directory, may change given string in place to a valid value. */
- void (*checkdirf)(struct FileList *, char *);
+ /* Set given path as root directory, if last bool is true may change given string in place to a valid value.
+ * Returns True if valid dir. */
+ bool (*checkdirf)(struct FileList *, char *, const bool);
/* Fill filelist (to be called by read job). */
void (*read_jobf)(struct FileList *, const char *, short *, short *, float *, ThreadMutex *);
@@ -942,24 +943,37 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m
/* ********** Main ********** */
-static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir)
+static bool filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change)
{
- BLI_make_exist(r_dir);
+ if (do_change) {
+ BLI_make_exist(r_dir);
+ return true;
+ }
+ else {
+ return BLI_is_dir(r_dir);
+ }
}
-static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir)
+static bool filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir, const bool do_change)
{
- char dir[FILE_MAX_LIBEXTRA];
- if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) {
+ char tdir[FILE_MAX_LIBEXTRA];
+ char *name;
+
+ const bool is_valid = (BLI_is_dir(r_dir) ||
+ (BLO_library_path_explode(r_dir, tdir, NULL, &name) && BLI_is_file(tdir) && !name));
+
+ if (do_change && !is_valid) {
/* if not a valid library, we need it to be a valid directory! */
BLI_make_exist(r_dir);
+ return true;
}
+ return is_valid;
}
-static void filelist_checkdir_main(struct FileList *filelist, char *r_dir)
+static bool filelist_checkdir_main(struct FileList *filelist, char *r_dir, const bool do_change)
{
/* TODO */
- filelist_checkdir_lib(filelist, r_dir);
+ return filelist_checkdir_lib(filelist, r_dir, do_change);
}
static void filelist_entry_clear(FileDirEntry *entry)
@@ -1378,6 +1392,11 @@ const char *filelist_dir(struct FileList *filelist)
return filelist->filelist.root;
}
+bool filelist_is_dir(struct FileList *filelist, const char *path)
+{
+ return filelist->checkdirf(filelist, (char *)path, false);
+}
+
/**
* May modify in place given r_dir, which is expected to be FILE_MAX_LIBEXTRA length.
*/
@@ -1386,7 +1405,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir)
BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA);
BLI_cleanup_dir(G.main->name, r_dir);
- filelist->checkdirf(filelist, r_dir);
+ BLI_assert(filelist->checkdirf(filelist, r_dir, true));
if (!STREQ(filelist->filelist.root, r_dir)) {
BLI_strncpy(filelist->filelist.root, r_dir, sizeof(filelist->filelist.root));
diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h
index d70faab1d6a..f4304681780 100644
--- a/source/blender/editors/space_file/filelist.h
+++ b/source/blender/editors/space_file/filelist.h
@@ -86,6 +86,7 @@ void filelist_clear_ex(struct FileList *filelist, const bool do_c
void filelist_free(struct FileList *filelist);
const char * filelist_dir(struct FileList *filelist);
+bool filelist_is_dir(struct FileList *filelist, const char *path);
void filelist_setdir(struct FileList *filelist, char *r_dir);
int filelist_files_ensure(struct FileList *filelist);
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 1a558d40560..7abe5ff5070 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -592,7 +592,7 @@ void ED_file_change_dir(bContext *C)
sfile->params->filter_search[0] = '\0';
sfile->params->active_file = -1;
- if (!file_is_dir(sfile, sfile->params->dir)) {
+ if (!filelist_is_dir(sfile->files, sfile->params->dir)) {
BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir));
/* could return but just refresh the current dir */
}
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index f9d76da9f87..a89d3494af0 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1608,18 +1608,26 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
/* imtype */
simopts->im_format = scene->r.im_format;
is_depth_set = true;
+ if (!BKE_image_is_multiview(ima)) {
+ /* In case multiview is disabled, render settings would be invalid for render result in this area. */
+ simopts->im_format.stereo3d_format = *ima->stereo3d_format;
+ simopts->im_format.views_format = ima->views_format;
+ }
}
else {
if (ima->source == IMA_SRC_GENERATED) {
simopts->im_format.imtype = R_IMF_IMTYPE_PNG;
simopts->im_format.compress = ibuf->foptions.quality;
+ simopts->im_format.planes = ibuf->planes;
}
else {
BKE_imbuf_to_image_format(&simopts->im_format, ibuf);
}
- }
- simopts->im_format.planes = ibuf->planes;
+ /* use the multiview image settings as the default */
+ simopts->im_format.stereo3d_format = *ima->stereo3d_format;
+ simopts->im_format.views_format = ima->views_format;
+ }
//simopts->subimtype = scene->r.subimtype; /* XXX - this is lame, we need to make these available too! */
@@ -1660,10 +1668,6 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
}
}
- /* use the multiview image settings as the default */
- simopts->im_format.stereo3d_format = *ima->stereo3d_format;
- simopts->im_format.views_format = ima->views_format;
-
/* color management */
BKE_color_managed_display_settings_copy(&simopts->im_format.display_settings, &scene->display_settings);
BKE_color_managed_view_settings_copy(&simopts->im_format.view_settings, &scene->view_settings);
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index d9c51e427c8..ab40c55b59d 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -1327,8 +1327,10 @@ void drawnodespace(const bContext *C, ARegion *ar)
path = snode->treepath.last;
/* update tree path name (drawn in the bottom left) */
- if (snode->id && UNLIKELY(!STREQ(path->node_name, snode->id->name + 2))) {
- BLI_strncpy(path->node_name, snode->id->name + 2, sizeof(path->node_name));
+ ID *name_id = (path->nodetree && path->nodetree != snode->nodetree) ? &path->nodetree->id : snode->id;
+
+ if (name_id && UNLIKELY(!STREQ(path->node_name, name_id->name + 2))) {
+ BLI_strncpy(path->node_name, name_id->name + 2, sizeof(path->node_name));
}
/* current View2D center, will be set temporarily for parent node trees */
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index d8edafb1dc9..db7e1b58e40 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -4207,7 +4207,7 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
/* If we are drawing shadows and any of the materials don't cast a shadow,
* then don't draw the object */
if (v3d->flag2 & V3D_RENDER_SHADOW) {
- for (int i = 0; i < ob->totcol; ++i) {
+ for (int i = 1; i <= ob->totcol; ++i) {
Material *ma = give_current_material(ob, i);
if (ma && !(ma->mode2 & MA_CASTSHADOW)) {
return true;
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 8dbc2788744..06677ef4476 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -288,6 +288,108 @@ static int create_view_aligned_slices(VolumeSlicer *slicer,
return num_points;
}
+static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec,
+ bool use_fire, const float min[3],
+ const float ob_sizei[3], const float invsize[3])
+{
+ int invsize_location = GPU_shader_get_uniform(shader, "invsize");
+ int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei");
+ int min_location = GPU_shader_get_uniform(shader, "min_location");
+
+ int soot_location;
+ int stepsize_location;
+ int densityscale_location;
+ int spec_location, flame_location;
+ int shadow_location, actcol_location;
+
+ if (use_fire) {
+ spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
+ flame_location = GPU_shader_get_uniform(shader, "flame_texture");
+ }
+ else {
+ shadow_location = GPU_shader_get_uniform(shader, "shadow_texture");
+ actcol_location = GPU_shader_get_uniform(shader, "active_color");
+ soot_location = GPU_shader_get_uniform(shader, "soot_texture");
+ stepsize_location = GPU_shader_get_uniform(shader, "step_size");
+ densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
+ }
+
+ GPU_shader_bind(shader);
+
+ if (use_fire) {
+ GPU_texture_bind(sds->tex_flame, 2);
+ GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame);
+
+ GPU_texture_bind(tex_spec, 3);
+ GPU_shader_uniform_texture(shader, spec_location, tex_spec);
+ }
+ else {
+ float density_scale = 10.0f;
+
+ GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx);
+ GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale);
+
+ GPU_texture_bind(sds->tex, 0);
+ GPU_shader_uniform_texture(shader, soot_location, sds->tex);
+
+ GPU_texture_bind(sds->tex_shadow, 1);
+ GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow);
+
+ float active_color[3] = { 0.9, 0.9, 0.9 };
+ if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
+ mul_v3_v3(active_color, sds->active_color);
+ GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color);
+ }
+
+ GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
+ GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei);
+ GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
+}
+
+static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool use_fire)
+{
+ GPU_shader_unbind();
+
+ GPU_texture_unbind(sds->tex);
+
+ if (use_fire) {
+ GPU_texture_unbind(sds->tex_flame);
+ GPU_texture_unbind(tex_spec);
+ GPU_texture_free(tex_spec);
+ }
+ else {
+ GPU_texture_unbind(sds->tex_shadow);
+ }
+}
+
+static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const VolumeSlicer *slicer,
+ const float ob_sizei[3], const float invsize[3], const int num_points, const bool do_fire)
+{
+ GPUTexture *tex_spec = (do_fire) ? create_flame_spectrum_texture() : NULL;
+
+ GLuint vertex_buffer;
+ glGenBuffers(1, &vertex_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer->verts[0][0], GL_STATIC_DRAW);
+
+ bind_shader(sds, shader, tex_spec, do_fire, slicer->min, ob_sizei, invsize);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, NULL);
+
+ glDrawArrays(GL_TRIANGLES, 0, num_points);
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ unbind_shader(sds, tex_spec, do_fire);
+
+ /* cleanup */
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDeleteBuffers(1, &vertex_buffer);
+}
+
void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
const float min[3], const float max[3],
const float viewnormal[3])
@@ -299,14 +401,23 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
const bool use_fire = (sds->active_fields & SM_ACTIVE_FIRE) && sds->tex_flame;
- GPUShader *shader = GPU_shader_get_builtin_shader(
- (use_fire) ? GPU_SHADER_SMOKE_FIRE : GPU_SHADER_SMOKE);
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE);
if (!shader) {
fprintf(stderr, "Unable to create GLSL smoke shader.\n");
return;
}
+ GPUShader *fire_shader = NULL;
+ if (use_fire) {
+ fire_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SMOKE_FIRE);
+
+ if (!fire_shader) {
+ fprintf(stderr, "Unable to create GLSL fire shader.\n");
+ return;
+ }
+ }
+
const float ob_sizei[3] = {
1.0f / fabsf(ob->size[0]),
1.0f / fabsf(ob->size[1]),
@@ -320,50 +431,6 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
TIMEIT_START(draw);
#endif
- /* setup smoke shader */
-
- int soot_location = GPU_shader_get_uniform(shader, "soot_texture");
- int spec_location = GPU_shader_get_uniform(shader, "spectrum_texture");
- int shadow_location = GPU_shader_get_uniform(shader, "shadow_texture");
- int flame_location = GPU_shader_get_uniform(shader, "flame_texture");
- int actcol_location = GPU_shader_get_uniform(shader, "active_color");
- int stepsize_location = GPU_shader_get_uniform(shader, "step_size");
- int densityscale_location = GPU_shader_get_uniform(shader, "density_scale");
- int invsize_location = GPU_shader_get_uniform(shader, "invsize");
- int ob_sizei_location = GPU_shader_get_uniform(shader, "ob_sizei");
- int min_location = GPU_shader_get_uniform(shader, "min_location");
-
- GPU_shader_bind(shader);
-
- GPU_texture_bind(sds->tex, 0);
- GPU_shader_uniform_texture(shader, soot_location, sds->tex);
-
- GPU_texture_bind(sds->tex_shadow, 1);
- GPU_shader_uniform_texture(shader, shadow_location, sds->tex_shadow);
-
- GPUTexture *tex_spec = NULL;
-
- if (use_fire) {
- GPU_texture_bind(sds->tex_flame, 2);
- GPU_shader_uniform_texture(shader, flame_location, sds->tex_flame);
-
- tex_spec = create_flame_spectrum_texture();
- GPU_texture_bind(tex_spec, 3);
- GPU_shader_uniform_texture(shader, spec_location, tex_spec);
- }
-
- float active_color[3] = { 0.9, 0.9, 0.9 };
- float density_scale = 10.0f;
- if ((sds->active_fields & SM_ACTIVE_COLORS) == 0)
- mul_v3_v3(active_color, sds->active_color);
-
- GPU_shader_uniform_vector(shader, actcol_location, 3, 1, active_color);
- GPU_shader_uniform_vector(shader, stepsize_location, 1, 1, &sds->dx);
- GPU_shader_uniform_vector(shader, densityscale_location, 1, 1, &density_scale);
- GPU_shader_uniform_vector(shader, min_location, 3, 1, min);
- GPU_shader_uniform_vector(shader, ob_sizei_location, 3, 1, ob_sizei);
- GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize);
-
/* setup slicing information */
const int max_slices = 256;
@@ -387,43 +454,23 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob,
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
- GLuint vertex_buffer;
- glGenBuffers(1, &vertex_buffer);
- glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
- glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * num_points, &slicer.verts[0][0], GL_STATIC_DRAW);
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, NULL);
-
- glDrawArrays(GL_TRIANGLES, 0, num_points);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false);
- glDisableClientState(GL_VERTEX_ARRAY);
+ /* Draw fire separately (T47639). */
+ if (use_fire) {
+ glBlendFunc(GL_ONE, GL_ONE);
+ draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true);
+ }
#ifdef DEBUG_DRAW_TIME
printf("Draw Time: %f\n", (float)TIMEIT_VALUE(draw));
TIMEIT_END(draw);
#endif
- /* cleanup */
-
- glBindBuffer(GL_ARRAY_BUFFER, 0);
- glDeleteBuffers(1, &vertex_buffer);
-
- GPU_texture_unbind(sds->tex);
- GPU_texture_unbind(sds->tex_shadow);
-
- if (use_fire) {
- GPU_texture_unbind(sds->tex_flame);
- GPU_texture_unbind(tex_spec);
- GPU_texture_free(tex_spec);
- }
-
MEM_freeN(slicer.verts);
- GPU_shader_unbind();
-
glDepthMask(gl_depth_write);
if (!gl_blend) {
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 67a40ae4180..3c13ab9d595 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -357,7 +357,7 @@ static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info)
gps->flag = GP_STROKE_3DSPACE;
gps->thickness = 3;
/* assign color to stroke */
- strcpy(gps->colorname, palcolor->info);
+ BLI_strncpy(gps->colorname, palcolor->info, sizeof(gps->colorname));
gps->palcolor = palcolor;
BLI_addtail(&gpf->strokes, gps);
changed = true;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index cfa083116f2..8885209ce01 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -78,6 +78,7 @@ set(SRC
shaders/gpu_shader_vsm_store_frag.glsl
shaders/gpu_shader_vsm_store_vert.glsl
shaders/gpu_shader_fx_depth_resolve.glsl
+ shaders/gpu_shader_fire_frag.glsl
shaders/gpu_shader_smoke_frag.glsl
shaders/gpu_shader_smoke_vert.glsl
@@ -99,6 +100,7 @@ set(SRC
)
data_to_c_simple(shaders/gpu_shader_geometry.glsl SRC)
+data_to_c_simple(shaders/gpu_shader_fire_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_smoke_frag.glsl SRC)
data_to_c_simple(shaders/gpu_shader_smoke_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index c40bc8eaf27..211394e7932 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -877,7 +877,7 @@ static char *code_generate_geometry(ListBase *nodes, bool use_opensubdiv)
if (input->attribtype == CD_MTFACE) {
BLI_dynstr_appendf(
ds,
- "\tINTERP_FACE_VARYING_2(var%d, "
+ "\tINTERP_FACE_VARYING_ATT_2(var%d, "
"int(texelFetch(FVarDataOffsetBuffer, fvar%d_offset).r), st);\n",
input->attribid,
input->attribid);
diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c
index df1213b01e2..5cfb323bc4b 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -45,6 +45,7 @@
#define MAX_EXT_DEFINE_LENGTH 1024
/* Non-generated shaders */
+extern char datatoc_gpu_shader_fire_frag_glsl[];
extern char datatoc_gpu_shader_smoke_vert_glsl[];
extern char datatoc_gpu_shader_smoke_frag_glsl[];
extern char datatoc_gpu_shader_vsm_store_vert_glsl[];
@@ -618,8 +619,8 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
case GPU_SHADER_SMOKE_FIRE:
if (!GG.shaders.smoke_fire)
GG.shaders.smoke_fire = GPU_shader_create(
- datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl,
- NULL, NULL, "#define USE_FIRE;\n", 0, 0, 0);
+ datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_fire_frag_glsl,
+ NULL, NULL, NULL, 0, 0, 0);
retval = GG.shaders.smoke_fire;
break;
}
diff --git a/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl
new file mode 100644
index 00000000000..3819203bcd9
--- /dev/null
+++ b/source/blender/gpu/shaders/gpu_shader_fire_frag.glsl
@@ -0,0 +1,17 @@
+
+varying vec3 coords;
+
+uniform sampler3D flame_texture;
+uniform sampler1D spectrum_texture;
+
+void main()
+{
+ float flame = texture3D(flame_texture, coords).r;
+ vec4 emission = texture1D(spectrum_texture, flame);
+
+ vec4 color;
+ color.rgb = emission.a * emission.rgb;
+ color.a = emission.a;
+
+ gl_FragColor = color;
+}
diff --git a/source/blender/gpu/shaders/gpu_shader_geometry.glsl b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
index 6f063883e37..fe630dbeddb 100644
--- a/source/blender/gpu/shaders/gpu_shader_geometry.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_geometry.glsl
@@ -31,6 +31,18 @@ uniform int osd_fvar_count;
tessCoord.t); \
}
+#ifdef USE_NEW_SHADING
+# define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \
+ { \
+ vec2 tmp; \
+ INTERP_FACE_VARYING_2(tmp, fvarOffset, tessCoord); \
+ result = vec3(tmp, 0); \
+ }
+#else
+# define INTERP_FACE_VARYING_ATT_2(result, fvarOffset, tessCoord) \
+ INTERP_FACE_VARYING_2(result, fvarOffset, tessCoord)
+#endif
+
uniform samplerBuffer FVarDataBuffer;
uniform isamplerBuffer FVarDataOffsetBuffer;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 845a78720ba..119bfb61fec 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -2185,11 +2185,11 @@ void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0));
}
-void env_apply(vec4 col, vec4 hor, vec4 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol)
+void env_apply(vec4 col, vec3 hor, vec3 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol)
{
vec3 vv = normalize(vm[2].xyz);
float skyfac = 0.5 * (1.0 + dot(vn, -vv));
- outcol = col + f * mix(hor, zen, skyfac);
+ outcol = col + f * vec4(mix(hor, zen, skyfac), 0);
}
void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol)
diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
index 4d1feb5c83e..fd790009e02 100644
--- a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl
@@ -8,11 +8,6 @@ uniform float density_scale;
uniform sampler3D soot_texture;
uniform sampler3D shadow_texture;
-#ifdef USE_FIRE
-uniform sampler3D flame_texture;
-uniform sampler1D spectrum_texture;
-#endif
-
void main()
{
/* compute color and density from volume texture */
@@ -37,12 +32,5 @@ void main()
/* premultiply alpha */
vec4 color = vec4(soot_alpha * soot_color, soot_alpha);
-#ifdef USE_FIRE
- /* fire */
- float flame = texture3D(flame_texture, coords).r;
- vec4 emission = texture1D(spectrum_texture, flame);
- color.rgb += (1 - color.a) * emission.a * emission.rgb;
-#endif
-
gl_FragColor = color;
}
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 773d203bdb3..23b73424da5 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -336,7 +336,7 @@ typedef enum eGPdata_Flag {
/* Convenience/cache flag to make it easier to quickly toggle onion skinning on/off */
GP_DATA_SHOW_ONIONSKINS = (1 << 9),
/* Draw a green and red point to indicate start and end of the stroke */
- GP_DATA_SHOW_DIRECTION = (1 << 10)
+ GP_DATA_SHOW_DIRECTION = (1 << 10)
} eGPdata_Flag;
#endif /* __DNA_GPENCIL_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index a4934cc1f24..5c5264afcba 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1167,7 +1167,11 @@ typedef enum eGP_BrushEdit_SettingsFlag {
/* apply brush to strength */
GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2),
/* apply brush to thickness */
- GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3)
+ GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3),
+ /* apply interpolation to all layers */
+ GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS = (1 << 4),
+ /* apply interpolation to only selected */
+ GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED = (1 << 5)
} eGP_BrushEdit_SettingsFlag;
@@ -1738,9 +1742,11 @@ typedef struct Scene {
#define R_STAMP_CAMERALENS 0x0800
#define R_STAMP_STRIPMETA 0x1000
#define R_STAMP_MEMORY 0x2000
+#define R_STAMP_HIDE_LABELS 0x4000
#define R_STAMP_ALL (R_STAMP_TIME|R_STAMP_FRAME|R_STAMP_DATE|R_STAMP_CAMERA|R_STAMP_SCENE| \
R_STAMP_NOTE|R_STAMP_MARKER|R_STAMP_FILENAME|R_STAMP_SEQSTRIP| \
- R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY)
+ R_STAMP_RENDERTIME|R_STAMP_CAMERALENS|R_STAMP_MEMORY| \
+ R_STAMP_HIDE_LABELS)
/* alphamode */
#define R_ADDSKY 0
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 9cbe132282f..820465ee7d1 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -916,6 +916,7 @@ int RNA_property_enum_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value);
int RNA_property_enum_get_default(PointerRNA *ptr, PropertyRNA *prop);
void *RNA_property_enum_py_data_get(PropertyRNA *prop);
+int RNA_property_enum_step(const struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int direction);
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop);
void RNA_property_pointer_set(PointerRNA *ptr, PropertyRNA *prop, PointerRNA ptr_value);
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 047e5ea17ab..6879a0534e9 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -2873,6 +2873,45 @@ void *RNA_property_enum_py_data_get(PropertyRNA *prop)
return eprop->py_data;
}
+/**
+ * Get the value of the item that is \a step items away from \a from_value.
+ *
+ * \param from_value: Item value to start stepping from.
+ * \param step: Absolute value defines step size, sign defines direction.
+ * E.g to get the next item, pass 1, for the previous -1.
+ */
+int RNA_property_enum_step(const bContext *C, PointerRNA *ptr, PropertyRNA *prop, int from_value, int step)
+{
+ EnumPropertyItem *item_array;
+ int totitem;
+ bool free;
+ int result_value = from_value;
+ int i, i_init;
+ int single_step = (step < 0) ? -1 : 1;
+ int step_tot = 0;
+
+ RNA_property_enum_items((bContext *)C, ptr, prop, &item_array, &totitem, &free);
+ i = RNA_enum_from_value(item_array, from_value);
+ i_init = i;
+
+ do {
+ i = mod_i(i + single_step, totitem);
+ if (item_array[i].identifier[0]) {
+ step_tot += single_step;
+ }
+ } while ((i != i_init) && (step_tot != step));
+
+ if (i != i_init) {
+ result_value = item_array[i].value;
+ }
+
+ if (free) {
+ MEM_freeN(item_array);
+ }
+
+ return result_value;
+}
+
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
{
PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop;
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index e4f9f856db7..2a8cc073e22 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -1889,7 +1889,7 @@ void RNA_def_material(BlenderRNA *brna)
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "index");
- RNA_def_property_ui_text(prop, "Pass Index", "Index number for the IndexMA render pass");
+ RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Material Index\" render pass");
RNA_def_property_update(prop, NC_OBJECT, "rna_Material_update");
/* flags */
diff --git a/source/blender/makesrna/intern/rna_movieclip.c b/source/blender/makesrna/intern/rna_movieclip.c
index 19d78361019..15411f85ba3 100644
--- a/source/blender/makesrna/intern/rna_movieclip.c
+++ b/source/blender/makesrna/intern/rna_movieclip.c
@@ -347,6 +347,8 @@ static void rna_def_movieclip(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "colorspace_settings");
RNA_def_property_struct_type(prop, "ColorManagedInputColorspaceSettings");
RNA_def_property_ui_text(prop, "Color Space Settings", "Input color space settings");
+
+ rna_def_animdata_common(srna);
}
void RNA_def_movieclip(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 2d158a3d371..addc6b6e28b 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -2560,7 +2560,7 @@ static void rna_def_object(BlenderRNA *brna)
/* render */
prop = RNA_def_property(srna, "pass_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "index");
- RNA_def_property_ui_text(prop, "Pass Index", "Index number for the IndexOB render pass");
+ RNA_def_property_ui_text(prop, "Pass Index", "Index number for the \"Object Index\" render pass");
RNA_def_property_update(prop, NC_OBJECT, "rna_Object_internal_update");
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 98df12719d3..f2a1e0a50ab 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -2291,7 +2291,7 @@ static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop)
"rna_GPencilBrushes_index_get",
"rna_GPencilBrushes_index_set",
"rna_GPencilBrushes_index_range");
- RNA_def_property_ui_text(prop, "Active brush Index", "Index of active brush");
+ RNA_def_property_ui_text(prop, "Active Brush Index", "Index of active brush");
}
static void rna_def_transform_orientation(BlenderRNA *brna)
@@ -6289,6 +6289,11 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Stamp Output", "Render the stamp info text in the rendered image");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ prop = RNA_def_property(srna, "use_stamp_labels", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "stamp", R_STAMP_HIDE_LABELS);
+ RNA_def_property_ui_text(prop, "Stamp Labels", "Draw stamp labels (\"Camera\" in front of camera name, etc.)");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "use_stamp_strip_meta", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "stamp", R_STAMP_STRIPMETA);
RNA_def_property_ui_text(prop, "Strip Metadata", "Use metadata from the strips in the sequencer");
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index a8e80dbc4a3..7e1d0164eb4 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -1037,6 +1037,16 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Affect Thickness", "The brush affects the thickness of the point");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "interpolate_all_layers", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS);
+ RNA_def_property_ui_text(prop, "Interpolate All Layers", "Interpolate all layers, not only active");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
+ prop = RNA_def_property(srna, "interpolate_selected_only", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED);
+ RNA_def_property_ui_text(prop, "Interpolate Selected Strokes", "Interpolate only selected strokes in the original frame");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+
prop = RNA_def_property(srna, "selection_alpha", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "alpha");
RNA_def_property_range(prop, 0.0f, 1.0f);
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index a751c414d83..9d55115a14c 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -618,7 +618,7 @@ void RNA_api_ui_layout(StructRNA *srna)
#endif
func = RNA_def_function(srna, "label", "rna_uiItemL");
- RNA_def_function_ui_description(func, "Item. Display text and/or icon in the layout");
+ RNA_def_function_ui_description(func, "Item. Displays text and/or icon in the layout");
api_ui_item_common(func);
parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED);
RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item");
@@ -644,6 +644,7 @@ void RNA_api_ui_layout(StructRNA *srna)
/* templates */
func = RNA_def_function(srna, "template_header", "uiTemplateHeader");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Inserts common Space header UI (editor type selector)");
func = RNA_def_function(srna, "template_ID", "uiTemplateID");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
@@ -853,9 +854,12 @@ void RNA_api_ui_layout(StructRNA *srna)
func = RNA_def_function(srna, "template_header_3D", "uiTemplateHeader3D");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Inserts common 3DView header UI (selectors for context mode, shading, etc.)");
+
func = RNA_def_function(srna, "template_edit_mode_selection", "uiTemplateEditModeSelection");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
+ RNA_def_function_ui_description(func, "Inserts common 3DView Edit modes header UI (selector for selection mode)");
func = RNA_def_function(srna, "template_reports_banner", "uiTemplateReportsBanner");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 7cf0cf67269..8d0b704a402 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -398,18 +398,21 @@ void RNA_api_wm(StructRNA *srna)
rna_generic_op_invoke(func, 0);
func = RNA_def_function(srna, "modal_handler_add", "rna_event_modal_handler_add");
+ RNA_def_function_ui_description(func, "Add a modal handler to the window manager, for the given modal operator "
+ "(called by invoke() with self, just before returning {'RUNNING_MODAL'})");
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "operator", "Operator", "", "Operator to call");
RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_function_return(func, RNA_def_boolean(func, "handle", 1, "", ""));
+ RNA_def_function_return(func, RNA_def_boolean(func, "handle", 1, "", "Whether adding the handler was successful"));
func = RNA_def_function(srna, "event_timer_add", "rna_event_timer_add");
+ RNA_def_function_ui_description(func, "Add a timer to the given window, to generate periodic 'TIMER' events");
parm = RNA_def_property(func, "time_step", PROP_FLOAT, PROP_NONE);
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_property_range(parm, 0.0, FLT_MAX);
RNA_def_property_ui_text(parm, "Time Step", "Interval in seconds between timer events");
- RNA_def_pointer(func, "window", "Window", "", "Window to attach the timer to or None");
+ RNA_def_pointer(func, "window", "Window", "", "Window to attach the timer to, or None");
parm = RNA_def_pointer(func, "result", "Timer", "", "");
RNA_def_function_return(func, parm);
@@ -421,44 +424,49 @@ void RNA_api_wm(StructRNA *srna)
/* Progress bar interface */
func = RNA_def_function(srna, "progress_begin", "rna_progress_begin");
RNA_def_function_ui_description(func, "Start progress report");
-
parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_NONE);
RNA_def_property_ui_text(parm, "min", "any value in range [0,9999]");
RNA_def_property_flag(parm, PROP_REQUIRED);
-
parm = RNA_def_property(func, "max", PROP_FLOAT, PROP_NONE);
RNA_def_property_flag(parm, PROP_REQUIRED);
RNA_def_property_ui_text(parm, "max", "any value in range [min+1,9998]");
func = RNA_def_function(srna, "progress_update", "rna_progress_update");
+ RNA_def_function_ui_description(func, "Update the progress feedback");
parm = RNA_def_property(func, "value", PROP_FLOAT, PROP_NONE);
RNA_def_property_flag(parm, PROP_REQUIRED);
- RNA_def_property_ui_text(parm, "value", "any value between min and max as set in progress_begin()");
+ RNA_def_property_ui_text(parm, "value", "Any value between min and max as set in progress_begin()");
func = RNA_def_function(srna, "progress_end", "rna_progress_end");
RNA_def_function_ui_description(func, "Terminate progress report");
/* invoke functions, for use with python */
func = RNA_def_function(srna, "invoke_props_popup", "rna_Operator_props_popup");
- RNA_def_function_ui_description(func, "Operator popup invoke");
+ RNA_def_function_ui_description(func, "Operator popup invoke "
+ "(show operator properties and execute it automatically on changes)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_EVENT | WM_GEN_INVOKE_RETURN);
/* invoked dialog opens popup with OK button, does not auto-exec operator. */
func = RNA_def_function(srna, "invoke_props_dialog", "WM_operator_props_dialog_popup");
- RNA_def_function_ui_description(func, "Operator dialog (non-autoexec popup) invoke");
+ RNA_def_function_ui_description(func, "Operator dialog (non-autoexec popup) invoke "
+ "(show operator properties and only execute it on click on OK button)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_SIZE | WM_GEN_INVOKE_RETURN);
/* invoke enum */
func = RNA_def_function(srna, "invoke_search_popup", "rna_Operator_enum_search_invoke");
+ RNA_def_function_ui_description(func, "Operator search popup invoke (search in values of "
+ "operator's type 'prop' EnumProperty, and execute it on confirmation)");
rna_generic_op_invoke(func, 0);
/* invoke functions, for use with python */
func = RNA_def_function(srna, "invoke_popup", "WM_operator_ui_popup");
- RNA_def_function_ui_description(func, "Operator popup invoke");
+ RNA_def_function_ui_description(func, "Operator popup invoke "
+ "(only shows operator's properties, without executing it)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_SIZE | WM_GEN_INVOKE_RETURN);
func = RNA_def_function(srna, "invoke_confirm", "rna_Operator_confirm");
- RNA_def_function_ui_description(func, "Operator confirmation");
+ RNA_def_function_ui_description(func, "Operator confirmation popup "
+ "(only to let user confirm the execution, no operator properties shown)");
rna_generic_op_invoke(func, WM_GEN_INVOKE_EVENT | WM_GEN_INVOKE_RETURN);
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 23ab61821f4..8711384e1ee 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -130,6 +130,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (U.opensubdiv_compute_type == USER_OPENSUBDIV_COMPUTE_NONE) {
modifier_setError(md, "OpenSubdiv is disabled in User Preferences");
}
+ else if ((ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) != 0) {
+ modifier_setError(md, "OpenSubdiv is not supported in paint modes");
+ }
else if ((DAG_get_eval_flags_for_object(md->scene, ob) & DAG_EVAL_NEED_CPU) == 0) {
subsurf_flags |= SUBSURF_USE_GPU_BACKEND;
do_cddm_convert = false;
diff --git a/source/blender/nodes/shader/nodes/node_shader_material.c b/source/blender/nodes/shader/nodes/node_shader_material.c
index 8b21b1ff33b..6850cdbf6ea 100644
--- a/source/blender/nodes/shader/nodes/node_shader_material.c
+++ b/source/blender/nodes/shader/nodes/node_shader_material.c
@@ -223,12 +223,27 @@ static void node_shader_init_material(bNodeTree *UNUSED(ntree), bNode *node)
/* XXX this is also done as a local static function in gpu_codegen.c,
* but we need this to hack around the crappy material node.
*/
-static GPUNodeLink *gpu_get_input_link(GPUNodeStack *in)
+static GPUNodeLink *gpu_get_input_link(GPUMaterial *mat, GPUNodeStack *in)
{
- if (in->link)
+ if (in->link) {
return in->link;
- else
- return GPU_uniform(in->vec);
+ }
+ else {
+ GPUNodeLink *result = NULL;
+
+ /* note GPU_uniform() is only intended to be used as a parameter to
+ * GPU_link(), returning it directly results in leaks or double frees */
+ if (in->type == GPU_FLOAT)
+ GPU_link(mat, "set_value", GPU_uniform(in->vec), &result);
+ else if (in->type == GPU_VEC3)
+ GPU_link(mat, "set_rgb", GPU_uniform(in->vec), &result);
+ else if (in->type == GPU_VEC4)
+ GPU_link(mat, "set_rgba", GPU_uniform(in->vec), &result);
+ else
+ BLI_assert(0);
+
+ return result;
+ }
}
static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
@@ -251,18 +266,18 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
/* write values */
if (hasinput[MAT_IN_COLOR])
- shi.rgb = gpu_get_input_link(&in[MAT_IN_COLOR]);
+ shi.rgb = gpu_get_input_link(mat, &in[MAT_IN_COLOR]);
if (hasinput[MAT_IN_SPEC])
- shi.specrgb = gpu_get_input_link(&in[MAT_IN_SPEC]);
+ shi.specrgb = gpu_get_input_link(mat, &in[MAT_IN_SPEC]);
if (hasinput[MAT_IN_REFL])
- shi.refl = gpu_get_input_link(&in[MAT_IN_REFL]);
+ shi.refl = gpu_get_input_link(mat, &in[MAT_IN_REFL]);
/* retrieve normal */
if (hasinput[MAT_IN_NORMAL]) {
GPUNodeLink *tmp;
- shi.vn = gpu_get_input_link(&in[MAT_IN_NORMAL]);
+ shi.vn = gpu_get_input_link(mat, &in[MAT_IN_NORMAL]);
if (GPU_material_use_world_space_shading(mat)) {
GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
GPU_link(mat, "direction_transform_m4v3", shi.vn, GPU_builtin(GPU_VIEW_MATRIX), &shi.vn);
@@ -276,15 +291,15 @@ static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNU
if (node->type == SH_NODE_MATERIAL_EXT) {
if (hasinput[MAT_IN_MIR])
- shi.mir = gpu_get_input_link(&in[MAT_IN_MIR]);
+ shi.mir = gpu_get_input_link(mat, &in[MAT_IN_MIR]);
if (hasinput[MAT_IN_AMB])
- shi.amb = gpu_get_input_link(&in[MAT_IN_AMB]);
+ shi.amb = gpu_get_input_link(mat, &in[MAT_IN_AMB]);
if (hasinput[MAT_IN_EMIT])
- shi.emit = gpu_get_input_link(&in[MAT_IN_EMIT]);
+ shi.emit = gpu_get_input_link(mat, &in[MAT_IN_EMIT]);
if (hasinput[MAT_IN_SPECTRA])
- shi.spectra = gpu_get_input_link(&in[MAT_IN_SPECTRA]);
+ shi.spectra = gpu_get_input_link(mat, &in[MAT_IN_SPECTRA]);
if (hasinput[MAT_IN_ALPHA])
- shi.alpha = gpu_get_input_link(&in[MAT_IN_ALPHA]);
+ shi.alpha = gpu_get_input_link(mat, &in[MAT_IN_ALPHA]);
}
GPU_shaderesult_set(&shi, &shr); /* clears shr */
diff --git a/source/blender/python/intern/bpy_library_write.c b/source/blender/python/intern/bpy_library_write.c
index f582cebb260..bf91253141a 100644
--- a/source/blender/python/intern/bpy_library_write.c
+++ b/source/blender/python/intern/bpy_library_write.c
@@ -50,7 +50,7 @@
PyDoc_STRVAR(bpy_lib_write_doc,
-".. method:: write(filepath, datablocks, relative_remap=False, fake_user=False)\n"
+".. method:: write(filepath, datablocks, relative_remap=False, fake_user=False, compress=False)\n"
"\n"
" Write data-blocks into a blend file.\n"
"\n"
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index fcdab746d57..0c137221856 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -1369,12 +1369,13 @@ typedef struct wmOpPopUp {
/* Only invoked by OK button in popups created with wm_block_dialog_create() */
static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win = CTX_wm_window(C);
-
wmOpPopUp *data = arg1;
uiBlock *block = arg2;
+ /* Explicitly set UI_RETURN_OK flag, otherwise the menu might be cancelled
+ * in case WM_operator_call_ex exits/reloads the current file (T49199). */
+ UI_popup_menu_retval_set(block, UI_RETURN_OK, true);
+
WM_operator_call_ex(C, data->op, true);
/* let execute handle freeing it */
@@ -1384,8 +1385,18 @@ static void dialog_exec_cb(bContext *C, void *arg1, void *arg2)
/* in this case, wm_operator_ui_popup_cancel wont run */
MEM_freeN(data);
+ /* get context data *after* WM_operator_call_ex which might have closed the current file and changed context */
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
+
/* check window before 'block->handle' incase the
- * popup execution closed the window and freed the block. see T44688. */
+ * popup execution closed the window and freed the block. see T44688.
+ */
+ /* Post 2.78 TODO: Check if this fix and others related to T44688 are still
+ * needed or can be improved now that requesting context data has been corrected
+ * (see above). We're close to release so not a good time for experiments.
+ * -- Julian
+ */
if (BLI_findindex(&wm->windows, win) != -1) {
UI_popup_block_close(C, win, block);
}
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 2748de0e7dd..58bebc66a3e 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -58,7 +58,7 @@ if(WIN32 AND NOT UNIX)
blenderplayer ${EXETYPE}
bad_level_call_stubs/stubs.c
${CMAKE_SOURCE_DIR}/release/windows/icons/winblender.rc)
-
+ WINDOWS_SIGN_TARGET(blenderplayer)
install(TARGETS blenderplayer
COMPONENT Blenderplayer
DESTINATION ".")
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 7acea43d1f5..f65688e1304 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -263,6 +263,7 @@ if(WITH_PYTHON_MODULE)
else()
add_executable(blender ${EXETYPE} ${SRC})
+ WINDOWS_SIGN_TARGET(blender)
endif()
if(WITH_BUILDINFO)
@@ -337,7 +338,8 @@ if(WITH_PYTHON)
# install(CODE "message(\"copying blender scripts...\")")
# exclude addons_contrib if release
- if("${BLENDER_VERSION_CYCLE}" STREQUAL "release")
+ if("${BLENDER_VERSION_CYCLE}" STREQUAL "release" OR
+ "${BLENDER_VERSION_CYCLE}" STREQUAL "rc")
set(ADDON_EXCLUDE_CONDITIONAL "addons_contrib/*")
else()
set(ADDON_EXCLUDE_CONDITIONAL "_addons_contrib/*") # dummy, wont do anything
diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
index 6c09af33f9e..577e25d6198 100644
--- a/source/gameengine/GamePlayer/ghost/CMakeLists.txt
+++ b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
@@ -81,6 +81,10 @@ if(WIN32)
blender_include_dirs(../../../../intern/utfconv)
endif()
+if(WITH_INPUT_NDOF)
+ add_definitions(-DWITH_INPUT_NDOF)
+endif(WITH_INPUT_NDOF)
+
if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
diff --git a/source/tools b/source/tools
-Subproject 373945d0978b6601c55c9d5879e0f488b18515c
+Subproject 896c5f78952adb2d091d28c65086d46992dabda