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:
authorBastien Montagne <montagne29@wanadoo.fr>2016-09-04 17:41:06 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2016-09-04 17:41:06 +0300
commit3c29aad787f636167319950636f1497442075df8 (patch)
tree3a993cc25296ce987893b9f58b7c794b51e77f85 /source/blender
parent498583844fb7d0adbbc91d512f98885800cdf46e (diff)
parente76e8fcdcc53455a52a6a73495881eddd346472c (diff)
Merge branch 'master' into blender2.8
Conflicts: intern/cycles/blender/blender_particles.cpp source/blender/blenkernel/intern/particle.c source/blender/gpu/intern/gpu_shader.c
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/alembic/CMakeLists.txt1
-rw-r--r--source/blender/alembic/intern/abc_exporter.cc85
-rw-r--r--source/blender/alembic/intern/abc_exporter.h2
-rw-r--r--source/blender/alembic/intern/alembic_capi.cc125
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h6
-rw-r--r--source/blender/blenkernel/BKE_cachefile.h2
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c16
-rw-r--r--source/blender/blenkernel/intern/armature_update.c6
-rw-r--r--source/blender/blenkernel/intern/cachefile.c20
-rw-r--r--source/blender/blenkernel/intern/constraint.c21
-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/scene.c20
-rw-r--r--source/blender/blenkernel/intern/tracking.c2
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c565
-rw-r--r--source/blender/blenkernel/intern/world.c2
-rw-r--r--source/blender/blenlib/intern/math_geom.c4
-rw-r--r--source/blender/blenloader/intern/readfile.c16
-rw-r--r--source/blender/blenloader/intern/versioning_270.c39
-rw-r--r--source/blender/blenloader/intern/writefile.c2
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp7
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval.cc2
-rw-r--r--source/blender/depsgraph/intern/eval/deg_eval_flush.cc97
-rw-r--r--source/blender/editors/gpencil/gpencil_data.c432
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c710
-rw-r--r--source/blender/editors/gpencil/gpencil_intern.h30
-rw-r--r--source/blender/editors/gpencil/gpencil_ops.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c28
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c47
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c63
-rw-r--r--source/blender/editors/include/UI_interface.h2
-rw-r--r--source/blender/editors/interface/interface_handlers.c17
-rw-r--r--source/blender/editors/interface/interface_regions.c4
-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/sculpt_paint/paint_stroke.c3
-rw-r--r--source/blender/editors/sound/sound_ops.c4
-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.c11
-rw-r--r--source/blender/editors/space_node/node_draw.c6
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c10
-rw-r--r--source/blender/editors/space_view3d/drawvolume.c193
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c8
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c3
-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.c3
-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_cachefile_types.h1
-rw-r--r--source/blender/makesdna/DNA_scene_types.h4
-rw-r--r--source/blender/makesrna/intern/rna_curve.c2
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c17
-rw-r--r--source/blender/makesrna/intern/rna_lamp.c2
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c10
-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_nodetree.c4
-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_tracking.c12
-rw-r--r--source/blender/makesrna/intern/rna_wm.c6
-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/render/intern/raytrace/rayobject.cpp84
-rw-r--r--source/blender/render/intern/source/pipeline.c7
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c19
83 files changed, 1892 insertions, 1112 deletions
diff --git a/source/blender/alembic/CMakeLists.txt b/source/blender/alembic/CMakeLists.txt
index 42bd6a9c340..0b6b2433bd0 100644
--- a/source/blender/alembic/CMakeLists.txt
+++ b/source/blender/alembic/CMakeLists.txt
@@ -33,6 +33,7 @@ set(INC
../makesrna
../windowmanager
../../../intern/guardedalloc
+ ../../../intern/utfconv
)
set(INC_SYS
diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc
index 132c59c0cfb..57a2bdd274f 100644
--- a/source/blender/alembic/intern/abc_exporter.cc
+++ b/source/blender/alembic/intern/abc_exporter.cc
@@ -30,6 +30,10 @@
#include <Alembic/AbcCoreOgawa/All.h>
+#ifdef WIN32
+# include "utfconv.h"
+#endif
+
#include "abc_camera.h"
#include "abc_curves.h"
#include "abc_hair.h"
@@ -66,6 +70,54 @@ extern "C" {
using Alembic::Abc::TimeSamplingPtr;
using Alembic::Abc::OBox3dProperty;
+
+/* ************************************************************************** */
+
+/* This kinda duplicates CreateArchiveWithInfo, but Alembic does not seem to
+ * have a version supporting streams. */
+static Alembic::Abc::OArchive create_archive(std::ostream *ostream,
+ const std::string &filename,
+ const std::string &scene_name,
+ const Alembic::Abc::Argument &arg0,
+ const Alembic::Abc::Argument &arg1,
+ bool ogawa)
+{
+ Alembic::Abc::MetaData md = GetMetaData(arg0, arg1);
+ md.set(Alembic::Abc::kApplicationNameKey, "Blender");
+ md.set(Alembic::Abc::kUserDescriptionKey, scene_name);
+
+ time_t raw_time;
+ time(&raw_time);
+ char buffer[128];
+
+#if defined _WIN32 || defined _WIN64
+ ctime_s(buffer, 128, &raw_time);
+#else
+ ctime_r(&raw_time, buffer);
+#endif
+
+ const std::size_t buffer_len = strlen(buffer);
+ if (buffer_len > 0 && buffer[buffer_len - 1] == '\n') {
+ buffer[buffer_len - 1] = '\0';
+ }
+
+ md.set(Alembic::Abc::kDateWrittenKey, buffer);
+
+ Alembic::Abc::ErrorHandler::Policy policy = GetErrorHandlerPolicyFromArgs(arg0, arg1);
+
+#ifdef WITH_ALEMBIC_HDF5
+ if (!ogawa) {
+ return Alembic::Abc::OArchive(Alembic::AbcCoreHDF5::WriteArchive(), filename, md, policy);
+ }
+#else
+ static_cast<void>(filename);
+ static_cast<void>(ogawa);
+#endif
+
+ Alembic::AbcCoreOgawa::WriteArchive archive_writer;
+ return Alembic::Abc::OArchive(archive_writer(ostream, md), Alembic::Abc::kWrapExisting, policy);
+}
+
/* ************************************************************************** */
ExportSettings::ExportSettings()
@@ -246,26 +298,25 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled)
Alembic::Abc::Argument arg(md);
-#ifdef WITH_ALEMBIC_HDF5
- if (!m_settings.export_ogawa) {
- m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreHDF5::WriteArchive(),
- m_filename,
- "Blender",
- scene_name,
- Alembic::Abc::ErrorHandler::kThrowPolicy,
- arg);
- }
- else
+ /* Use stream to support unicode character paths on Windows. */
+ if (m_settings.export_ogawa) {
+#ifdef WIN32
+ UTF16_ENCODE(m_filename);
+ std::wstring wstr(m_filename_16);
+ m_out_file.open(wstr.c_str(), std::ios::out | std::ios::binary);
+ UTF16_UN_ENCODE(m_filename);
+#else
+ m_out_file.open(m_filename, std::ios::out | std::ios::binary);
#endif
- {
- m_archive = Alembic::Abc::CreateArchiveWithInfo(Alembic::AbcCoreOgawa::WriteArchive(),
- m_filename,
- "Blender",
- scene_name,
- Alembic::Abc::ErrorHandler::kThrowPolicy,
- arg);
}
+ m_archive = create_archive(&m_out_file,
+ m_filename,
+ scene_name,
+ Alembic::Abc::ErrorHandler::kThrowPolicy,
+ arg,
+ m_settings.export_ogawa);
+
/* Create time samplings for transforms and shapes. */
TimeSamplingPtr trans_time = createTimeSampling(m_settings.frame_step_xform);
diff --git a/source/blender/alembic/intern/abc_exporter.h b/source/blender/alembic/intern/abc_exporter.h
index 070eb9ea81a..6c242f973c4 100644
--- a/source/blender/alembic/intern/abc_exporter.h
+++ b/source/blender/alembic/intern/abc_exporter.h
@@ -24,6 +24,7 @@
#define __ABC_EXPORTER_H__
#include <Alembic/Abc/All.h>
+#include <fstream>
#include <map>
#include <set>
#include <vector>
@@ -75,6 +76,7 @@ class AbcExporter {
const char *m_filename;
+ std::ofstream m_out_file;
Alembic::Abc::OArchive m_archive;
unsigned int m_trans_sampling_index, m_shape_sampling_index;
diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc
index f42c708b4c2..d057cc341f6 100644
--- a/source/blender/alembic/intern/alembic_capi.cc
+++ b/source/blender/alembic/intern/alembic_capi.cc
@@ -29,6 +29,12 @@
#include <Alembic/AbcCoreOgawa/All.h>
#include <Alembic/AbcMaterial/IMaterial.h>
+#include <fstream>
+
+#ifdef WIN32
+# include "utfconv.h"
+#endif
+
#include "abc_camera.h"
#include "abc_curves.h"
#include "abc_hair.h"
@@ -109,49 +115,97 @@ using Alembic::AbcGeom::V3fArraySamplePtr;
using Alembic::AbcMaterial::IMaterial;
-struct AbcArchiveHandle {
- int unused;
-};
-
-ABC_INLINE IArchive *archive_from_handle(AbcArchiveHandle *handle)
-{
- return reinterpret_cast<IArchive *>(handle);
-}
-
-ABC_INLINE AbcArchiveHandle *handle_from_archive(IArchive *archive)
+static IArchive open_archive(const std::string &filename,
+ const std::vector<std::istream *> &input_streams,
+ bool &is_hdf5)
{
- return reinterpret_cast<AbcArchiveHandle *>(archive);
-}
-
-static IArchive *open_archive(const std::string &filename)
-{
- Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr;
- IArchive *archive;
-
try {
- archive = new IArchive(Alembic::AbcCoreOgawa::ReadArchive(),
- filename.c_str(), ErrorHandler::kThrowPolicy,
- cache_ptr);
+ is_hdf5 = false;
+ Alembic::AbcCoreOgawa::ReadArchive archive_reader(input_streams);
+
+ return IArchive(archive_reader(filename),
+ kWrapExisting,
+ ErrorHandler::kThrowPolicy);
}
catch (const Exception &e) {
std::cerr << e.what() << '\n';
#ifdef WITH_ALEMBIC_HDF5
try {
- archive = new IArchive(Alembic::AbcCoreHDF5::ReadArchive(),
- filename.c_str(), ErrorHandler::kThrowPolicy,
- cache_ptr);
+ is_hdf5 = true;
+ Alembic::AbcCoreAbstract::ReadArraySampleCachePtr cache_ptr;
+
+ return IArchive(Alembic::AbcCoreHDF5::ReadArchive(),
+ filename.c_str(), ErrorHandler::kThrowPolicy,
+ cache_ptr);
}
catch (const Exception &) {
std::cerr << e.what() << '\n';
- return NULL;
+ return IArchive();
}
#else
- return NULL;
+ return IArchive();
#endif
}
- return archive;
+ return IArchive();
+}
+
+/* Wrapper around an archive to be able to use streams so that unicode paths
+ * work on Windows (T49112), and to make sure the input stream remains valid as
+ * long as the archive is open. */
+class ArchiveWrapper {
+ IArchive m_archive;
+ std::ifstream m_infile;
+ std::vector<std::istream *> m_streams;
+
+public:
+ explicit ArchiveWrapper(const char *filename)
+ {
+#ifdef WIN32
+ UTF16_ENCODE(filename);
+ std::wstring wstr(filename_16);
+ m_infile.open(wstr.c_str(), std::ios::in | std::ios::binary);
+ UTF16_UN_ENCODE(filename);
+#else
+ m_infile.open(filename, std::ios::in | std::ios::binary);
+#endif
+
+ m_streams.push_back(&m_infile);
+
+ bool is_hdf5;
+ m_archive = open_archive(filename, m_streams, is_hdf5);
+
+ /* We can't open an HDF5 file from a stream, so close it. */
+ if (is_hdf5) {
+ m_infile.close();
+ m_streams.clear();
+ }
+ }
+
+ bool valid() const
+ {
+ return m_archive.valid();
+ }
+
+ IObject getTop()
+ {
+ return m_archive.getTop();
+ }
+};
+
+struct AbcArchiveHandle {
+ int unused;
+};
+
+ABC_INLINE ArchiveWrapper *archive_from_handle(AbcArchiveHandle *handle)
+{
+ return reinterpret_cast<ArchiveWrapper *>(handle);
+}
+
+ABC_INLINE AbcArchiveHandle *handle_from_archive(ArchiveWrapper *archive)
+{
+ return reinterpret_cast<AbcArchiveHandle *>(archive);
}
//#define USE_NURBS
@@ -247,9 +301,10 @@ static void gather_objects_paths(const IObject &object, ListBase *object_paths)
AbcArchiveHandle *ABC_create_handle(const char *filename, ListBase *object_paths)
{
- IArchive *archive = open_archive(filename);
+ ArchiveWrapper *archive = new ArchiveWrapper(filename);
- if (!archive) {
+ if (!archive->valid()) {
+ delete archive;
return NULL;
}
@@ -582,12 +637,10 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
data->do_update = do_update;
data->progress = progress;
- IArchive *archive = open_archive(data->filename);
+ ArchiveWrapper *archive = new ArchiveWrapper(data->filename);
- if (!archive || !archive->valid()) {
- if (archive) {
- delete archive;
- }
+ if (!archive->valid()) {
+ delete archive;
data->error_code = ABC_ARCHIVE_FAIL;
return;
}
@@ -812,7 +865,7 @@ void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence
void ABC_get_transform(AbcArchiveHandle *handle, Object *ob, const char *object_path, float r_mat[4][4], float time, float scale)
{
- IArchive *archive = archive_from_handle(handle);
+ ArchiveWrapper *archive = archive_from_handle(handle);
if (!archive || !archive->valid()) {
return;
@@ -1088,7 +1141,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle,
const char **err_str,
int read_flag)
{
- IArchive *archive = archive_from_handle(handle);
+ ArchiveWrapper *archive = archive_from_handle(handle);
if (!archive || !archive->valid()) {
*err_str = "Invalid archive!";
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 483fefbd89c..189340db618 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
@@ -37,7 +37,7 @@
/* can be left blank, otherwise a,b,c... etc with no quotes */
#define BLENDER_VERSION_CHAR
/* alpha/beta/rc/release, docs use this */
-#define BLENDER_VERSION_CYCLE alpha
+#define BLENDER_VERSION_CYCLE rc
extern char versionstr[]; /* from blender.c */
diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h
index 51b161f1a06..7a9744ef9d6 100644
--- a/source/blender/blenkernel/BKE_cachefile.h
+++ b/source/blender/blenkernel/BKE_cachefile.h
@@ -38,6 +38,8 @@ struct CacheFile;
struct Main;
struct Scene;
+void BKE_cachefiles_init(void);
+
void *BKE_cachefile_add(struct Main *bmain, const char *name);
void BKE_cachefile_init(struct CacheFile *cache_file);
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 79e500f8ceb..714417ae29e 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -2282,7 +2282,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,11 +2565,15 @@ 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,
+ const 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))
{
SubsurfModifierData *smd = (SubsurfModifierData *)last_md;
/* TODO(sergey): Deduplicate this with checks from subsurf_ccg.c. */
@@ -2589,7 +2593,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 +2628,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
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index aebd564ca58..3bc81a69c86 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -617,9 +617,9 @@ void BKE_pose_eval_bone(EvaluationContext *UNUSED(eval_ctx),
/* pass */
}
else {
- /* TODO(sergey): Use time source node for time. */
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
if ((pchan->flag & POSE_DONE) == 0) {
+ /* TODO(sergey): Use time source node for time. */
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
}
}
@@ -641,8 +641,8 @@ void BKE_pose_constraints_evaluate(EvaluationContext *UNUSED(eval_ctx),
/* IK are being solved separately/ */
}
else {
- float ctime = BKE_scene_frame_get(scene); /* not accurate... */
if ((pchan->flag & POSE_DONE) == 0) {
+ float ctime = BKE_scene_frame_get(scene); /* not accurate... */
BKE_pose_where_is_bone(scene, ob, pchan, ctime, 1);
}
}
diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c
index 16f263791db..502f1d53ab2 100644
--- a/source/blender/blenkernel/intern/cachefile.c
+++ b/source/blender/blenkernel/intern/cachefile.c
@@ -35,6 +35,7 @@
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "BKE_animsys.h"
@@ -48,6 +49,13 @@
# include "ABC_alembic.h"
#endif
+static SpinLock spin;
+
+void BKE_cachefiles_init(void)
+{
+ BLI_spin_init(&spin);
+}
+
void *BKE_cachefile_add(Main *bmain, const char *name)
{
CacheFile *cache_file = BKE_libblock_alloc(bmain, ID_CF, name);
@@ -65,6 +73,7 @@ void BKE_cachefile_init(CacheFile *cache_file)
cache_file->frame = 0.0f;
cache_file->is_sequence = false;
cache_file->scale = 1.0f;
+ cache_file->handle_mutex = BLI_mutex_alloc();
}
/** Free (or release) any data used by this cachefile (does not free the cachefile itself). */
@@ -76,6 +85,7 @@ void BKE_cachefile_free(CacheFile *cache_file)
ABC_free_handle(cache_file->handle);
#endif
+ BLI_mutex_free(cache_file->handle_mutex);
BLI_freelistN(&cache_file->object_paths);
}
@@ -114,9 +124,19 @@ void BKE_cachefile_reload(const Main *bmain, CacheFile *cache_file)
void BKE_cachefile_ensure_handle(const Main *bmain, CacheFile *cache_file)
{
+ BLI_spin_lock(&spin);
+ if (cache_file->handle_mutex == NULL) {
+ cache_file->handle_mutex = BLI_mutex_alloc();
+ }
+ BLI_spin_unlock(&spin);
+
+ BLI_mutex_lock(cache_file->handle_mutex);
+
if (cache_file->handle == NULL) {
BKE_cachefile_reload(bmain, cache_file);
}
+
+ BLI_mutex_unlock(cache_file->handle_mutex);
}
void BKE_cachefile_update_frame(Main *bmain, Scene *scene, const float ctime, const float fps)
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 70fdd4aa72e..c4afa58b7d3 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -4344,7 +4344,7 @@ static bConstraintTypeInfo CTI_OBJECTSOLVER = {
static void transformcache_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
{
bTransformCacheConstraint *data = con->data;
- func(con, (ID **)&data->cache_file, false, userdata);
+ func(con, (ID **)&data->cache_file, true, userdata);
}
static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targets)
@@ -4353,11 +4353,15 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa
bTransformCacheConstraint *data = con->data;
Scene *scene = cob->scene;
- const float frame = BKE_scene_frame_get(scene);
- const float time = BKE_cachefile_time_offset(data->cache_file, frame, FPS);
-
CacheFile *cache_file = data->cache_file;
+ if (!cache_file) {
+ return;
+ }
+
+ const float frame = BKE_scene_frame_get(scene);
+ const float time = BKE_cachefile_time_offset(cache_file, frame, FPS);
+
BKE_cachefile_ensure_handle(G.main, cache_file);
ABC_get_transform(cache_file->handle, cob->ob, data->object_path,
@@ -4391,6 +4395,13 @@ static void transformcache_free(bConstraint *con)
}
}
+static void transformcache_new_data(void *cdata)
+{
+ bTransformCacheConstraint *data = (bTransformCacheConstraint *)cdata;
+
+ data->cache_file = NULL;
+}
+
static bConstraintTypeInfo CTI_TRANSFORM_CACHE = {
CONSTRAINT_TYPE_TRANSFORM_CACHE, /* type */
sizeof(bTransformCacheConstraint), /* size */
@@ -4399,7 +4410,7 @@ static bConstraintTypeInfo CTI_TRANSFORM_CACHE = {
transformcache_free, /* free data */
transformcache_id_looper, /* id looper */
transformcache_copy, /* copy data */
- NULL, /* new data */
+ transformcache_new_data, /* new data */
NULL, /* get constraint targets */
NULL, /* flush constraint targets */
NULL, /* get target matrix */
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 e9d039ad480..d098366aef4 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -154,8 +154,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 4afce3b5f85..61831d92766 100644
--- a/source/blender/blenkernel/intern/library_remap.c
+++ b/source/blender/blenkernel/intern/library_remap.c
@@ -871,8 +871,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 87e55a7ac95..0b15d28ec17 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -977,7 +977,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/scene.c b/source/blender/blenkernel/intern/scene.c
index 73af6a6be65..5454e1f7568 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -1539,10 +1539,11 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
#else
finish_time = PIL_check_seconds_timer();
tot_thread = BLI_system_thread_count();
+ int total_objects = 0;
for (i = 0; i < tot_thread; i++) {
- int total_objects = 0;
- double total_time = 0.0;
+ int thread_total_objects = 0;
+ double thread_total_time = 0.0;
StatisicsEntry *entry;
if (state->has_updated_objects) {
@@ -1551,11 +1552,14 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
entry;
entry = entry->next)
{
- total_objects++;
- total_time += entry->duration;
+ thread_total_objects++;
+ thread_total_time += entry->duration;
}
- printf("Thread %d: total %d objects in %f sec.\n", i, total_objects, total_time);
+ printf("Thread %d: total %d objects in %f sec.\n",
+ i,
+ thread_total_objects,
+ thread_total_time);
for (entry = state->statistics[i].first;
entry;
@@ -1563,12 +1567,16 @@ static void print_threads_statistics(ThreadedObjectUpdateState *state)
{
printf(" %s in %f sec\n", entry->object->id.name + 2, entry->duration);
}
+
+ total_objects += thread_total_objects;
}
BLI_freelistN(&state->statistics[i]);
}
if (state->has_updated_objects) {
- printf("Scene update in %f sec\n", finish_time - state->base_time);
+ printf("Scene updated %d objects in %f sec\n",
+ total_objects,
+ finish_time - state->base_time);
}
#endif
}
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index d5d3384bb48..a86606f1099 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -330,7 +330,7 @@ void BKE_tracking_settings_init(MovieTracking *tracking)
tracking->settings.object_distance = 1;
tracking->stabilization.scaleinf = 1.0f;
- tracking->stabilization.anchor_frame = MINFRAME;
+ tracking->stabilization.anchor_frame = 1;
zero_v2(tracking->stabilization.target_pos);
tracking->stabilization.target_rot = 0.0f;
tracking->stabilization.scale = 1.0f;
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index 4d72d851ae9..df42f253fdf 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -452,6 +452,29 @@ static MovieTrackingMarker *get_tracking_data_point(
}
}
+
+/* Define the reference point for rotation/scale measurement and compensation.
+ * The stabilizator works by assuming the image was distorted by a affine linear
+ * transform, i.e. it was rotated and stretched around this reference point
+ * (pivot point) and then shifted laterally. Any scale and orientation changes
+ * will be picked up relative to this point. And later the image will be
+ * stabilized by rotating around this point. The result can only be as
+ * accurate as this pivot point actually matches the real rotation center
+ * of the actual movements. Thus any scheme to define a pivot point is
+ * always guesswork.
+ *
+ * As a simple default, we use the weighted average of the location markers
+ * of the current frame as pivot point. TODO It is planned to add further
+ * options, like e.g. anchoring the pivot point at the canvas. Moreover,
+ * it is planned to allow for a user controllable offset.
+ */
+static void setup_pivot(const float ref_pos[2], float r_pivot[2])
+{
+ zero_v2(r_pivot); /* TODO: add an animated offset position here. */
+ add_v2_v2(r_pivot, ref_pos);
+}
+
+
/* Calculate the contribution of a single track at the time position (frame) of
* the given marker. Each track has a local reference frame, which is as close
* as possible to the global anchor_frame. Thus the translation contribution is
@@ -508,22 +531,21 @@ static void translation_contribution(TrackStabilizationBase *track_ref,
* in the same framework, we average the scales as logarithms.
*
* aspect is a total aspect ratio of the undistorted image (includes fame and
- * pixel aspect).
+ * pixel aspect). The function returns a quality factor, which can be used
+ * to damp the contributions of points in close proximity to the pivot point,
+ * since such contributions might be dominated by rounding errors and thus
+ * poison the calculated average. When the quality factor goes towards zero,
+ * the weight of this contribution should be reduced accordingly.
*/
-static void rotation_contribution(TrackStabilizationBase *track_ref,
- MovieTrackingMarker *marker,
- float aspect,
- float target_pos[2],
- float averaged_translation_contribution[2],
- float *result_angle,
- float *result_scale)
+static float rotation_contribution(TrackStabilizationBase *track_ref,
+ MovieTrackingMarker *marker,
+ const float aspect,
+ const float pivot[2],
+ float *result_angle,
+ float *result_scale)
{
- float len;
+ float len, quality;
float pos[2];
- float pivot[2];
- copy_v2_fl(pivot, 0.5f); /* Use center of frame as hard wired pivot. */
- add_v2_v2(pivot, averaged_translation_contribution);
- sub_v2_v2(pivot, target_pos);
sub_v2_v2v2(pos, marker->pos, pivot);
pos[0] *= aspect;
@@ -531,9 +553,47 @@ static void rotation_contribution(TrackStabilizationBase *track_ref,
*result_angle = atan2f(pos[1],pos[0]);
- len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS;
+ len = len_v2(pos);
+
+ /* prevent points very close to the pivot point from poisoning the result */
+ quality = 1 - expf(-len*len / SCALE_ERROR_LIMIT_BIAS*SCALE_ERROR_LIMIT_BIAS);
+ len += SCALE_ERROR_LIMIT_BIAS;
+
*result_scale = len * track_ref->stabilization_scale_base;
BLI_assert(0.0 < *result_scale);
+
+ return quality;
+}
+
+
+/* Workaround to allow for rotation around an arbitrary pivot point.
+ * Currently, the public API functions do not support this flexibility.
+ * Rather, rotation will always be applied around a fixed origin.
+ * As a workaround, we shift the image after rotation to match the
+ * desired rotation centre. And since this offset needs to be applied
+ * after the rotation and scaling, we can collapse it with the
+ * translation compensation, which is also a lateral shift (offset).
+ * The offset to apply is intended_pivot - rotated_pivot
+ */
+static void compensate_rotation_center(const int size, float aspect,
+ const float angle,
+ const float scale,
+ const float pivot[2],
+ float result_translation[2])
+{
+ const float origin[2] = {0.5f*aspect*size, 0.5f*size};
+ float intended_pivot[2], rotated_pivot[2];
+ float rotation_mat[2][2];
+
+ copy_v2_v2(intended_pivot, pivot);
+ copy_v2_v2(rotated_pivot, pivot);
+ rotate_m2(rotation_mat, +angle);
+ sub_v2_v2(rotated_pivot, origin);
+ mul_m2v2(rotation_mat, rotated_pivot);
+ mul_v2_fl(rotated_pivot, scale);
+ add_v2_v2(rotated_pivot, origin);
+ add_v2_v2(result_translation, intended_pivot);
+ sub_v2_v2(result_translation, rotated_pivot);
}
@@ -553,6 +613,7 @@ static bool average_track_contributions(StabContext *ctx,
int framenr,
float aspect,
float r_translation[2],
+ float r_pivot[2],
float *r_angle,
float *r_scale_step)
{
@@ -561,12 +622,15 @@ static bool average_track_contributions(StabContext *ctx,
MovieTrackingTrack *track;
MovieTracking *tracking = ctx->tracking;
MovieTrackingStabilization *stab = &tracking->stabilization;
+ float ref_pos[2];
BLI_assert(stab->flag & TRACKING_2D_STABILIZATION);
zero_v2(r_translation);
*r_scale_step = 0.0f; /* logarithm */
*r_angle = 0.0f;
+ zero_v2(ref_pos);
+
ok = false;
weight_sum = 0.0f;
for (track = tracking->tracks.first; track; track = track->next) {
@@ -586,8 +650,10 @@ static bool average_track_contributions(StabContext *ctx,
float offset[2];
weight_sum += weight;
translation_contribution(stabilization_base, marker, offset);
- mul_v2_fl(offset, weight);
- add_v2_v2(r_translation, offset);
+ r_translation[0] += weight * offset[0];
+ r_translation[1] += weight * offset[1];
+ ref_pos[0] += weight * marker->pos[0];
+ ref_pos[1] += weight * marker->pos[1];
ok |= (weight_sum > EPSILON_WEIGHT);
}
}
@@ -596,8 +662,11 @@ static bool average_track_contributions(StabContext *ctx,
return false;
}
+ ref_pos[0] /= weight_sum;
+ ref_pos[1] /= weight_sum;
r_translation[0] /= weight_sum;
r_translation[1] /= weight_sum;
+ setup_pivot(ref_pos, r_pivot);
if (!(stab->flag & TRACKING_STABILIZE_ROTATION)) {
return ok;
@@ -619,17 +688,15 @@ static bool average_track_contributions(StabContext *ctx,
TrackStabilizationBase *stabilization_base =
access_stabilization_baseline_data(ctx, track);
BLI_assert(stabilization_base != NULL);
- float rotation, scale;
- float target_pos[2];
+ float rotation, scale, quality;
+ quality = rotation_contribution(stabilization_base,
+ marker,
+ aspect,
+ r_pivot,
+ &rotation,
+ &scale);
+ weight *= quality;
weight_sum += weight;
- get_animated_target_pos(ctx, framenr, target_pos);
- rotation_contribution(stabilization_base,
- marker,
- aspect,
- target_pos,
- r_translation,
- &rotation,
- &scale);
*r_angle += rotation * weight;
if (stab->flag & TRACKING_STABILIZE_SCALE) {
*r_scale_step += logf(scale) * weight;
@@ -656,6 +723,75 @@ static bool average_track_contributions(StabContext *ctx,
}
+/* Calculate weight center of location tracks for given frame.
+ * This function performs similar calculations as average_track_contributions(),
+ * but does not require the tracks to be initialized for stabilisation. Moreover,
+ * when there is no usable tracking data for the given frame number, data from
+ * a neighbouring frame is used. Thus this function can be used to calculate
+ * a starting point on initialization.
+ */
+static void average_marker_positions(StabContext *ctx, int framenr, float r_ref_pos[2])
+{
+ bool ok = false;
+ float weight_sum;
+ MovieTrackingTrack *track;
+ MovieTracking *tracking = ctx->tracking;
+
+ zero_v2(r_ref_pos);
+ weight_sum = 0.0f;
+ for (track = tracking->tracks.first; track; track = track->next) {
+ if (track->flag & TRACK_USE_2D_STAB) {
+ float weight = 0.0f;
+ MovieTrackingMarker *marker =
+ get_tracking_data_point(ctx, track, framenr, &weight);
+ if (marker) {
+ weight_sum += weight;
+ r_ref_pos[0] += weight * marker->pos[0];
+ r_ref_pos[1] += weight * marker->pos[1];
+ ok |= (weight_sum > EPSILON_WEIGHT);
+ }
+ }
+ }
+ if (ok) {
+ r_ref_pos[0] /= weight_sum;
+ r_ref_pos[1] /= weight_sum;
+ } else {
+ /* No usable tracking data on any track on this frame.
+ * Use data from neighbouring frames to extrapolate...
+ */
+ int next_lower = MINAFRAME;
+ int next_higher = MAXFRAME;
+ use_values_from_fcurves(ctx, true);
+ for (track = tracking->tracks.first; track; track = track->next) {
+ /* Note: we deliberately do not care if this track
+ * is already initialized for stabilisation */
+ if (track->flag & TRACK_USE_2D_STAB) {
+ int startpoint = search_closest_marker_index(track, framenr);
+ retrieve_next_higher_usable_frame(ctx,
+ track,
+ startpoint,
+ framenr,
+ &next_higher);
+ retrieve_next_lower_usable_frame(ctx,
+ track,
+ startpoint,
+ framenr,
+ &next_lower);
+ }
+ }
+ if (next_lower >= MINFRAME) {
+ /* use next usable frame to the left.
+ * Also default to this frame when we're in a gap */
+ average_marker_positions(ctx, next_lower, r_ref_pos);
+
+ } else if (next_higher < MAXFRAME) {
+ average_marker_positions(ctx, next_higher, r_ref_pos);
+ }
+ use_values_from_fcurves(ctx, false);
+ }
+}
+
+
/* Linear interpolation of data retrieved at two measurement points.
* This function is used to fill gaps in the middle of the covered area,
* at frames without any usable tracks for stabilization.
@@ -670,8 +806,9 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx,
int framenr,
int frame_a,
int frame_b,
- float aspect,
- float translation[2],
+ const float aspect,
+ float r_translation[2],
+ float r_pivot[2],
float *r_angle,
float *r_scale_step)
{
@@ -679,6 +816,7 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx,
float trans_a[2], trans_b[2];
float angle_a, angle_b;
float scale_a, scale_b;
+ float pivot_a[2], pivot_b[2];
bool success = false;
BLI_assert(frame_a <= frame_b);
@@ -688,16 +826,17 @@ static bool interpolate_averaged_track_contributions(StabContext *ctx,
t = ((float)framenr - frame_a) / (frame_b - frame_a);
s = 1.0f - t;
- success = average_track_contributions(ctx, frame_a, aspect, trans_a, &angle_a, &scale_a);
+ success = average_track_contributions(ctx, frame_a, aspect, trans_a, pivot_a, &angle_a, &scale_a);
if (!success) {
return false;
}
- success = average_track_contributions(ctx, frame_b, aspect, trans_b, &angle_b, &scale_b);
+ success = average_track_contributions(ctx, frame_b, aspect, trans_b, pivot_b, &angle_b, &scale_b);
if (!success) {
return false;
}
- interp_v2_v2v2(translation, trans_a, trans_b, t);
+ interp_v2_v2v2(r_translation, trans_a, trans_b, t);
+ interp_v2_v2v2(r_pivot, pivot_a, pivot_b, t);
*r_scale_step = s * scale_a + t * scale_b;
*r_angle = s * angle_a + t * angle_b;
return true;
@@ -802,13 +941,12 @@ static void initialize_track_for_stabilization(StabContext *ctx,
MovieTrackingTrack *track,
int reference_frame,
float aspect,
- const float target_pos[2],
const float average_translation[2],
- float average_angle,
- float average_scale_step)
+ const float pivot[2],
+ const float average_angle,
+ const float average_scale_step)
{
float pos[2], angle, len;
- float pivot[2];
TrackStabilizationBase *local_data =
access_stabilization_baseline_data(ctx, track);
MovieTrackingMarker *marker =
@@ -825,9 +963,6 @@ static void initialize_track_for_stabilization(StabContext *ctx,
marker->pos);
/* Per track baseline value for rotation. */
- copy_v2_fl(pivot, 0.5f); /* Use center of frame as hard wired pivot. */
- add_v2_v2(pivot, average_translation);
- sub_v2_v2(pivot, target_pos);
sub_v2_v2v2(pos, marker->pos, pivot);
pos[0] *= aspect;
@@ -855,10 +990,9 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
*/
int reference_frame = tracking->stabilization.anchor_frame;
float average_angle=0, average_scale_step=0;
- float average_translation[2];
- float target_pos_at_ref_frame[2];
- zero_v2(target_pos_at_ref_frame);
+ float average_translation[2], average_pos[2], pivot[2];
zero_v2(average_translation);
+ zero_v2(pivot);
/* Initialize private working data. */
for (track = tracking->tracks.first; track != NULL; track = track->next) {
@@ -891,6 +1025,10 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
goto cleanup;
}
+ /* starting point for pivot, before having initialized any track */
+ average_marker_positions(ctx, reference_frame, average_pos);
+ setup_pivot(average_pos, pivot);
+
for (i = 0; i < track_cnt; ++i) {
track = order[i].data;
if (reference_frame != order[i].reference_frame) {
@@ -899,18 +1037,16 @@ static void initialize_all_tracks(StabContext *ctx, float aspect)
reference_frame,
aspect,
average_translation,
+ pivot,
&average_angle,
&average_scale_step);
- get_animated_target_pos(ctx,
- reference_frame,
- target_pos_at_ref_frame);
}
initialize_track_for_stabilization(ctx,
track,
reference_frame,
aspect,
- target_pos_at_ref_frame,
average_translation,
+ pivot,
average_angle,
average_scale_step);
}
@@ -936,6 +1072,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx,
int framenr,
float aspect,
float r_translation[2],
+ float r_pivot[2],
float *r_angle,
float *r_scale_step)
{
@@ -953,6 +1090,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx,
framenr,
aspect,
r_translation,
+ r_pivot,
r_angle,
r_scale_step);
if (!success) {
@@ -971,6 +1109,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx,
next_higher,
aspect,
r_translation,
+ r_pivot,
r_angle,
r_scale_step);
}
@@ -982,6 +1121,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx,
next_higher,
aspect,
r_translation,
+ r_pivot,
r_angle,
r_scale_step);
}
@@ -991,6 +1131,7 @@ static bool stabilization_determine_offset_for_frame(StabContext *ctx,
next_lower,
aspect,
r_translation,
+ r_pivot,
r_angle,
r_scale_step);
}
@@ -1017,16 +1158,17 @@ static void stabilization_calculate_data(StabContext *ctx,
bool do_compensate,
float scale_step,
float r_translation[2],
+ float r_pivot[2],
float *r_scale,
float *r_angle)
{
- float target_pos[2];
+ float target_pos[2], target_scale;
float scaleinf = get_animated_scaleinf(ctx, framenr);
- *r_scale = (get_animated_target_scale(ctx,framenr) - 1.0f) * scaleinf + 1.0f;
-
if (ctx->stab->flag & TRACKING_STABILIZE_SCALE) {
- *r_scale *= expf(scale_step * scaleinf); /* Averaged in log scale */
+ *r_scale = expf(scale_step * scaleinf); /* Averaged in log scale */
+ } else {
+ *r_scale = 1.0f;
}
mul_v2_fl(r_translation, get_animated_locinf(ctx, framenr));
@@ -1039,10 +1181,17 @@ static void stabilization_calculate_data(StabContext *ctx,
get_animated_target_pos(ctx, framenr, target_pos);
sub_v2_v2(r_translation, target_pos);
*r_angle -= get_animated_target_rot(ctx,framenr);
+ target_scale = get_animated_target_scale(ctx,framenr);
+ if (target_scale != 0.0f) {
+ *r_scale /= target_scale;
+ /* target_scale is an expected/intended reference zoom value */
+ }
/* Convert from relative to absolute coordinates, square pixels. */
r_translation[0] *= (float)size * aspect;
r_translation[1] *= (float)size;
+ r_pivot[0] *= (float)size * aspect;
+ r_pivot[1] *= (float)size;
/* Output measured data, or inverse of the measured values for
* compensation?
@@ -1056,25 +1205,61 @@ static void stabilization_calculate_data(StabContext *ctx,
}
}
+static void stabilization_data_to_mat4(float pixel_aspect,
+ const float pivot[2],
+ const float translation[2],
+ float scale,
+ float angle,
+ float r_mat[4][4])
+{
+ float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4],
+ pivot_mat[4][4], inv_pivot_mat[4][4],
+ aspect_mat[4][4], inv_aspect_mat[4][4];
+ float scale_vector[3] = {scale, scale, 1.0f};
-/* Determine the inner part of the frame, which is always safe to use.
- * When enlarging the image by the inverse of this factor, any black areas
- * appearing due to frame translation and rotation will be removed.
+ unit_m4(translation_mat);
+ unit_m4(rotation_mat);
+ unit_m4(scale_mat);
+ unit_m4(aspect_mat);
+ unit_m4(pivot_mat);
+ unit_m4(inv_pivot_mat);
+
+ /* aspect ratio correction matrix */
+ aspect_mat[0][0] /= pixel_aspect;
+ invert_m4_m4(inv_aspect_mat, aspect_mat);
+
+ add_v2_v2(pivot_mat[3], pivot);
+ sub_v2_v2(inv_pivot_mat[3], pivot);
+
+ size_to_mat4(scale_mat, scale_vector); /* scale matrix */
+ add_v2_v2(translation_mat[3], translation); /* translation matrix */
+ rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
+
+ /* Compose transformation matrix. */
+ mul_m4_series(r_mat, aspect_mat, translation_mat,
+ pivot_mat, scale_mat, rotation_mat, inv_pivot_mat,
+ inv_aspect_mat);
+}
+
+/* Calculate scale factor necessary to eliminate black image areas
+ * caused by the compensating movements of the stabilizator.
+ * This function visits every frame where stabilisation data is
+ * available and determines the factor for this frame. The overall
+ * largest factor found is returned as result.
*
- * NOTE: When calling this function, basic initialization of tracks must be
- * done already
+ * NOTE: all tracks need to be initialized before calling this function.
*/
-static void stabilization_determine_safe_image_area(StabContext *ctx,
- int size,
- float image_aspect)
+static float calculate_autoscale_factor(StabContext *ctx,
+ int size,
+ float aspect)
{
MovieTrackingStabilization *stab = ctx->stab;
float pixel_aspect = ctx->tracking->camera.pixel_aspect;
+ int height = size, width = aspect*size;
int sfra = INT_MAX, efra = INT_MIN, cfra;
float scale = 1.0f, scale_step = 0.0f;
MovieTrackingTrack *track;
- stab->scale = 1.0f;
/* Calculate maximal frame range of tracks where stabilization is active. */
for (track = ctx->tracking->tracks.first; track; track = track->next) {
@@ -1089,124 +1274,117 @@ static void stabilization_determine_safe_image_area(StabContext *ctx,
}
}
- /* For every frame we calculate scale factor needed to eliminate black border area
- * and choose largest scale factor as final one.
- */
+ use_values_from_fcurves(ctx, true);
for (cfra = sfra; cfra <= efra; cfra++) {
- float translation[2], angle, tmp_scale;
- int i;
+ float translation[2], pivot[2], angle, tmp_scale;
float mat[4][4];
- float points[4][2] = {{0.0f, 0.0f},
- {0.0f, size},
- {image_aspect * size, size},
- {image_aspect * size, 0.0f}};
- float si, co;
- bool do_compensate = true;
-
+ const float points[4][2] = {{0.0f, 0.0f},
+ {0.0f, height},
+ {width, height},
+ {width, 0.0f}};
+ const bool do_compensate = true;
+ /* Calculate stabilization parameters for the current frame. */
stabilization_determine_offset_for_frame(ctx,
cfra,
- image_aspect,
+ aspect,
translation,
+ pivot,
&angle,
&scale_step);
stabilization_calculate_data(ctx,
cfra,
size,
- image_aspect,
+ aspect,
do_compensate,
scale_step,
translation,
+ pivot,
&tmp_scale,
&angle);
-
- BKE_tracking_stabilization_data_to_mat4(size * image_aspect,
- size,
- pixel_aspect,
- translation,
- 1.0f,
- angle,
- mat);
-
- si = sinf(angle);
- co = cosf(angle);
-
+ /* Compose transformation matrix. */
+ /* NOTE: Here we operate in NON-COMPENSATED coordinates, meaning we have
+ * to construct transformation matrix using proper pivot point.
+ * Compensation for that will happen later on.
+ */
+ stabilization_data_to_mat4(pixel_aspect,
+ pivot,
+ translation,
+ tmp_scale,
+ angle,
+ mat);
/* Investigate the transformed border lines for this frame;
* find out, where it cuts the original frame.
*/
- for (i = 0; i < 4; i++) {
- int j;
- float a[3] = {0.0f, 0.0f, 0.0f},
- b[3] = {0.0f, 0.0f, 0.0f};
-
- copy_v2_v2(a, points[i]);
- copy_v2_v2(b, points[(i + 1) % 4]);
- a[2] = b[2] = 0.0f;
-
- mul_m4_v3(mat, a);
- mul_m4_v3(mat, b);
-
- for (j = 0; j < 4; j++) {
- float point[3] = {points[j][0], points[j][1], 0.0f};
- float v1[3], v2[3];
-
- sub_v3_v3v3(v1, b, a);
- sub_v3_v3v3(v2, point, a);
-
- if (cross_v2v2(v1, v2) >= 0.0f) {
- const float rot_dx[4][2] = {{1.0f, 0.0f},
- {0.0f, -1.0f},
- {-1.0f, 0.0f},
- {0.0f, 1.0f}};
- const float rot_dy[4][2] = {{0.0f, 1.0f},
- {1.0f, 0.0f},
- {0.0f, -1.0f},
- {-1.0f, 0.0f}};
-
- float dx = translation[0] * rot_dx[j][0] +
- translation[1] * rot_dx[j][1],
- dy = translation[0] * rot_dy[j][0] +
- translation[1] * rot_dy[j][1];
-
- float w, h, E, F, G, H, I, J, K, S;
-
- if (j % 2) {
- w = (float)size / 2.0f;
- h = image_aspect*size / 2.0f;
- }
- else {
- w = image_aspect*size / 2.0f;
- h = (float)size / 2.0f;
- }
-
- E = -w * co + h * si;
- F = -h * co - w * si;
-
- if ((i % 2) == (j % 2)) {
- G = -w * co - h * si;
- H = h * co - w * si;
- }
- else {
- G = w * co + h * si;
- H = -h * co + w * si;
- }
-
- I = F - H;
- J = G - E;
- K = G * F - E * H;
-
- S = (dx * I + dy * J + K) / (-w * I - h * J);
-
- scale = min_ff(scale, S);
+ for (int edge_index = 0; edge_index < 4; edge_index++) {
+ /* Calculate coordinates of stabilized frame edge points.
+ * Use matrix multiplication here so we operate in homogeneous
+ * coordinates.
+ */
+ float stable_edge_p1[3], stable_edge_p2[3];
+ copy_v2_v2(stable_edge_p1, points[edge_index]);
+ copy_v2_v2(stable_edge_p2, points[(edge_index + 1) % 4]);
+ stable_edge_p1[2] = stable_edge_p2[2] = 0.0f;
+ mul_m4_v3(mat, stable_edge_p1);
+ mul_m4_v3(mat, stable_edge_p2);
+ /* Now we iterate over all original frame corners (we call them
+ * 'point' here) to see if there's black area between stabilized
+ * frame edge and original point.
+ */
+ for (int point_index = 0; point_index < 4; point_index++) {
+ const float point[3] = {points[point_index][0],
+ points[point_index][1],
+ 0.0f};
+ /* Calculate vector which goes from first edge point to
+ * second one.
+ */
+ float stable_edge_vec[3];
+ sub_v3_v3v3(stable_edge_vec, stable_edge_p2, stable_edge_p1);
+ /* Calculate vector which connects current frame point to
+ * first edge point.
+ */
+ float point_to_edge_start_vec[3];
+ sub_v3_v3v3(point_to_edge_start_vec, point, stable_edge_p1);
+ /* Use this two vectors to check whether frame point is inside
+ * of the stabilized frame or not.
+ * If the point is inside, there is no black area happening
+ * and no scaling required for it.
+ */
+ if (cross_v2v2(stable_edge_vec, point_to_edge_start_vec) >= 0.0f) {
+ /* We are scaling around motion-compensated pivot point. */
+ float scale_pivot[2];
+ add_v2_v2v2(scale_pivot, pivot, translation);
+ /* Calculate line which goes via `point` and parallel to
+ * the stabilized frame edge. This line is coming via
+ * `point` and `point2` at the end.
+ */
+ float point2[2];
+ add_v2_v2v2(point2, point, stable_edge_vec);
+ /* Calculate actual distance between pivot point and
+ * the stabilized frame edge. Then calculate distance
+ * between pivot point and line which goes via actual
+ * corner and is parallel to the edge.
+ *
+ * Dividing one by another will give us required scale
+ * factor to get rid of black areas.
+ */
+ float real_dist = dist_to_line_v2(scale_pivot,
+ stable_edge_p1,
+ stable_edge_p2);
+ float required_dist = dist_to_line_v2(scale_pivot,
+ point,
+ point2);
+ const float S = required_dist / real_dist;
+ scale = max_ff(scale, S);
}
}
}
}
-
- stab->scale = scale;
-
if (stab->maxscale > 0.0f) {
- stab->scale = max_ff(stab->scale, 1.0f / stab->maxscale);
+ scale = min_ff(scale, stab->maxscale);
}
+ use_values_from_fcurves(ctx, false);
+
+ return scale;
}
@@ -1218,19 +1396,14 @@ static void stabilization_determine_safe_image_area(StabContext *ctx,
* turns out to be tricky, hard to maintain and generally not worth the
* effort. Thus we'll re-initialize on every frame.
*/
-static StabContext *init_stabilizer(MovieClip *clip, int width, int height)
+static StabContext *init_stabilizer(MovieClip *clip, int size, float aspect)
{
- MovieTracking *tracking = &clip->tracking;
- MovieTrackingStabilization *stab = &tracking->stabilization;
- float pixel_aspect = tracking->camera.pixel_aspect;
- float aspect = (float)width * pixel_aspect / height;
- int size = height;
-
StabContext *ctx = initialize_stabilization_working_context(clip);
BLI_assert(ctx != NULL);
initialize_all_tracks(ctx, aspect);
- if (stab->flag & TRACKING_AUTOSCALE) {
- stabilization_determine_safe_image_area(ctx, size, aspect);
+ if (ctx->stab->flag & TRACKING_AUTOSCALE) {
+ ctx->stab->scale = 1.0;
+ ctx->stab->scale = calculate_autoscale_factor(ctx, size, aspect);
}
/* By default, just use values for the global current frame. */
use_values_from_fcurves(ctx, false);
@@ -1275,9 +1448,10 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip,
float pixel_aspect = tracking->camera.pixel_aspect;
float aspect = (float)width * pixel_aspect / height;
int size = height;
+ float pivot[2];
if (enabled) {
- ctx = init_stabilizer(clip, width, height);
+ ctx = init_stabilizer(clip, size, aspect);
}
if (enabled &&
@@ -1285,6 +1459,7 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip,
framenr,
aspect,
translation,
+ pivot,
angle,
&scale_step))
{
@@ -1295,8 +1470,15 @@ void BKE_tracking_stabilization_data_get(MovieClip *clip,
do_compensate,
scale_step,
translation,
+ pivot,
scale,
angle);
+ compensate_rotation_center(size,
+ aspect,
+ *angle,
+ *scale,
+ pivot,
+ translation);
}
else {
zero_v2(translation);
@@ -1426,47 +1608,30 @@ ImBuf *BKE_tracking_stabilize_frame(MovieClip *clip,
void BKE_tracking_stabilization_data_to_mat4(int buffer_width,
int buffer_height,
float pixel_aspect,
- float translation[2], float scale, float angle,
- float mat[4][4])
+ float translation[2],
+ float scale,
+ float angle,
+ float r_mat[4][4])
{
- float translation_mat[4][4], rotation_mat[4][4], scale_mat[4][4],
- pivot_mat[4][4], inv_pivot_mat[4][4],
- aspect_mat[4][4], inv_aspect_mat[4][4];
- float scale_vector[3] = {scale, scale, 1.0f};
-
- float pivot[2]; /* XXX this should be a parameter, it is part of the stabilization data */
-
- /* Use the motion compensated image center as rotation center.
- * This is not 100% correct, but reflects the way the rotation data was
- * measured. Actually we'd need a way to find a good pivot, and use that
- * both for averaging and for compensation.
+ /* Since we cannot receive the real pivot point coordinates (API limitation),
+ * we perform the rotation/scale around the center of frame.
+ * Then we correct by an additional shift, which was calculated in
+ * compensate_rotation_center() and "sneaked in" as additional offset
+ * in the translation parameter. This works, since translation needs to be
+ * applied after rotation/scale anyway. Thus effectively the image gets
+ * rotated around the desired pivot point
*/
/* TODO(sergey) pivot shouldn't be calculated here, rather received
* as a parameter.
*/
- pivot[0] = pixel_aspect * buffer_width / 2.0f - translation[0];
- pivot[1] = (float)buffer_height / 2.0f - translation[1];
-
- unit_m4(translation_mat);
- unit_m4(rotation_mat);
- unit_m4(scale_mat);
- unit_m4(aspect_mat);
- unit_m4(pivot_mat);
- unit_m4(inv_pivot_mat);
-
- /* aspect ratio correction matrix */
- aspect_mat[0][0] /= pixel_aspect;
- invert_m4_m4(inv_aspect_mat, aspect_mat);
-
- add_v2_v2(pivot_mat[3], pivot);
- sub_v2_v2(inv_pivot_mat[3], pivot);
-
- size_to_mat4(scale_mat, scale_vector); /* scale matrix */
- add_v2_v2(translation_mat[3], translation); /* translation matrix */
- rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
-
- /* compose transformation matrix */
- mul_m4_series(mat, aspect_mat, translation_mat,
- pivot_mat, scale_mat, rotation_mat, inv_pivot_mat,
- inv_aspect_mat);
+ float pivot[2];
+ pivot[0] = 0.5f * pixel_aspect * buffer_width;
+ pivot[1] = 0.5f * buffer_height;
+ /* Compose transformation matrix. */
+ stabilization_data_to_mat4(pixel_aspect,
+ pivot,
+ translation,
+ scale,
+ angle,
+ r_mat);
}
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/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 999616f3865..a476b18eaac 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2705,6 +2705,7 @@ static void lib_link_cachefiles(FileData *fd, Main *bmain)
BLI_listbase_clear(&cache_file->object_paths);
cache_file->handle = NULL;
+ cache_file->handle_mutex = NULL;
if (cache_file->adt) {
lib_link_animdata(fd, &cache_file->id, cache_file->adt);
@@ -2715,6 +2716,7 @@ static void lib_link_cachefiles(FileData *fd, Main *bmain)
static void direct_link_cachefile(FileData *fd, CacheFile *cache_file)
{
cache_file->handle = NULL;
+ cache_file->handle_mutex = NULL;
/* relink animdata */
cache_file->adt = newdataadr(fd, cache_file->adt);
@@ -4930,6 +4932,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.
*
@@ -6309,10 +6314,13 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
* since it gets initialized later */
sima->iuser.scene = NULL;
- sima->scopes.waveform_1 = NULL;
- sima->scopes.waveform_2 = NULL;
- sima->scopes.waveform_3 = NULL;
- sima->scopes.vecscope = NULL;
+#if 0
+ /* Those are allocated and freed by space code, no need to handle them here. */
+ MEM_SAFE_FREE(sima->scopes.waveform_1);
+ MEM_SAFE_FREE(sima->scopes.waveform_2);
+ MEM_SAFE_FREE(sima->scopes.waveform_3);
+ MEM_SAFE_FREE(sima->scopes.vecscope);
+#endif
sima->scopes.ok = 0;
/* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 95ea1fd12cf..d7523ea0dfd 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -90,9 +90,6 @@ static void migrate_single_rot_stabilization_track_settings(MovieTrackingStabili
}
}
stab->rot_track = NULL; /* this field is now ignored */
-
- /* by default show the track lists expanded, to improve "discoverability" */
- stab->flag |= TRACKING_SHOW_STAB_TRACKS;
}
static void do_version_constraints_radians_degrees_270_1(ListBase *lb)
@@ -1221,12 +1218,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 */
@@ -1234,14 +1239,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;
}
@@ -1254,7 +1260,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) {
@@ -1281,13 +1287,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
for (clip = main->movieclip.first; clip != NULL; clip = clip->id.next) {
if (clip->tracking.stabilization.rot_track) {
migrate_single_rot_stabilization_track_settings(&clip->tracking.stabilization);
- if (!clip->tracking.stabilization.scale) {
- /* ensure init.
- * Was previously used for autoscale only,
- * now used always (as "target scale") */
- clip->tracking.stabilization.scale = 1.0f;
- }
}
+ if (clip->tracking.stabilization.scale == 0.0f) {
+ /* ensure init.
+ * Was previously used for autoscale only,
+ * now used always (as "target scale") */
+ clip->tracking.stabilization.scale = 1.0f;
+ }
+ /* blender prefers 1-based frame counting;
+ * thus using frame 1 as reference typically works best */
+ clip->tracking.stabilization.anchor_frame = 1;
+ /* by default show the track lists expanded, to improve "discoverability" */
+ clip->tracking.stabilization.flag |= TRACKING_SHOW_STAB_TRACKS;
+ /* deprecated, not used anymore */
+ clip->tracking.stabilization.ok = false;
}
}
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 12389dc1e7f..8e458d14f1f 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -49,7 +49,7 @@
* <bh.len> int, len data after BHead
* <bh.old> void, old pointer
* <bh.SDNAnr> int
- * <bh.nr> int, in case of array: amount of structs
+ * <bh.nr> int, in case of array: number of structs
* data
* ...
* ...
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
index 76afedf4b2a..ca3c5f7b069 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
@@ -20,6 +20,8 @@
* Monique Dewanchand
*/
+#include <stdlib.h>
+
#include "COM_DoubleEdgeMaskOperation.h"
#include "BLI_math.h"
#include "DNA_node_types.h"
@@ -1151,12 +1153,13 @@ void DoubleEdgeMaskOperation::doDoubleEdgeMask(float *imask, float *omask, float
if (true) { // if both input sockets have some data coming in...
- t = (this->getWidth() * this->getHeight()) - 1; // determine size of the frame
+ rw = this->getWidth(); // width of a row of pixels
+ t = (rw * this->getHeight()) - 1; // determine size of the frame
+ memset(res, 0, sizeof(float) * (t + 1)); // clear output buffer (not all pixels will be written later)
lres = (unsigned int *)res; // unsigned int pointer to output buffer (for bit level ops)
limask = (unsigned int *)imask; // unsigned int pointer to input mask (for bit level ops)
lomask = (unsigned int *)omask; // unsigned int pointer to output mask (for bit level ops)
- rw = this->getWidth(); // width of a row of pixels
/*
diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc
index c3fd202d832..f8cca5393e2 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_LOW,
+ TASK_PRIORITY_HIGH,
thread_id);
}
}
diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
index f9e1504b3ce..7c6c25bef0d 100644
--- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
+++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc
@@ -33,7 +33,7 @@
#include "intern/eval/deg_eval_flush.h"
// TODO(sergey): Use some sort of wrapper.
-#include <queue>
+#include <deque>
extern "C" {
#include "DNA_object_types.h"
@@ -71,7 +71,7 @@ void lib_id_recalc_data_tag(Main *bmain, ID *id)
} /* namespace */
-typedef std::queue<OperationDepsNode *> FlushQueue;
+typedef std::deque<OperationDepsNode *> FlushQueue;
static void flush_init_func(void *data_v, int i)
{
@@ -122,20 +122,60 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
*/
GSET_FOREACH_BEGIN(OperationDepsNode *, node, graph->entry_tags)
{
- queue.push(node);
+ queue.push_back(node);
node->scheduled = true;
}
GSET_FOREACH_END();
+ int num_flushed_objects = 0;
while (!queue.empty()) {
OperationDepsNode *node = queue.front();
- queue.pop();
+ queue.pop_front();
for (;;) {
node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
ComponentDepsNode *comp_node = node->owner;
IDDepsNode *id_node = comp_node->owner;
+
+ ID *id = id_node->id;
+ if(id_node->done == 0) {
+ deg_editors_id_update(bmain, id);
+ lib_id_recalc_tag(bmain, id);
+ /* TODO(sergey): For until we've got proper data nodes in the graph. */
+ lib_id_recalc_data_tag(bmain, id);
+ }
+
+ if(comp_node->done == 0) {
+ Object *object = NULL;
+ if (GS(id->name) == ID_OB) {
+ object = (Object *)id;
+ if(id_node->done == 0) {
+ ++num_flushed_objects;
+ }
+ }
+ foreach (OperationDepsNode *op, comp_node->operations) {
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ if (object != NULL) {
+ /* This code is used to preserve those areas which does
+ * direct object update,
+ *
+ * Plus it ensures visibility changes and relations and
+ * layers visibility update has proper flags to work with.
+ */
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ object->recalc |= OB_RECALC_TIME;
+ }
+ else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
+ object->recalc |= OB_RECALC_OB;
+ }
+ else {
+ object->recalc |= OB_RECALC_DATA;
+ }
+ }
+ }
+
id_node->done = 1;
comp_node->done = 1;
@@ -154,7 +194,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
foreach (DepsRelation *rel, node->outlinks) {
OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
if (to_node->scheduled == false) {
- queue.push(to_node);
+ queue.push_front(to_node);
to_node->scheduled = true;
}
}
@@ -162,52 +202,7 @@ void deg_graph_flush_updates(Main *bmain, Depsgraph *graph)
}
}
}
-
- GHASH_FOREACH_BEGIN(DEG::IDDepsNode *, id_node, graph->id_hash)
- {
- if (id_node->done == 1) {
- ID *id = id_node->id;
- Object *object = NULL;
-
- if (GS(id->name) == ID_OB) {
- object = (Object *)id;
- }
-
- deg_editors_id_update(bmain, id_node->id);
-
- lib_id_recalc_tag(bmain, id_node->id);
- /* TODO(sergey): For until we've got proper data nodes in the graph. */
- lib_id_recalc_data_tag(bmain, id_node->id);
-
- GHASH_FOREACH_BEGIN(const ComponentDepsNode *, comp_node, id_node->components)
- {
- if (comp_node->done) {
- foreach (OperationDepsNode *op, comp_node->operations) {
- op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
- }
- if (object != NULL) {
- /* This code is used to preserve those areas which does
- * direct object update,
- *
- * Plus it ensures visibility changes and relations and
- * layers visibility update has proper flags to work with.
- */
- if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
- object->recalc |= OB_RECALC_TIME;
- }
- else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
- object->recalc |= OB_RECALC_OB;
- }
- else {
- object->recalc |= OB_RECALC_DATA;
- }
- }
- }
- }
- GHASH_FOREACH_END();
- }
- }
- GHASH_FOREACH_END();
+ DEG_DEBUG_PRINTF("Update flushed to %d objects\n", num_flushed_objects);
}
static void graph_clear_func(void *data_v, int i)
diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c
index 2aa6d30c114..9560ab188a4 100644
--- a/source/blender/editors/gpencil/gpencil_data.c
+++ b/source/blender/editors/gpencil/gpencil_data.c
@@ -75,9 +75,6 @@
#include "gpencil_intern.h"
-/* maximum sizes of gp-session buffer */
-#define GP_STROKE_BUFFER_MAX 5000
-
/* ************************************************ */
/* Datablock Operators */
@@ -882,9 +879,9 @@ static int gp_stroke_change_color_exec(bContext *C, wmOperator *UNUSED(op))
continue;
/* asign new color (only if different) */
- if (STREQ(gps->colorname, color->info) == false) {
+ if ((STREQ(gps->colorname, color->info) == false) || (gps->palcolor != color)) {
BLI_strncpy(gps->colorname, color->info, sizeof(gps->colorname));
- gps->flag |= GP_STROKE_RECALC_COLOR;
+ gps->palcolor = color;
}
}
}
@@ -965,431 +962,6 @@ void GPENCIL_OT_stroke_lock_color(wmOperatorType *ot)
ot->poll = gp_active_layer_poll;
}
-/* ******************* Apply layer thickness change to Strokes ************************** */
-
-static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
-
- /* sanity checks */
- if (ELEM(NULL, gpd, gpl, gpl->frames.first))
- return OPERATOR_CANCELLED;
-
- /* loop all strokes */
- for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- /* Apply thickness */
- gps->thickness = gps->thickness + gpl->thickness;
- }
- }
- /* clear value */
- gpl->thickness = 0.0f;
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Apply Stroke Thickness";
- ot->idname = "GPENCIL_OT_stroke_apply_thickness";
- ot->description = "Apply the thickness change of the layer to its strokes";
-
- /* api callbacks */
- ot->exec = gp_stroke_apply_thickness_exec;
- ot->poll = gp_active_layer_poll;
-}
-
-/* ******************* Close Strokes ************************** */
-
-enum {
- GP_STROKE_CYCLIC_CLOSE = 1,
- GP_STROKE_CYCLIC_OPEN = 2,
- GP_STROKE_CYCLIC_TOGGLE = 3
-};
-
-static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- const int type = RNA_enum_get(op->ptr, "type");
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* loop all selected strokes */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- bGPDpalettecolor *palcolor = gps->palcolor;
-
- /* skip strokes that are not selected or invalid for current view */
- if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false)
- continue;
- /* skip hidden or locked colors */
- if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED))
- continue;
-
- switch (type) {
- case GP_STROKE_CYCLIC_CLOSE:
- /* Close all (enable) */
- gps->flag |= GP_STROKE_CYCLIC;
- break;
- case GP_STROKE_CYCLIC_OPEN:
- /* Open all (disable) */
- gps->flag &= ~GP_STROKE_CYCLIC;
- break;
- case GP_STROKE_CYCLIC_TOGGLE:
- /* Just toggle flag... */
- gps->flag ^= GP_STROKE_CYCLIC;
- break;
- default:
- BLI_assert(0);
- break;
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-/**
- * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
- * option to force opened/closed strokes instead of just toggle behavior.
- */
-void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
-{
- static EnumPropertyItem cyclic_type[] = {
- {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""},
- {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""},
- {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Set Cyclical State";
- ot->idname = "GPENCIL_OT_stroke_cyclical_set";
- ot->description = "Close or open the selected stroke adding an edge from last to first point";
-
- /* api callbacks */
- ot->exec = gp_stroke_cyclical_set_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
-}
-
-/* ******************* Stroke join ************************** */
-
-/* Helper: flip stroke */
-static void gpencil_flip_stroke(bGPDstroke *gps)
-{
- bGPDspoint pt, *point, *point2;
- int end = gps->totpoints - 1;
-
- for (int i = 0; i < gps->totpoints / 2; i++) {
- /* save first point */
- point = &gps->points[i];
- pt.x = point->x;
- pt.y = point->y;
- pt.z = point->z;
- pt.flag = point->flag;
- pt.pressure = point->pressure;
- pt.strength = point->strength;
- pt.time = point->time;
-
- /* replace first point with last point */
- point2 = &gps->points[end];
- point->x = point2->x;
- point->y = point2->y;
- point->z = point2->z;
- point->flag = point2->flag;
- point->pressure = point2->pressure;
- point->strength = point2->strength;
- point->time = point2->time;
-
- /* replace last point with first saved before */
- point = &gps->points[end];
- point->x = pt.x;
- point->y = pt.y;
- point->z = pt.z;
- point->flag = pt.flag;
- point->pressure = pt.pressure;
- point->strength = pt.strength;
- point->time = pt.time;
-
- end--;
- }
-}
-
-/* Helper: copy point between strokes */
-static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3],
- float pressure, float strength, float deltatime)
-{
- bGPDspoint *newpoint;
-
- gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
- gps->totpoints++;
-
- newpoint = &gps->points[gps->totpoints - 1];
- newpoint->x = point->x * delta[0];
- newpoint->y = point->y * delta[1];
- newpoint->z = point->z * delta[2];
- newpoint->flag = point->flag;
- newpoint->pressure = pressure;
- newpoint->strength = strength;
- newpoint->time = point->time + deltatime;
-}
-
-/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
-static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, const bool leave_gaps)
-{
- bGPDspoint point, *pt;
- int i;
- float delta[3] = {1.0f, 1.0f, 1.0f};
- float deltatime = 0.0f;
-
- /* sanity checks */
- if (ELEM(NULL, gps_a, gps_b))
- return;
-
- if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0))
- return;
-
- /* define start and end points of each stroke */
- float sa[3], sb[3], ea[3], eb[3];
- pt = &gps_a->points[0];
- copy_v3_v3(sa, &pt->x);
-
- pt = &gps_a->points[gps_a->totpoints - 1];
- copy_v3_v3(ea, &pt->x);
-
- pt = &gps_b->points[0];
- copy_v3_v3(sb, &pt->x);
-
- pt = &gps_b->points[gps_b->totpoints - 1];
- copy_v3_v3(eb, &pt->x);
-
- /* review if need flip stroke B */
- float ea_sb = len_squared_v3v3(ea, sb);
- float ea_eb = len_squared_v3v3(ea, eb);
- /* flip if distance to end point is shorter */
- if (ea_eb < ea_sb) {
- gpencil_flip_stroke(gps_b);
- }
-
- /* don't visibly link the first and last points? */
- if (leave_gaps) {
- /* 1st: add one tail point to start invisible area */
- point = gps_a->points[gps_a->totpoints - 1];
- deltatime = point.time;
- gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f);
-
- /* 2nd: add one head point to finish invisible area */
- point = gps_b->points[0];
- gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime);
- }
-
- /* 3rd: add all points */
- for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
- /* check if still room in buffer */
- if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) {
- gpencil_stroke_copy_point(gps_a, pt, delta, pt->pressure, pt->strength, deltatime);
- }
- }
-}
-
-static int gp_stroke_join_exec(bContext *C, wmOperator *op)
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd);
- bGPDstroke *gps, *gpsn;
- bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
- bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
-
- bGPDframe *gpf_a = NULL;
- bGPDstroke *stroke_a = NULL;
- bGPDstroke *stroke_b = NULL;
- bGPDstroke *new_stroke = NULL;
-
- const int type = RNA_enum_get(op->ptr, "type");
- const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps");
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- if (activegpl->flag & GP_LAYER_LOCKED)
- return OPERATOR_CANCELLED;
-
- BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY));
-
-
- /* read all selected strokes */
- bool first = false;
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = gpl->actframe;
- for (gps = gpf->strokes.first; gps; gps = gpsn) {
- gpsn = gps->next;
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
- }
- /* to join strokes, cyclic must be disabled */
- gps->flag &= ~GP_STROKE_CYCLIC;
- /* saves first frame and stroke */
- if (!first) {
- first = true;
- gpf_a = gpf;
- stroke_a = gps;
- }
- else {
- stroke_b = gps;
- /* create a new stroke if was not created before (only created if something to join) */
- if (new_stroke == NULL) {
- new_stroke = MEM_dupallocN(stroke_a);
- new_stroke->points = MEM_dupallocN(stroke_a->points);
- new_stroke->triangles = NULL;
- new_stroke->tot_triangles = 0;
- new_stroke->flag |= GP_STROKE_RECALC_CACHES;
- /* if new, set current color */
- if (type == GP_STROKE_JOINCOPY) {
- new_stroke->palcolor = palcolor;
- BLI_strncpy(new_stroke->colorname, palcolor->info, sizeof(new_stroke->colorname));
- new_stroke->flag |= GP_STROKE_RECALC_COLOR;
- }
- }
- /* join new_stroke and stroke B. New stroke will contain all the previous data */
- gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps);
-
- /* if join only, delete old strokes */
- if (type == GP_STROKE_JOIN) {
- if (stroke_a) {
- BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke);
- BLI_remlink(&gpf->strokes, stroke_a);
- BKE_gpencil_free_stroke(stroke_a);
- stroke_a = NULL;
- }
- if (stroke_b) {
- BLI_remlink(&gpf->strokes, stroke_b);
- BKE_gpencil_free_stroke(stroke_b);
- stroke_b = NULL;
- }
- }
- }
- }
- }
- }
- CTX_DATA_END;
- /* add new stroke if was not added before */
- if (type == GP_STROKE_JOINCOPY) {
- if (new_stroke) {
- /* Add a new frame if needed */
- if (activegpl->actframe == NULL)
- activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum);
-
- BLI_addtail(&activegpl->actframe->strokes, new_stroke);
- }
- }
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_stroke_join(wmOperatorType *ot)
-{
- static EnumPropertyItem join_type[] = {
- {GP_STROKE_JOIN, "JOIN", 0, "Join", ""},
- {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
- /* identifiers */
- ot->name = "Join Strokes";
- ot->idname = "GPENCIL_OT_stroke_join";
- ot->description = "Join selected strokes (optionally as new stroke)";
-
- /* api callbacks */
- ot->exec = gp_stroke_join_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
- ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", "");
- RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them");
-}
-
-/* ******************* Stroke flip ************************** */
-
-static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
-{
- bGPdata *gpd = ED_gpencil_data_get_active(C);
-
- /* sanity checks */
- if (ELEM(NULL, gpd))
- return OPERATOR_CANCELLED;
-
- /* read all selected strokes */
- CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
- {
- bGPDframe *gpf = gpl->actframe;
- for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
- if (gps->flag & GP_STROKE_SELECT) {
- /* skip strokes that are invalid for current view */
- if (ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
- continue;
- }
- /* flip stroke */
- gpencil_flip_stroke(gps);
- }
- }
- }
- CTX_DATA_END;
-
- /* notifiers */
- WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
-
- return OPERATOR_FINISHED;
-}
-
-void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Flip Stroke";
- ot->idname = "GPENCIL_OT_stroke_flip";
- ot->description = "Change direction of the points of the selected strokes";
-
- /* api callbacks */
- ot->exec = gp_stroke_flip_exec;
- ot->poll = gp_active_layer_poll;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
/* ************************************************ */
/* Drawing Brushes Operators */
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index e58178bf2a7..9f700e8716c 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -72,6 +72,7 @@
#include "ED_gpencil.h"
#include "ED_object.h"
+#include "ED_screen.h"
#include "ED_view3d.h"
#include "gpencil_intern.h"
@@ -431,16 +432,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 +451,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 +510,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 +555,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 +567,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", "");
}
@@ -1188,40 +1190,35 @@ static int gp_snap_poll(bContext *C)
static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
RegionView3D *rv3d = CTX_wm_region_data(C);
const float gridf = rv3d->gridview;
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- float diff_mat[4][4];
-
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
-
+ bGPDframe *gpf = gpl->actframe;
+ float diff_mat[4][4];
+
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
}
-
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
continue;
- }
-
- bGPDspoint *pt;
- int i;
-
- // TOOD: if entire stroke is selected, offset entire stroke by same amount?
-
+
+ // TODO: if entire stroke is selected, offset entire stroke by same amount?
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
-
- /* only if point is selected.. */
+ /* only if point is selected */
if (pt->flag & GP_SPOINT_SELECT) {
if (gpl->parent == NULL) {
pt->x = gridf * floorf(0.5f + pt->x / gridf);
@@ -1232,19 +1229,17 @@ static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op))
/* apply parent transformations */
float fpt[3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
-
+
fpt[0] = gridf * floorf(0.5f + fpt[0] / gridf);
fpt[1] = gridf * floorf(0.5f + fpt[1] / gridf);
fpt[2] = gridf * floorf(0.5f + fpt[2] / gridf);
-
+
/* return data */
copy_v3_v3(&pt->x, fpt);
gp_apply_parent_point(gpl, pt);
}
-
}
}
-
}
}
}
@@ -1272,49 +1267,46 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot)
static int gp_snap_to_cursor(bContext *C, wmOperator *op)
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
-
+
const bool use_offset = RNA_boolean_get(op->ptr, "use_offset");
const float *cursor_global = ED_view3d_cursor3d_get(scene, v3d);
-
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- float diff_mat[4][4];
-
+
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
-
+ bGPDframe *gpf = gpl->actframe;
+ float diff_mat[4][4];
+
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
}
-
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
continue;
- }
-
- bGPDspoint *pt;
- int i;
-
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
-
+
if (use_offset) {
float offset[3];
-
+
/* compute offset from first point of stroke to cursor */
/* TODO: Allow using midpoint instead? */
sub_v3_v3v3(offset, cursor_global, &gps->points->x);
-
+
/* apply offset to all points in the stroke */
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
add_v3_v3(&pt->x, offset);
@@ -1331,9 +1323,8 @@ static int gp_snap_to_cursor(bContext *C, wmOperator *op)
}
}
}
-
-
}
+
}
}
@@ -1364,6 +1355,8 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot)
static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -1375,36 +1368,31 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
INIT_MINMAX(min, max);
/* calculate midpoints from selected points */
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- float diff_mat[4][4];
-
for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) {
/* only editable and visible layers are considered */
if (gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
-
+ bGPDframe *gpf = gpl->actframe;
+ float diff_mat[4][4];
+
/* calculate difference matrix if parent object */
if (gpl->parent != NULL) {
ED_gpencil_parent_location(gpl, diff_mat);
}
-
- bGPDframe *gpf = gpl->actframe;
- bGPDstroke *gps;
- for (gps = gpf->strokes.first; gps; gps = gps->next) {
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ bGPDspoint *pt;
+ int i;
+
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false)
continue;
/* check if the color is editable */
- if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false)
continue;
- }
-
- bGPDspoint *pt;
- int i;
-
/* only continue if this stroke is selected (editable doesn't guarantee this)... */
if ((gps->flag & GP_STROKE_SELECT) == 0)
continue;
-
+
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
if (gpl->parent == NULL) {
@@ -1415,14 +1403,14 @@ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op))
/* apply parent transformations */
float fpt[3];
mul_v3_m4v3(fpt, diff_mat, &pt->x);
-
+
add_v3_v3(centroid, fpt);
minmax_v3v3_v3(min, max, fpt);
}
count++;
}
}
-
+
}
}
}
@@ -1455,5 +1443,529 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ******************* Apply layer thickness change to strokes ************************** */
+
+static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd, gpl, gpl->frames.first))
+ return OPERATOR_CANCELLED;
+
+ /* loop all strokes */
+ for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) {
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* Apply thickness */
+ gps->thickness = gps->thickness + gpl->thickness;
+ }
+ }
+ /* clear value */
+ gpl->thickness = 0.0f;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Apply Stroke Thickness";
+ ot->idname = "GPENCIL_OT_stroke_apply_thickness";
+ ot->description = "Apply the thickness change of the layer to its strokes";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_apply_thickness_exec;
+ ot->poll = gp_active_layer_poll;
+}
+
+/* ******************* Close Strokes ************************** */
+
+enum {
+ GP_STROKE_CYCLIC_CLOSE = 1,
+ GP_STROKE_CYCLIC_OPEN = 2,
+ GP_STROKE_CYCLIC_TOGGLE = 3
+};
+
+static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* loop all selected strokes */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
+ bGPDpalettecolor *palcolor = gps->palcolor;
+
+ /* skip strokes that are not selected or invalid for current view */
+ if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+ /* skip hidden or locked colors */
+ if (!palcolor || (palcolor->flag & PC_COLOR_HIDE) || (palcolor->flag & PC_COLOR_LOCKED))
+ continue;
+
+ switch (type) {
+ case GP_STROKE_CYCLIC_CLOSE:
+ /* Close all (enable) */
+ gps->flag |= GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_OPEN:
+ /* Open all (disable) */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_TOGGLE:
+ /* Just toggle flag... */
+ gps->flag ^= GP_STROKE_CYCLIC;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+/**
+ * Similar to #CURVE_OT_cyclic_toggle or #MASK_OT_cyclic_toggle, but with
+ * option to force opened/closed strokes instead of just toggle behavior.
+ */
+void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
+{
+ static EnumPropertyItem cyclic_type[] = {
+ {GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""},
+ {GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""},
+ {GP_STROKE_CYCLIC_TOGGLE, "TOGGLE", 0, "Toggle", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Set Cyclical State";
+ ot->idname = "GPENCIL_OT_stroke_cyclical_set";
+ ot->description = "Close or open the selected stroke adding an edge from last to first point";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_cyclical_set_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
+}
+
+/* ******************* Stroke join ************************** */
+
+/* Helper: flip stroke */
+static void gpencil_flip_stroke(bGPDstroke *gps)
+{
+ int end = gps->totpoints - 1;
+
+ for (int i = 0; i < gps->totpoints / 2; i++) {
+ bGPDspoint *point, *point2;
+ bGPDspoint pt;
+
+ /* save first point */
+ point = &gps->points[i];
+ pt.x = point->x;
+ pt.y = point->y;
+ pt.z = point->z;
+ pt.flag = point->flag;
+ pt.pressure = point->pressure;
+ pt.strength = point->strength;
+ pt.time = point->time;
+
+ /* replace first point with last point */
+ point2 = &gps->points[end];
+ point->x = point2->x;
+ point->y = point2->y;
+ point->z = point2->z;
+ point->flag = point2->flag;
+ point->pressure = point2->pressure;
+ point->strength = point2->strength;
+ point->time = point2->time;
+
+ /* replace last point with first saved before */
+ point = &gps->points[end];
+ point->x = pt.x;
+ point->y = pt.y;
+ point->z = pt.z;
+ point->flag = pt.flag;
+ point->pressure = pt.pressure;
+ point->strength = pt.strength;
+ point->time = pt.time;
+
+ end--;
+ }
+}
+
+/* Helper: copy point between strokes */
+static void gpencil_stroke_copy_point(bGPDstroke *gps, bGPDspoint *point, float delta[3],
+ float pressure, float strength, float deltatime)
+{
+ bGPDspoint *newpoint;
+
+ gps->points = MEM_reallocN(gps->points, sizeof(bGPDspoint) * (gps->totpoints + 1));
+ gps->totpoints++;
+
+ newpoint = &gps->points[gps->totpoints - 1];
+ newpoint->x = point->x * delta[0];
+ newpoint->y = point->y * delta[1];
+ newpoint->z = point->z * delta[2];
+ newpoint->flag = point->flag;
+ newpoint->pressure = pressure;
+ newpoint->strength = strength;
+ newpoint->time = point->time + deltatime;
+}
+
+/* Helper: join two strokes using the shortest distance (reorder stroke if necessary ) */
+static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, bGPDstroke *gps_b, const bool leave_gaps)
+{
+ bGPDspoint point;
+ bGPDspoint *pt;
+ int i;
+ float delta[3] = {1.0f, 1.0f, 1.0f};
+ float deltatime = 0.0f;
+
+ /* sanity checks */
+ if (ELEM(NULL, gps_a, gps_b))
+ return;
+
+ if ((gps_a->totpoints == 0) || (gps_b->totpoints == 0))
+ return;
+
+ /* define start and end points of each stroke */
+ float sa[3], sb[3], ea[3], eb[3];
+ pt = &gps_a->points[0];
+ copy_v3_v3(sa, &pt->x);
+
+ pt = &gps_a->points[gps_a->totpoints - 1];
+ copy_v3_v3(ea, &pt->x);
+
+ pt = &gps_b->points[0];
+ copy_v3_v3(sb, &pt->x);
+
+ pt = &gps_b->points[gps_b->totpoints - 1];
+ copy_v3_v3(eb, &pt->x);
+
+ /* review if need flip stroke B */
+ float ea_sb = len_squared_v3v3(ea, sb);
+ float ea_eb = len_squared_v3v3(ea, eb);
+ /* flip if distance to end point is shorter */
+ if (ea_eb < ea_sb) {
+ gpencil_flip_stroke(gps_b);
+ }
+
+ /* don't visibly link the first and last points? */
+ if (leave_gaps) {
+ /* 1st: add one tail point to start invisible area */
+ point = gps_a->points[gps_a->totpoints - 1];
+ deltatime = point.time;
+ gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, 0.0f);
+
+ /* 2nd: add one head point to finish invisible area */
+ point = gps_b->points[0];
+ gpencil_stroke_copy_point(gps_a, &point, delta, 0.0f, 0.0f, deltatime);
+ }
+
+ /* 3rd: add all points */
+ for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) {
+ /* check if still room in buffer */
+ if (gps_a->totpoints <= GP_STROKE_BUFFER_MAX - 2) {
+ gpencil_stroke_copy_point(gps_a, pt, delta, pt->pressure, pt->strength, deltatime);
+ }
+ }
+}
+
+static int gp_stroke_join_exec(bContext *C, wmOperator *op)
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+ bGPDlayer *activegpl = BKE_gpencil_layer_getactive(gpd);
+ bGPDstroke *gps, *gpsn;
+ bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd);
+ bGPDpalettecolor *palcolor = BKE_gpencil_palettecolor_getactive(palette);
+
+ bGPDframe *gpf_a = NULL;
+ bGPDstroke *stroke_a = NULL;
+ bGPDstroke *stroke_b = NULL;
+ bGPDstroke *new_stroke = NULL;
+
+ const int type = RNA_enum_get(op->ptr, "type");
+ const bool leave_gaps = RNA_boolean_get(op->ptr, "leave_gaps");
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ if (activegpl->flag & GP_LAYER_LOCKED)
+ return OPERATOR_CANCELLED;
+
+ BLI_assert(ELEM(type, GP_STROKE_JOIN, GP_STROKE_JOINCOPY));
+
+
+ /* read all selected strokes */
+ bool first = false;
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ for (gps = gpf->strokes.first; gps; gps = gpsn) {
+ gpsn = gps->next;
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
+
+ /* to join strokes, cyclic must be disabled */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+
+ /* saves first frame and stroke */
+ if (!first) {
+ first = true;
+ gpf_a = gpf;
+ stroke_a = gps;
+ }
+ else {
+ stroke_b = gps;
+
+ /* create a new stroke if was not created before (only created if something to join) */
+ if (new_stroke == NULL) {
+ new_stroke = MEM_dupallocN(stroke_a);
+ new_stroke->points = MEM_dupallocN(stroke_a->points);
+ new_stroke->triangles = NULL;
+ new_stroke->tot_triangles = 0;
+ new_stroke->flag |= GP_STROKE_RECALC_CACHES;
+
+ /* if new, set current color */
+ if (type == GP_STROKE_JOINCOPY) {
+ new_stroke->palcolor = palcolor;
+ BLI_strncpy(new_stroke->colorname, palcolor->info, sizeof(new_stroke->colorname));
+ new_stroke->flag |= GP_STROKE_RECALC_COLOR;
+ }
+ }
+
+ /* join new_stroke and stroke B. New stroke will contain all the previous data */
+ gpencil_stroke_join_strokes(new_stroke, stroke_b, leave_gaps);
+
+ /* if join only, delete old strokes */
+ if (type == GP_STROKE_JOIN) {
+ if (stroke_a) {
+ BLI_insertlinkbefore(&gpf_a->strokes, stroke_a, new_stroke);
+ BLI_remlink(&gpf->strokes, stroke_a);
+ BKE_gpencil_free_stroke(stroke_a);
+ stroke_a = NULL;
+ }
+ if (stroke_b) {
+ BLI_remlink(&gpf->strokes, stroke_b);
+ BKE_gpencil_free_stroke(stroke_b);
+ stroke_b = NULL;
+ }
+ }
+ }
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* add new stroke if was not added before */
+ if (type == GP_STROKE_JOINCOPY) {
+ if (new_stroke) {
+ /* Add a new frame if needed */
+ if (activegpl->actframe == NULL)
+ activegpl->actframe = BKE_gpencil_frame_addnew(activegpl, gpf_a->framenum);
+
+ BLI_addtail(&activegpl->actframe->strokes, new_stroke);
+ }
+ }
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_join(wmOperatorType *ot)
+{
+ static EnumPropertyItem join_type[] = {
+ {GP_STROKE_JOIN, "JOIN", 0, "Join", ""},
+ {GP_STROKE_JOINCOPY, "JOINCOPY", 0, "Join and Copy", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Join Strokes";
+ ot->idname = "GPENCIL_OT_stroke_join";
+ ot->description = "Join selected strokes (optionally as new stroke)";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_join_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_enum(ot->srna, "type", join_type, GP_STROKE_JOIN, "Type", "");
+ RNA_def_boolean(ot->srna, "leave_gaps", false, "Leave Gaps", "Leave gaps between joined strokes instead of linking them");
+}
+
+/* ******************* Stroke flip ************************** */
+
+static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
+
+ /* sanity checks */
+ if (ELEM(NULL, gpd))
+ return OPERATOR_CANCELLED;
+
+ /* read all selected strokes */
+ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers)
+ {
+ bGPDframe *gpf = gpl->actframe;
+ if (gpf == NULL)
+ continue;
+
+ for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* check if the color is editable */
+ if (ED_gpencil_stroke_color_use(gpl, gps) == false) {
+ continue;
+ }
+
+ /* flip stroke */
+ gpencil_flip_stroke(gps);
+ }
+ }
+ }
+ CTX_DATA_END;
+
+ /* notifiers */
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void GPENCIL_OT_stroke_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Flip Stroke";
+ ot->idname = "GPENCIL_OT_stroke_flip";
+ ot->description = "Change direction of the points of the selected strokes";
+
+ /* api callbacks */
+ ot->exec = gp_stroke_flip_exec;
+ ot->poll = gp_active_layer_poll;
+
+ /* flags */
+ 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;
+}
/* ************************************************ */
diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h
index f37fba4212d..4178d49d652 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 */
@@ -214,6 +227,9 @@ typedef enum eGPencil_PaintModes {
GP_PAINTMODE_DRAW_POLY
} eGPencil_PaintModes;
+/* maximum sizes of gp-session buffer */
+#define GP_STROKE_BUFFER_MAX 5000
+
/* stroke editing ----- */
void GPENCIL_OT_editmode_toggle(struct wmOperatorType *ot);
@@ -246,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 -- */
@@ -300,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);
@@ -318,7 +335,7 @@ void gpencil_undo_init(struct bGPdata *gpd);
void gpencil_undo_push(struct bGPdata *gpd);
void gpencil_undo_finish(void);
-/******************************************************* */
+/* ****************************************************** */
/* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */
/* XXX - TODO: replace this with the modern bAnimListElem... */
@@ -340,7 +357,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 */
@@ -363,6 +380,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)
@@ -398,4 +418,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..ae1c5554521 100644
--- a/source/blender/editors/gpencil/gpencil_ops.c
+++ b/source/blender/editors/gpencil/gpencil_ops.c
@@ -375,6 +375,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) ------------ */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index dacdc0cf777..cc45cbd82af 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -164,9 +164,6 @@ typedef struct tGPsdata {
/* ------ */
-/* maximum sizes of gp-session buffer */
-#define GP_STROKE_BUFFER_MAX 5000
-
/* Macros for accessing sensitivity thresholds... */
/* minimum number of pixels mouse should move before new point created */
#define MIN_MANHATTEN_PX (U.gp_manhattendist)
@@ -2313,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)
@@ -2366,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;
@@ -2428,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;
@@ -2514,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_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 4cb966c6378..45dbde80284 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -36,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
#include "BLI_lasso.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
@@ -253,6 +254,9 @@ typedef enum eGP_SelectGrouped {
/* Select strokes in the same layer */
GP_SEL_SAME_LAYER = 0,
+ /* Select strokes with the same color */
+ GP_SEL_SAME_COLOR = 1,
+
/* TODO: All with same prefix - Useful for isolating all layers for a particular character for instance */
/* TODO: All with same appearance - colour/opacity/volumetric/fills ? */
} eGP_SelectGrouped;
@@ -302,6 +306,43 @@ static void gp_select_same_layer(bContext *C)
CTX_DATA_END;
}
+/* Select all strokes with same colors as selected ones */
+static void gp_select_same_color(bContext *C)
+{
+ /* First, build set containing all the colors of selected strokes
+ * - We use the palette names, so that we can select all strokes with one
+ * (potentially missing) color, and remap them to something else
+ */
+ GSet *selected_colors = BLI_gset_str_new("GP Selected Colors");
+
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if (gps->flag & GP_STROKE_SELECT) {
+ /* add instead of insert here, otherwise the uniqueness check gets skipped,
+ * and we get many duplicate entries...
+ */
+ BLI_gset_add(selected_colors, gps->colorname);
+ }
+ }
+ CTX_DATA_END;
+
+ /* Second, select any visible stroke that uses these colors */
+ CTX_DATA_BEGIN(C, bGPDstroke *, gps, editable_gpencil_strokes)
+ {
+ if (BLI_gset_haskey(selected_colors, gps->colorname)) {
+ /* select this stroke */
+ bGPDspoint *pt;
+ int i;
+
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag |= GP_SPOINT_SELECT;
+ }
+
+ gps->flag |= GP_STROKE_SELECT;
+ }
+ }
+ CTX_DATA_END;
+}
/* ----------------------------------- */
@@ -314,6 +355,9 @@ static int gpencil_select_grouped_exec(bContext *C, wmOperator *op)
case GP_SEL_SAME_LAYER:
gp_select_same_layer(C);
break;
+ case GP_SEL_SAME_COLOR:
+ gp_select_same_color(C);
+ break;
default:
BLI_assert(!"unhandled select grouped gpencil mode");
@@ -329,6 +373,7 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
{
static EnumPropertyItem prop_select_grouped_types[] = {
{GP_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
+ {GP_SEL_SAME_COLOR, "COLOR", 0, "Color", "Shared colors"},
{0, NULL, 0, NULL, NULL}
};
@@ -338,7 +383,7 @@ void GPENCIL_OT_select_grouped(wmOperatorType *ot)
ot->description = "Select all strokes with similar characteristics";
/* callbacks */
- //ot->invoke = WM_menu_invoke;
+ ot->invoke = WM_menu_invoke;
ot->exec = gpencil_select_grouped_exec;
ot->poll = gpencil_select_poll;
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/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 1f053c806b0..49e5845e3ca 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;
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_regions.c b/source/blender/editors/interface/interface_regions.c
index c621fcf493d..c507401b9a0 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -1380,6 +1380,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
rect_pre.xmax = rect_post.xmin = rect.xmin + ((rect.xmax - rect.xmin) / 4);
/* widget itself */
+ /* NOTE: i18n messages extracting tool does the same, please keep it in sync. */
{
wmOperatorType *ot = data->items.pointers[a];
@@ -1400,7 +1401,8 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe
}
rect_pre.xmax += 4; /* sneaky, avoid showing ugly margin */
- ui_draw_menu_item(&data->fstyle, &rect_pre, text_pre, data->items.icons[a], state, false);
+ ui_draw_menu_item(&data->fstyle, &rect_pre, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre),
+ data->items.icons[a], state, false);
ui_draw_menu_item(&data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep);
}
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 313181abc97..4482a071c91 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -997,7 +997,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 e467dbd05eb..6b3284fe8b1 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -896,7 +896,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 1520b7c1aea..bc6a4dc3de2 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -1608,7 +1608,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/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index d53d87db228..05270dbfa09 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -88,7 +88,6 @@ typedef struct PaintStroke {
/* Cached values */
ViewContext vc;
- bglMats mats;
Brush *brush;
UnifiedPaintSettings *ups;
@@ -675,8 +674,6 @@ PaintStroke *paint_stroke_new(bContext *C,
float zoomx, zoomy;
view3d_set_viewcontext(C, &stroke->vc);
- if (stroke->vc.v3d)
- view3d_get_transformation(stroke->vc.ar, stroke->vc.rv3d, stroke->vc.obact, &stroke->mats);
stroke->get_location = get_location;
stroke->test_start = test_start;
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 03f2e146b7d..ac3fc769ea1 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -348,10 +348,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 d9293aa126a..5eb261890b2 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..1f591b5fb35 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -1613,13 +1613,16 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
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 +1663,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/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 74a50497164..ecbfd5c7c85 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -1015,12 +1015,18 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
else {
userData.me = NULL;
- if ((ob->mode & OB_MODE_ALL_PAINT) == 0) {
+ /* if ((ob->mode & OB_MODE_ALL_PAINT) == 0) */ {
/* Note: this isn't efficient and runs on every redraw,
* its needed so material colors are used for vertex colors.
* In the future we will likely remove 'texface' so, just avoid running this where possible,
- * (when vertex paint or weight paint are used). */
+ * (when vertex paint or weight paint are used).
+ *
+ * Note 2: We disable optimization for now since it causes T48788
+ * and it is now too close to release to do something smarter.
+ *
+ * TODO(sergey): Find some real solution here.
+ */
update_tface_color_layer(dm, !(ob->mode & OB_MODE_TEXTURE_PAINT));
}
diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c
index 29c06388cf6..75ba8bc15d9 100644
--- a/source/blender/editors/space_view3d/drawvolume.c
+++ b/source/blender/editors/space_view3d/drawvolume.c
@@ -287,6 +287,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])
@@ -298,14 +400,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]),
@@ -319,50 +430,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;
@@ -386,43 +453,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_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 2cf32ff3128..e3b32ebdbb2 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -1131,9 +1131,11 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
UI_ThemeColor(TH_TEXT_HI);
}
else {
- /* no object */
- /* color is always white */
- UI_ThemeColor(TH_TEXT_HI);
+ /* no object */
+ if (ED_gpencil_has_keyframe_v3d(scene, NULL, cfra))
+ UI_ThemeColor(TH_TIME_GP_KEYFRAME);
+ else
+ UI_ThemeColor(TH_TEXT_HI);
}
if (markern) {
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/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 148db20b41d..f77e836461c 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1951,6 +1951,9 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
int index = buffer[(4 * a) + 3];
if (index != -1) {
ebone = BLI_findlink(arm->edbo, index & ~(BONESEL_ANY));
+ if ((index & 0xFFFF0000) == 0) {
+ continue;
+ }
if ((select == false) || ((ebone->flag & BONE_UNSELECTABLE) == 0)) {
if (index & BONESEL_TIP) {
ebone->flag |= BONE_DONE;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 27643ff7c4c..40710046cc2 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -79,6 +79,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
@@ -112,6 +113,7 @@ data_to_c_simple(shaders/gpu_shader_3D_smooth_color_vert.glsl SRC)
data_to_c_simple(shaders/gpu_shader_3D_smooth_color_frag.glsl 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 14d4e8cbe68..f33f5157f56 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -869,7 +869,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 e05ac3a5607..c95c427d32a 100644
--- a/source/blender/gpu/intern/gpu_shader.c
+++ b/source/blender/gpu/intern/gpu_shader.c
@@ -57,6 +57,7 @@ extern char datatoc_gpu_shader_3D_flat_color_vert_glsl[];
extern char datatoc_gpu_shader_3D_smooth_color_vert_glsl[];
extern char datatoc_gpu_shader_3D_smooth_color_frag_glsl[];
+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,7 +619,7 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader)
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);
+ NULL, NULL, NULL, 0, 0, 0);
retval = GG.shaders.smoke_fire;
break;
case GPU_SHADER_2D_UNIFORM_COLOR:
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_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h
index 1cda0233aa8..dd47d63fc19 100644
--- a/source/blender/makesdna/DNA_cachefile_types.h
+++ b/source/blender/makesdna/DNA_cachefile_types.h
@@ -58,6 +58,7 @@ typedef struct CacheFile {
struct AnimData *adt;
struct AbcArchiveHandle *handle;
+ void *handle_mutex;
/* Paths of the objects inside of the Alembic archive referenced by this
* CacheFile. */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index d4edc8a1c20..d59dad5762b 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1702,9 +1702,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/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index fb4ff6f4856..f4fb30e0793 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -1273,7 +1273,7 @@ static void rna_def_curve_spline_bezpoints(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_srna(cprop, "SplineBezierPoints");
srna = RNA_def_struct(brna, "SplineBezierPoints", NULL);
RNA_def_struct_sdna(srna, "Nurb");
- RNA_def_struct_ui_text(srna, "Spline Bezier Points", "Collection of spline bezirt points");
+ RNA_def_struct_ui_text(srna, "Spline Bezier Points", "Collection of spline Bezier points");
func = RNA_def_function(srna, "add", "rna_Curve_spline_bezpoints_add");
RNA_def_function_ui_description(func, "Add a number of points to this spline");
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index 3ecaec75c77..7eaf8b65902 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -439,12 +439,23 @@ static void rna_GPencil_stroke_point_select_set(PointerRNA *ptr, const int value
}
}
-static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count)
+static void rna_GPencil_stroke_point_add(bGPDstroke *stroke, int count, float pressure, float strength)
{
if (count > 0) {
+ /* create space at the end of the array for extra points */
stroke->points = MEM_recallocN_id(stroke->points,
sizeof(bGPDspoint) * (stroke->totpoints + count),
"gp_stroke_points");
+
+ /* init the pressure and strength values so that old scripts won't need to
+ * be modified to give these initial values...
+ */
+ for (int i = 0; i < count; i++) {
+ bGPDspoint *pt = stroke->points + (stroke->totpoints + i);
+ pt->pressure = pressure;
+ pt->strength = strength;
+ }
+
stroke->totpoints += count;
}
}
@@ -888,9 +899,7 @@ static void rna_def_gpencil_stroke_point(BlenderRNA *brna)
static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
-
FunctionRNA *func;
- /* PropertyRNA *parm; */
RNA_def_property_srna(cprop, "GPencilStrokePoints");
srna = RNA_def_struct(brna, "GPencilStrokePoints", NULL);
@@ -900,6 +909,8 @@ static void rna_def_gpencil_stroke_points_api(BlenderRNA *brna, PropertyRNA *cpr
func = RNA_def_function(srna, "add", "rna_GPencil_stroke_point_add");
RNA_def_function_ui_description(func, "Add a new grease pencil stroke point");
RNA_def_int(func, "count", 1, 0, INT_MAX, "Number", "Number of points to add to the stroke", 0, INT_MAX);
+ RNA_def_float(func, "pressure", 1.0f, 0.0f, 1.0f, "Pressure", "Pressure for newly created points", 0.0f, 1.0f);
+ RNA_def_float(func, "strength", 1.0f, 0.0f, 1.0f, "Strength", "Color intensity (alpha factor) for newly created points", 0.0f, 1.0f);
func = RNA_def_function(srna, "pop", "rna_GPencil_stroke_point_pop");
RNA_def_function_ui_description(func, "Remove a grease pencil stroke point");
diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c
index e4e3699f301..51709d3137c 100644
--- a/source/blender/makesrna/intern/rna_lamp.c
+++ b/source/blender/makesrna/intern/rna_lamp.c
@@ -546,7 +546,7 @@ static void rna_def_lamp_shadow(StructRNA *srna, int spot, int area)
prop = RNA_def_property(srna, "shadow_method", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, (spot) ? prop_spot_shadow_items : prop_shadow_items);
- RNA_def_property_update(prop, 0, "rna_Lamp_update");
+ RNA_def_property_update(prop, 0, "rna_Lamp_draw_update");
prop = RNA_def_property(srna, "shadow_buffer_size", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "bufsize");
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index d8cc61bf906..9b28009d161 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -1499,14 +1499,15 @@ static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA
RNA_def_property_srna(cprop, "LineStyleThicknessModifiers");
srna = RNA_def_struct(brna, "LineStyleThicknessModifiers", NULL);
RNA_def_struct_sdna(srna, "FreestyleLineStyle");
- RNA_def_struct_ui_text(srna, "Thickness Modifiers", "Thickness modifiers for changing line thicknesss");
+ RNA_def_struct_ui_text(srna, "Thickness Modifiers", "Thickness modifiers for changing line thickness");
func = RNA_def_function(srna, "new", "rna_LineStyle_thickness_modifier_add");
RNA_def_function_ui_description(func, "Add a thickness modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "ThicknessModifier", 0, "", "New name for the thickness modifier (not unique)");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", rna_enum_linestyle_thickness_modifier_type_items, 0, "", "Thickness modifier type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_linestyle_thickness_modifier_type_items, 0,
+ "", "Thickness modifier type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Newly added thickness modifier");
RNA_def_function_return(func, parm);
@@ -1528,14 +1529,15 @@ static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *
RNA_def_property_srna(cprop, "LineStyleGeometryModifiers");
srna = RNA_def_struct(brna, "LineStyleGeometryModifiers", NULL);
RNA_def_struct_sdna(srna, "FreestyleLineStyle");
- RNA_def_struct_ui_text(srna, "Geometry Modifiers", "Geometry modifiers for changing line geometrys");
+ RNA_def_struct_ui_text(srna, "Geometry Modifiers", "Geometry modifiers for changing line geometries");
func = RNA_def_function(srna, "new", "rna_LineStyle_geometry_modifier_add");
RNA_def_function_ui_description(func, "Add a geometry modifier to line style");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "name", "GeometryModifier", 0, "", "New name for the geometry modifier (not unique)");
RNA_def_property_flag(parm, PROP_REQUIRED);
- parm = RNA_def_enum(func, "type", rna_enum_linestyle_geometry_modifier_type_items, 0, "", "Geometry modifier type to add");
+ parm = RNA_def_enum(func, "type", rna_enum_linestyle_geometry_modifier_type_items, 0,
+ "", "Geometry modifier type to add");
RNA_def_property_flag(parm, PROP_REQUIRED);
parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Newly added geometry modifier");
RNA_def_function_return(func, parm);
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_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 72ecebdb7df..1e58b6421f2 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -5352,13 +5352,13 @@ static void def_cmp_double_edge_mask(StructRNA *srna)
};
prop = RNA_def_property(srna, "inner_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom2");
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
RNA_def_property_enum_items(prop, InnerEdgeMode_items);
RNA_def_property_ui_text(prop, "Inner Edge Mode", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
prop = RNA_def_property(srna, "edge_mode", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_sdna(prop, NULL, "custom2");
RNA_def_property_enum_items(prop, BufEdgeMode_items);
RNA_def_property_ui_text(prop, "Buffer Edge Mode", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 127c6d4d95e..74e9df1889a 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -2490,7 +2490,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 be42f3c538f..dfe319dd87d 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -2276,7 +2276,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)
@@ -6270,6 +6270,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_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index cbfebe5efc4..2340345c1c6 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -1768,17 +1768,17 @@ static void rna_def_trackingStabilization(BlenderRNA *brna)
prop = RNA_def_property(srna, "target_rotation", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "target_rot");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
- RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 3);
+ RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10.0f, 3);
RNA_def_property_ui_text(prop, "Expected Rotation",
"Rotation present on original shot, will be compensated (e.g. for deliberate tilting)");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, NULL);
/* target scale */
- prop = RNA_def_property(srna, "target_zoom", PROP_FLOAT, PROP_FACTOR);
+ prop = RNA_def_property(srna, "target_scale", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "scale");
- RNA_def_property_range(prop, FLT_EPSILON, 100.0f);
- RNA_def_property_ui_range(prop, 0.1f, 10.0f, 1, 3); /* increment in steps of 0.01. Show 3 digit after point */
- RNA_def_property_ui_text(prop, "Expected Zoom",
+ RNA_def_property_range(prop, FLT_EPSILON, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.01f, 10.0f, 0.001f, 3); /* increment in steps of 0.001. Show 3 digit after point */
+ RNA_def_property_ui_text(prop, "Expected Scale",
"Explicitly scale resulting frame to compensate zoom of original shot");
RNA_def_property_update(prop, NC_MOVIECLIP | ND_DISPLAY, "rna_tracking_flushUpdate");
@@ -2094,7 +2094,7 @@ static void rna_def_trackingObjects(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_srna(cprop, "MovieTrackingObjects");
srna = RNA_def_struct(brna, "MovieTrackingObjects", NULL);
RNA_def_struct_sdna(srna, "MovieTracking");
- RNA_def_struct_ui_text(srna, "Movie Objects", "Collection of movie trackingobjects");
+ RNA_def_struct_ui_text(srna, "Movie Objects", "Collection of movie tracking objects");
func = RNA_def_function(srna, "new", "rna_trackingObject_new");
RNA_def_function_ui_description(func, "Add tracking object to this movie clip");
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index f97f194033c..90081a93188 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -1935,15 +1935,15 @@ static void rna_def_wm_keyconfigs(BlenderRNA *brna, PropertyRNA *cprop)
prop = RNA_def_property(srna, "addon", PROP_POINTER, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "addonconf");
RNA_def_property_struct_type(prop, "KeyConfig");
- RNA_def_property_ui_text(prop, "Addon Key Configuration",
- "Key configuration that can be extended by addons, and is added to the active "
+ RNA_def_property_ui_text(prop, "Add-on Key Configuration",
+ "Key configuration that can be extended by add-ons, and is added to the active "
"configuration when handling events");
prop = RNA_def_property(srna, "user", PROP_POINTER, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "userconf");
RNA_def_property_struct_type(prop, "KeyConfig");
RNA_def_property_ui_text(prop, "User Key Configuration",
- "Final key configuration that combines keymaps from the active and addon configurations, "
+ "Final key configuration that combines keymaps from the active and add-on configurations, "
"and can be edited by the user");
RNA_api_keyconfigs(srna);
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/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
index 2104315dc00..c16ef5500df 100644
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ b/source/blender/render/intern/raytrace/rayobject.cpp
@@ -138,16 +138,81 @@ MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UN
/* Ray Triangle/Quad Intersection */
-MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *isect_precalc, RayFace *face, float r_uv[2], float *lambda)
+static bool isect_ray_tri_watertight_no_sign_check_v3(
+ const float ray_origin[3], const struct IsectRayPrecalc *isect_precalc,
+ const float v0[3], const float v1[3], const float v2[3],
+ float *r_lambda, float r_uv[2])
+{
+ const int kx = isect_precalc->kx;
+ const int ky = isect_precalc->ky;
+ const int kz = isect_precalc->kz;
+ const float sx = isect_precalc->sx;
+ const float sy = isect_precalc->sy;
+ const float sz = isect_precalc->sz;
+
+ /* Calculate vertices relative to ray origin. */
+ const float a[3] = {v0[0] - ray_origin[0], v0[1] - ray_origin[1], v0[2] - ray_origin[2]};
+ const float b[3] = {v1[0] - ray_origin[0], v1[1] - ray_origin[1], v1[2] - ray_origin[2]};
+ const float c[3] = {v2[0] - ray_origin[0], v2[1] - ray_origin[1], v2[2] - ray_origin[2]};
+
+ const float a_kx = a[kx], a_ky = a[ky], a_kz = a[kz];
+ const float b_kx = b[kx], b_ky = b[ky], b_kz = b[kz];
+ const float c_kx = c[kx], c_ky = c[ky], c_kz = c[kz];
+
+ /* Perform shear and scale of vertices. */
+ const float ax = a_kx - sx * a_kz;
+ const float ay = a_ky - sy * a_kz;
+ const float bx = b_kx - sx * b_kz;
+ const float by = b_ky - sy * b_kz;
+ const float cx = c_kx - sx * c_kz;
+ const float cy = c_ky - sy * c_kz;
+
+ /* Calculate scaled barycentric coordinates. */
+ const float u = cx * by - cy * bx;
+ const float v = ax * cy - ay * cx;
+ const float w = bx * ay - by * ax;
+ float det;
+
+ if ((u < 0.0f || v < 0.0f || w < 0.0f) &&
+ (u > 0.0f || v > 0.0f || w > 0.0f))
+ {
+ return false;
+ }
+
+ /* Calculate determinant. */
+ det = u + v + w;
+ if (UNLIKELY(det == 0.0f)) {
+ return false;
+ }
+ else {
+ /* Calculate scaled z-coordinates of vertices and use them to calculate
+ * the hit distance.
+ */
+ const float t = (u * a_kz + v * b_kz + w * c_kz) * sz;
+ /* Normalize u, v and t. */
+ const float inv_det = 1.0f / det;
+ if (r_uv) {
+ r_uv[0] = u * inv_det;
+ r_uv[1] = v * inv_det;
+ }
+ *r_lambda = t * inv_det;
+ return true;
+ }
+}
+
+MALWAYS_INLINE int isec_tri_quad(const float start[3],
+ const struct IsectRayPrecalc *isect_precalc,
+ const RayFace *face,
+ float r_uv[2], float *r_lambda)
{
float uv[2], l;
if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
/* check if intersection is within ray length */
- if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+ if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
r_uv[0] = -uv[0];
r_uv[1] = -uv[1];
- *lambda = l;
+ *r_lambda = l;
return 1;
}
}
@@ -156,10 +221,10 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i
if (RE_rayface_isQuad(face)) {
if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
/* check if intersection is within ray length */
- if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+ if (l > -RE_RAYTRACE_EPSILON && l < *r_lambda) {
r_uv[0] = -uv[0];
r_uv[1] = -uv[1];
- *lambda = l;
+ *r_lambda = l;
return 2;
}
}
@@ -170,24 +235,25 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i
/* Simpler yes/no Ray Triangle/Quad Intersection */
-MALWAYS_INLINE int isec_tri_quad_neighbour(float start[3], float dir[3], RayFace *face)
+MALWAYS_INLINE int isec_tri_quad_neighbour(const float start[3],
+ const float dir[3],
+ const RayFace *face)
{
float r[3];
struct IsectRayPrecalc isect_precalc;
float uv[2], l;
-
negate_v3_v3(r, dir); /* note, different than above function */
isect_ray_tri_watertight_v3_precalc(&isect_precalc, r);
- if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+ if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
return 1;
}
/* intersect second triangle in quad */
if (RE_rayface_isQuad(face)) {
- if (isect_ray_tri_watertight_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+ if (isect_ray_tri_watertight_no_sign_check_v3(start, &isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
return 2;
}
}
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 363267bb363..badc438b826 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -3058,6 +3058,13 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
}
#endif
+ if (RE_seq_render_active(scene, &scene->r)) {
+ if (scene->r.mode & R_BORDER) {
+ BKE_report(reports, RPT_ERROR, "Border rendering is not supported by sequencer");
+ return false;
+ }
+ }
+
/* layer flag tests */
if (!render_scene_has_layers_to_render(scene)) {
BKE_report(reports, RPT_ERROR, "All render layers are disabled");
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);
}