Merge remote-tracking branch 'origin/master' into blender2.8
Conflicts: source/blender/blenloader/intern/versioning_defaults.c
This commit is contained in:
@@ -986,7 +986,7 @@ if(SUPPORT_SSE_BUILD)
|
||||
add_definitions(-D__SSE__ -D__MMX__)
|
||||
endif()
|
||||
if(SUPPORT_SSE2_BUILD)
|
||||
set(PLATFORM_CFLAGS " ${COMPILER_SSE2_FLAG} ${PLATFORM_CFLAGS}")
|
||||
set(PLATFORM_CFLAGS " ${PLATFORM_CFLAGS} ${COMPILER_SSE2_FLAG}")
|
||||
add_definitions(-D__SSE2__)
|
||||
if(NOT SUPPORT_SSE_BUILD) # dont double up
|
||||
add_definitions(-D__MMX__)
|
||||
|
||||
@@ -97,6 +97,8 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES "blender" "blender")
|
||||
set(CPACK_CREATE_DESKTOP_LINKS "blender" "blender")
|
||||
|
||||
include(CPack)
|
||||
|
||||
# Target for build_archive.py script, to automatically pass along
|
||||
|
||||
@@ -191,7 +191,8 @@ public:
|
||||
OpenCLProgram(OpenCLDeviceBase *device,
|
||||
string program_name,
|
||||
string kernel_name,
|
||||
string kernel_build_options);
|
||||
string kernel_build_options,
|
||||
bool use_stdout = true);
|
||||
~OpenCLProgram();
|
||||
|
||||
void add_kernel(ustring name);
|
||||
@@ -212,6 +213,9 @@ public:
|
||||
bool load_binary(const string& clbin, const string *debug_src = NULL);
|
||||
bool save_binary(const string& clbin);
|
||||
|
||||
void add_log(string msg, bool is_debug);
|
||||
void add_error(string msg);
|
||||
|
||||
bool loaded;
|
||||
cl_program program;
|
||||
OpenCLDeviceBase *device;
|
||||
@@ -220,8 +224,10 @@ public:
|
||||
string program_name;
|
||||
|
||||
string kernel_file, kernel_build_options, device_md5;
|
||||
string error_msg, output_msg;
|
||||
string log;
|
||||
|
||||
bool use_stdout;
|
||||
string log, error_msg;
|
||||
string compile_output;
|
||||
|
||||
map<ustring, cl_kernel> kernels;
|
||||
};
|
||||
|
||||
@@ -212,6 +212,11 @@ bool OpenCLDeviceBase::load_kernels(const DeviceRequestedFeatures& requested_fea
|
||||
/* Call actual class to fill the vector with its programs. */
|
||||
load_kernels(requested_features, programs);
|
||||
|
||||
/* Parallel compilation is supported by Cycles, but currently all OpenCL frameworks
|
||||
* serialize the calls internally, so it's not much use right now.
|
||||
* Note: When enabling parallel compilation, use_stdout in the OpenCLProgram constructor
|
||||
* should be set to false as well. */
|
||||
#if 0
|
||||
TaskPool task_pool;
|
||||
foreach(OpenCLProgram *program, programs) {
|
||||
task_pool.push(function_bind(&OpenCLProgram::load, program));
|
||||
@@ -225,6 +230,14 @@ bool OpenCLDeviceBase::load_kernels(const DeviceRequestedFeatures& requested_fea
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
foreach(OpenCLProgram *program, programs) {
|
||||
program->load();
|
||||
if(!program->is_loaded()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -479,9 +492,9 @@ void OpenCLDeviceBase::shader(DeviceTask& task)
|
||||
cl_kernel kernel;
|
||||
|
||||
if(task.shader_eval_type >= SHADER_EVAL_BAKE)
|
||||
kernel = base_program(ustring("shader"));
|
||||
else
|
||||
kernel = base_program(ustring("bake"));
|
||||
else
|
||||
kernel = base_program(ustring("shader"));
|
||||
|
||||
cl_uint start_arg_index =
|
||||
kernel_set_args(kernel,
|
||||
|
||||
@@ -239,11 +239,16 @@ string OpenCLCache::get_kernel_md5()
|
||||
return self.kernel_md5;
|
||||
}
|
||||
|
||||
OpenCLDeviceBase::OpenCLProgram::OpenCLProgram(OpenCLDeviceBase *device, string program_name, string kernel_file, string kernel_build_options)
|
||||
OpenCLDeviceBase::OpenCLProgram::OpenCLProgram(OpenCLDeviceBase *device,
|
||||
string program_name,
|
||||
string kernel_file,
|
||||
string kernel_build_options,
|
||||
bool use_stdout)
|
||||
: device(device),
|
||||
program_name(program_name),
|
||||
kernel_file(kernel_file),
|
||||
kernel_build_options(kernel_build_options)
|
||||
kernel_build_options(kernel_build_options),
|
||||
use_stdout(use_stdout)
|
||||
{
|
||||
loaded = false;
|
||||
program = NULL;
|
||||
@@ -268,6 +273,30 @@ void OpenCLDeviceBase::OpenCLProgram::release()
|
||||
}
|
||||
}
|
||||
|
||||
void OpenCLDeviceBase::OpenCLProgram::add_log(string msg, bool debug)
|
||||
{
|
||||
if(!use_stdout) {
|
||||
log += msg + "\n";
|
||||
}
|
||||
else if(!debug) {
|
||||
printf("%s\n", msg.c_str());
|
||||
}
|
||||
else {
|
||||
VLOG(2) << msg;
|
||||
}
|
||||
}
|
||||
|
||||
void OpenCLDeviceBase::OpenCLProgram::add_error(string msg)
|
||||
{
|
||||
if(use_stdout) {
|
||||
fprintf(stderr, "%s\n", msg.c_str());
|
||||
}
|
||||
if(error_msg == "") {
|
||||
error_msg += "\n";
|
||||
}
|
||||
error_msg += msg;
|
||||
}
|
||||
|
||||
void OpenCLDeviceBase::OpenCLProgram::add_kernel(ustring name)
|
||||
{
|
||||
if(!kernels.count(name)) {
|
||||
@@ -287,6 +316,10 @@ bool OpenCLDeviceBase::OpenCLProgram::build_kernel(const string *debug_src)
|
||||
|
||||
clGetProgramBuildInfo(program, device->cdDevice, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
|
||||
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
add_error(string("OpenCL build failed with error ") + clewErrorString(ciErr) + ", errors in console.");
|
||||
}
|
||||
|
||||
if(ret_val_size > 1) {
|
||||
vector<char> build_log(ret_val_size + 1);
|
||||
clGetProgramBuildInfo(program, device->cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL);
|
||||
@@ -294,16 +327,11 @@ bool OpenCLDeviceBase::OpenCLProgram::build_kernel(const string *debug_src)
|
||||
build_log[ret_val_size] = '\0';
|
||||
/* Skip meaningless empty output from the NVidia compiler. */
|
||||
if(!(ret_val_size == 2 && build_log[0] == '\n')) {
|
||||
output_msg = string(&build_log[0]);
|
||||
add_log(string("OpenCL program ") + program_name + " build output: " + string(&build_log[0]), ciErr == CL_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
error_msg = string("OpenCL build failed: ") + clewErrorString(ciErr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return (ciErr == CL_SUCCESS);
|
||||
}
|
||||
|
||||
bool OpenCLDeviceBase::OpenCLProgram::compile_kernel(const string *debug_src)
|
||||
@@ -330,18 +358,18 @@ bool OpenCLDeviceBase::OpenCLProgram::compile_kernel(const string *debug_src)
|
||||
&ciErr);
|
||||
|
||||
if(ciErr != CL_SUCCESS) {
|
||||
error_msg = string("OpenCL program creation failed: ") + clewErrorString(ciErr);
|
||||
add_error(string("OpenCL program creation failed: ") + clewErrorString(ciErr));
|
||||
return false;
|
||||
}
|
||||
|
||||
double starttime = time_dt();
|
||||
|
||||
log += "Build flags: " + kernel_build_options + "\n";
|
||||
add_log(string("Compiling OpenCL program ") + program_name.c_str(), false);
|
||||
add_log(string("Build flags: ") + kernel_build_options, true);
|
||||
|
||||
if(!build_kernel(debug_src))
|
||||
return false;
|
||||
|
||||
log += "Kernel compilation of " + program_name + " finished in " + string_printf("%.2lfs.\n", time_dt() - starttime);
|
||||
add_log(string("Kernel compilation of ") + program_name + " finished in " + string_printf("%.2lfs.\n", time_dt() - starttime), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -353,7 +381,7 @@ bool OpenCLDeviceBase::OpenCLProgram::load_binary(const string& clbin,
|
||||
vector<uint8_t> binary;
|
||||
|
||||
if(!path_read_binary(clbin, binary)) {
|
||||
error_msg = "OpenCL failed to read cached binary " + clbin + ".";
|
||||
add_error(string_printf("OpenCL failed to read cached binary %s.", clbin.c_str()));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -366,7 +394,8 @@ bool OpenCLDeviceBase::OpenCLProgram::load_binary(const string& clbin,
|
||||
&size, &bytes, &status, &ciErr);
|
||||
|
||||
if(status != CL_SUCCESS || ciErr != CL_SUCCESS) {
|
||||
error_msg = "OpenCL failed create program from cached binary " + clbin + ": " + clewErrorString(status) + " " + clewErrorString(ciErr);
|
||||
add_error(string("OpenCL failed create program from cached binary ") + clbin + ": "
|
||||
+ clewErrorString(status) + " " + clewErrorString(ciErr));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -407,7 +436,7 @@ void OpenCLDeviceBase::OpenCLProgram::load()
|
||||
cache_locker);
|
||||
|
||||
if(!program) {
|
||||
log += "OpenCL program " + program_name + " not found in cache.\n";
|
||||
add_log(string("OpenCL program ") + program_name + " not found in cache.", true);
|
||||
|
||||
string basename = "cycles_kernel_" + program_name + "_" + device_md5 + "_" + OpenCLCache::get_kernel_md5();
|
||||
basename = path_cache_get(path_join("kernels", basename));
|
||||
@@ -424,10 +453,10 @@ void OpenCLDeviceBase::OpenCLProgram::load()
|
||||
/* If binary kernel exists already, try use it. */
|
||||
if(path_exists(clbin) && load_binary(clbin)) {
|
||||
/* Kernel loaded from binary, nothing to do. */
|
||||
log += "Loaded program from " + clbin + ".\n";
|
||||
add_log(string("Loaded program from ") + clbin + ".", true);
|
||||
}
|
||||
else {
|
||||
log += "Kernel file " + clbin + " either doesn't exist or failed to be loaded by driver.\n";
|
||||
add_log(string("Kernel file ") + clbin + " either doesn't exist or failed to be loaded by driver.", true);
|
||||
|
||||
/* If does not exist or loading binary failed, compile kernel. */
|
||||
if(!compile_kernel(debug_src)) {
|
||||
@@ -436,7 +465,7 @@ void OpenCLDeviceBase::OpenCLProgram::load()
|
||||
|
||||
/* Save binary for reuse. */
|
||||
if(!save_binary(clbin)) {
|
||||
log += "Saving compiled OpenCL kernel to " + clbin + " failed!";
|
||||
add_log(string("Saving compiled OpenCL kernel to ") + clbin + " failed!", true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,7 +475,7 @@ void OpenCLDeviceBase::OpenCLProgram::load()
|
||||
cache_locker);
|
||||
}
|
||||
else {
|
||||
log += "Found cached OpenCL program " + program_name + ".\n";
|
||||
add_log(string("Found cached OpenCL program ") + program_name + ".", true);
|
||||
}
|
||||
|
||||
for(map<ustring, cl_kernel>::iterator kernel = kernels.begin(); kernel != kernels.end(); ++kernel) {
|
||||
@@ -455,7 +484,7 @@ void OpenCLDeviceBase::OpenCLProgram::load()
|
||||
string name = "kernel_ocl_" + kernel->first.string();
|
||||
kernel->second = clCreateKernel(program, name.c_str(), &ciErr);
|
||||
if(device->opencl_error(ciErr)) {
|
||||
error_msg = "Error getting kernel " + name + " from program " + program_name + ": " + clewErrorString(ciErr);
|
||||
add_error(string("Error getting kernel ") + name + " from program " + program_name + ": " + clewErrorString(ciErr));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -465,12 +494,15 @@ void OpenCLDeviceBase::OpenCLProgram::load()
|
||||
|
||||
void OpenCLDeviceBase::OpenCLProgram::report_error()
|
||||
{
|
||||
/* If loaded is true, there was no error. */
|
||||
if(loaded) return;
|
||||
/* if use_stdout is true, the error was already reported. */
|
||||
if(use_stdout) return;
|
||||
|
||||
cerr << error_msg << endl;
|
||||
if(!output_msg.empty()) {
|
||||
if(!compile_output.empty()) {
|
||||
cerr << "OpenCL kernel build output for " << program_name << ":" << endl;
|
||||
cerr << output_msg << endl;
|
||||
cerr << compile_output << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -687,6 +687,12 @@ class IMAGE_PT_view_properties(Panel):
|
||||
sub.active = uvedit.show_stretch
|
||||
sub.row().prop(uvedit, "draw_stretch_type", expand=True)
|
||||
|
||||
col = layout.column()
|
||||
col.prop(uvedit, "show_other_objects")
|
||||
row = col.row()
|
||||
row.active = uvedit.show_other_objects
|
||||
row.prop(uvedit, "other_uv_filter", text="Filter")
|
||||
|
||||
if show_render and ima:
|
||||
layout.separator()
|
||||
render_slot = ima.render_slots.active
|
||||
|
||||
@@ -401,7 +401,7 @@ void AbcMeshWriter::writeMesh(DerivedMesh *dm)
|
||||
Int32ArraySample(loop_counts));
|
||||
|
||||
UVSample sample;
|
||||
if (m_settings.export_uvs) {
|
||||
if (m_first_frame && m_settings.export_uvs) {
|
||||
const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
|
||||
|
||||
if (!sample.indices.empty() && !sample.uvs.empty()) {
|
||||
@@ -470,7 +470,7 @@ void AbcMeshWriter::writeSubD(DerivedMesh *dm)
|
||||
Int32ArraySample(loop_counts));
|
||||
|
||||
UVSample sample;
|
||||
if (m_settings.export_uvs) {
|
||||
if (m_first_frame && m_settings.export_uvs) {
|
||||
const char *name = get_uv_sample(sample, m_custom_data_config, &dm->loopData);
|
||||
|
||||
if (!sample.indices.empty() && !sample.uvs.empty()) {
|
||||
@@ -565,7 +565,7 @@ void AbcMeshWriter::writeArbGeoParams(DerivedMesh *dm)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_settings.export_vcols) {
|
||||
if (m_first_frame && m_settings.export_vcols) {
|
||||
if (m_subdiv_schema.valid()) {
|
||||
write_custom_data(m_subdiv_schema.getArbGeomParams(), m_custom_data_config, &dm->loopData, CD_MLOOPCOL);
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ void BKE_cachefile_reload(const struct Main *bmain, struct CacheFile *cache_file
|
||||
|
||||
void BKE_cachefile_ensure_handle(const struct Main *bmain, struct CacheFile *cache_file);
|
||||
|
||||
void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene, float ctime, const float fps);
|
||||
void BKE_cachefile_update_frame(struct Main *bmain, struct Scene *scene,const float ctime, const float fps);
|
||||
|
||||
bool BKE_cachefile_filepath_get(
|
||||
const struct Main *bmain, const struct CacheFile *cache_file, float frame,
|
||||
|
||||
@@ -64,7 +64,7 @@ struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_
|
||||
|
||||
/* library_remap.c (keep here since they're general functions) */
|
||||
void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL();
|
||||
void BKE_libblock_free_ex(struct Main *bmain, void *idv, bool do_id_user) ATTR_NONNULL();
|
||||
void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user) ATTR_NONNULL();
|
||||
void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL();
|
||||
void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL();
|
||||
void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL();
|
||||
|
||||
@@ -88,4 +88,6 @@ bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv);
|
||||
bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv);
|
||||
void BKE_library_ID_test_usages(struct Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked);
|
||||
|
||||
void BKE_library_tag_unused_linked_data(struct Main *bmain, const bool do_init_tag);
|
||||
|
||||
#endif /* __BKE_LIBRARY_QUERY_H__ */
|
||||
|
||||
@@ -3256,7 +3256,7 @@ void DM_calc_tangents_names_from_gpu(
|
||||
*r_tangent_names_count = count;
|
||||
}
|
||||
|
||||
static void DM_calc_loop_tangents_thread(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
|
||||
static void DM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
|
||||
{
|
||||
struct SGLSLMeshToTangent *mesh2tangent = taskdata;
|
||||
/* new computation method */
|
||||
|
||||
@@ -453,7 +453,7 @@ finally:
|
||||
pRes[3] = fSign;
|
||||
}
|
||||
|
||||
static void emDM_calc_loop_tangents_thread(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
|
||||
static void emDM_calc_loop_tangents_thread(TaskPool * __restrict UNUSED(pool), void *taskdata, int UNUSED(threadid))
|
||||
{
|
||||
struct SGLSLEditMeshToTangent *mesh2tangent = taskdata;
|
||||
/* new computation method */
|
||||
|
||||
@@ -73,6 +73,8 @@
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_memarena.h"
|
||||
|
||||
#include "BLI_threads.h"
|
||||
#include "BLT_translation.h"
|
||||
@@ -1627,6 +1629,10 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
|
||||
ID *id, *id_next;
|
||||
int a;
|
||||
|
||||
LinkNode *copied_ids = NULL;
|
||||
LinkNode *linked_loop_candidates = NULL;
|
||||
MemArena *linklist_mem = BLI_memarena_new(256 * sizeof(copied_ids), __func__);
|
||||
|
||||
for (a = set_listbasepointers(bmain, lbarray); a--; ) {
|
||||
id = lbarray[a]->first;
|
||||
|
||||
@@ -1636,6 +1642,7 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
|
||||
|
||||
for (; id; id = id_next) {
|
||||
id->newid = NULL;
|
||||
id->tag &= ~LIB_TAG_DOIT;
|
||||
id_next = id->next; /* id is possibly being inserted again */
|
||||
|
||||
/* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its
|
||||
@@ -1658,6 +1665,10 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
|
||||
else {
|
||||
id_make_local(bmain, id, false, true);
|
||||
}
|
||||
|
||||
if (id->newid) {
|
||||
BLI_linklist_prepend_arena(&copied_ids, id, linklist_mem);
|
||||
}
|
||||
}
|
||||
else {
|
||||
id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW);
|
||||
@@ -1677,12 +1688,13 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
|
||||
/* We have to remap local usages of old (linked) ID to new (local) id in a second loop, as lbarray ordering is not
|
||||
* enough to ensure us we did catch all dependencies (e.g. if making local a parent object before its child...).
|
||||
* See T48907. */
|
||||
for (a = set_listbasepointers(bmain, lbarray); a--; ) {
|
||||
for (id = lbarray[a]->first; id; id = id->next) {
|
||||
if (id->newid) {
|
||||
BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
|
||||
}
|
||||
}
|
||||
for (LinkNode *it = copied_ids; it; it = it->next) {
|
||||
id = it->link;
|
||||
|
||||
BLI_assert(id->newid != NULL);
|
||||
BLI_assert(id->lib != NULL);
|
||||
|
||||
BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE);
|
||||
}
|
||||
|
||||
/* Third step: remove datablocks that have been copied to be localized and are no more used in the end...
|
||||
@@ -1690,55 +1702,108 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged
|
||||
bool do_loop = true;
|
||||
while (do_loop) {
|
||||
do_loop = false;
|
||||
for (a = set_listbasepointers(bmain, lbarray); a--; ) {
|
||||
for (id = lbarray[a]->first; id; id = id_next) {
|
||||
id_next = id->next;
|
||||
if (id->newid) {
|
||||
bool is_local = false, is_lib = false;
|
||||
for (LinkNode *it = copied_ids; it; it = it->next) {
|
||||
if ((id = it->link) == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Attempt to re-link copied proxy objects. This allows appending of an entire scene
|
||||
* from another blend file into this one, even when that blend file contains proxified
|
||||
* armatures that have local references. Since the proxified object needs to be linked
|
||||
* (not local), this will only work when the "Localize all" checkbox is disabled.
|
||||
* TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
|
||||
if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
|
||||
Object *ob = (Object *)id;
|
||||
Object *ob_new = (Object *)id->newid;
|
||||
bool is_local = false, is_lib = false;
|
||||
|
||||
/* Proxies only work when the proxified object is linked-in from a library. */
|
||||
if (ob->proxy->id.lib == NULL) {
|
||||
printf("Warning, proxy object %s will loose its link to %s, because the "
|
||||
"proxified object is local.\n", id->newid->name, ob->proxy->id.name);
|
||||
}
|
||||
/* We can only switch the proxy'ing to a made-local proxy if it is no longer
|
||||
* referred to from a library. Not checking for local use; if new local proxy
|
||||
* was not used locally would be a nasty bug! */
|
||||
else if (is_local || is_lib) {
|
||||
printf("Warning, made-local proxy object %s will loose its link to %s, "
|
||||
"because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n",
|
||||
id->newid->name, ob->proxy->id.name, is_local, is_lib);
|
||||
}
|
||||
else {
|
||||
/* we can switch the proxy'ing from the linked-in to the made-local proxy.
|
||||
* BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
|
||||
* was already allocated by BKE_object_make_local_ex() (which called BKE_object_copy_ex). */
|
||||
ob_new->proxy = ob->proxy;
|
||||
ob_new->proxy_group = ob->proxy_group;
|
||||
ob_new->proxy_from = ob->proxy_from;
|
||||
ob_new->proxy->proxy_from = ob_new;
|
||||
ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
|
||||
}
|
||||
}
|
||||
BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
|
||||
|
||||
BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib);
|
||||
if (!is_local && !is_lib) {
|
||||
BKE_libblock_free(bmain, id);
|
||||
do_loop = true;
|
||||
/* Attempt to re-link copied proxy objects. This allows appending of an entire scene
|
||||
* from another blend file into this one, even when that blend file contains proxified
|
||||
* armatures that have local references. Since the proxified object needs to be linked
|
||||
* (not local), this will only work when the "Localize all" checkbox is disabled.
|
||||
* TL;DR: this is a dirty hack on top of an already weak feature (proxies). */
|
||||
if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) {
|
||||
Object *ob = (Object *)id;
|
||||
Object *ob_new = (Object *)id->newid;
|
||||
|
||||
/* Proxies only work when the proxified object is linked-in from a library. */
|
||||
if (ob->proxy->id.lib == NULL) {
|
||||
printf("Warning, proxy object %s will loose its link to %s, because the "
|
||||
"proxified object is local.\n", id->newid->name, ob->proxy->id.name);
|
||||
}
|
||||
/* We can only switch the proxy'ing to a made-local proxy if it is no longer
|
||||
* referred to from a library. Not checking for local use; if new local proxy
|
||||
* was not used locally would be a nasty bug! */
|
||||
else if (is_local || is_lib) {
|
||||
printf("Warning, made-local proxy object %s will loose its link to %s, "
|
||||
"because the linked-in proxy is referenced (is_local=%i, is_lib=%i).\n",
|
||||
id->newid->name, ob->proxy->id.name, is_local, is_lib);
|
||||
}
|
||||
else {
|
||||
/* we can switch the proxy'ing from the linked-in to the made-local proxy.
|
||||
* BKE_object_make_proxy() shouldn't be used here, as it allocates memory that
|
||||
* was already allocated by BKE_object_make_local_ex() (which called BKE_object_copy_ex). */
|
||||
ob_new->proxy = ob->proxy;
|
||||
ob_new->proxy_group = ob->proxy_group;
|
||||
ob_new->proxy_from = ob->proxy_from;
|
||||
ob_new->proxy->proxy_from = ob_new;
|
||||
ob->proxy = ob->proxy_from = ob->proxy_group = NULL;
|
||||
}
|
||||
}
|
||||
/* Special hack for groups... Thing is, since we can't instantiate them here, we need to ensure
|
||||
* they remain 'alive' (only instantiation is a real group 'user'... *sigh* See T49722. */
|
||||
else if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) {
|
||||
id_us_ensure_real(id->newid);
|
||||
}
|
||||
|
||||
if (!is_local) {
|
||||
if (!is_lib) { /* Not used at all, we can free it! */
|
||||
BKE_libblock_free(bmain, id);
|
||||
it->link = NULL;
|
||||
do_loop = true;
|
||||
}
|
||||
else { /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */
|
||||
/* Note that we store the node, not directly ID pointer, that way if it->link is set to NULL
|
||||
* later we can skip it in lib-dependency cycles search later. */
|
||||
BLI_linklist_prepend_arena(&linked_loop_candidates, it, linklist_mem);
|
||||
id->tag |= LIB_TAG_DOIT;
|
||||
|
||||
/* Grrrrrrr... those half-datablocks-stuff... grrrrrrrrrrr...
|
||||
* Here we have to also tag them as potential candidates, otherwise they would falsy report
|
||||
* ID they used as 'directly used' in fourth step. */
|
||||
ID *ntree = (ID *)ntreeFromID(id);
|
||||
if (ntree != NULL) {
|
||||
ntree->tag |= LIB_TAG_DOIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Fourth step: Try to find circle dependencies between indirectly-linked-only datablocks.
|
||||
* Those are fake 'usages' that prevent their deletion. See T49775 for nice ugly case. */
|
||||
BKE_library_tag_unused_linked_data(bmain, false);
|
||||
for (LinkNode *it = linked_loop_candidates; it; it = it->next) {
|
||||
if (it->link == NULL) {
|
||||
continue;
|
||||
}
|
||||
if ((id = ((LinkNode *)it->link)->link) == NULL) {
|
||||
it->link = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Note: in theory here we are only handling datablocks forming exclusive linked dependency-cycles-based
|
||||
* archipelagos, so no need to check again after we have deleted one, as done in previous step. */
|
||||
if (id->tag & LIB_TAG_DOIT) {
|
||||
/* Note: *in theory* IDs tagged here are fully *outside* of file scope, totally unused, so we can
|
||||
* directly wipe them out without caring about clearing their usages.
|
||||
* However, this is a highly-risky presumption, and nice crasher in case something goes wrong here.
|
||||
* So for 2.78a will keep the safe option, and switch to more efficient one in master later. */
|
||||
#if 0
|
||||
BKE_libblock_free_ex(bmain, id, false);
|
||||
#else
|
||||
BKE_libblock_unlink(bmain, id, false, false);
|
||||
BKE_libblock_free(bmain, id);
|
||||
#endif
|
||||
it->link = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_memarena_free(linklist_mem);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -961,30 +961,32 @@ static int foreach_libblock_id_users_callback(void *user_data, ID *self_id, ID *
|
||||
{
|
||||
IDUsersIter *iter = user_data;
|
||||
|
||||
/* XXX This is actually some kind of hack...
|
||||
* Issue is, shapekeys' 'from' ID pointer is not actually ID usage.
|
||||
* Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
|
||||
*/
|
||||
if ((GS(self_id->name) == ID_KE) && (((Key *)self_id)->from == *id_p)) {
|
||||
return IDWALK_RET_NOP;
|
||||
}
|
||||
/* XXX another hack, for similar reasons as above one. */
|
||||
if ((GS(self_id->name) == ID_OB) && (((Object *)self_id)->proxy_from == (Object *)*id_p)) {
|
||||
return IDWALK_RET_NOP;
|
||||
}
|
||||
|
||||
if (*id_p && (*id_p == iter->id)) {
|
||||
#if 0
|
||||
printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
|
||||
iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
|
||||
(iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
|
||||
(cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
|
||||
#endif
|
||||
if (cb_flag & IDWALK_INDIRECT_USAGE) {
|
||||
iter->count_indirect++;
|
||||
if (*id_p) {
|
||||
/* XXX This is actually some kind of hack...
|
||||
* Issue is, shapekeys' 'from' ID pointer is not actually ID usage.
|
||||
* Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
|
||||
*/
|
||||
if ((GS(self_id->name) == ID_KE) && (((Key *)self_id)->from == *id_p)) {
|
||||
return IDWALK_RET_NOP;
|
||||
}
|
||||
else {
|
||||
iter->count_direct++;
|
||||
/* XXX another hack, for similar reasons as above one. */
|
||||
if ((GS(self_id->name) == ID_OB) && (((Object *)self_id)->proxy_from == (Object *)*id_p)) {
|
||||
return IDWALK_RET_NOP;
|
||||
}
|
||||
|
||||
if (*id_p == iter->id) {
|
||||
#if 0
|
||||
printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n",
|
||||
iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0,
|
||||
(iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0,
|
||||
(cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0);
|
||||
#endif
|
||||
if (cb_flag & IDWALK_INDIRECT_USAGE) {
|
||||
iter->count_indirect++;
|
||||
}
|
||||
else {
|
||||
iter->count_direct++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1099,3 +1101,71 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo
|
||||
*is_used_local = (iter.count_direct != 0);
|
||||
*is_used_linked = (iter.count_indirect != 0);
|
||||
}
|
||||
|
||||
|
||||
static int foreach_libblock_tag_unused_linked_data_callback(void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag))
|
||||
{
|
||||
bool *is_changed = user_data;
|
||||
|
||||
if (*id_p) {
|
||||
/* XXX This is actually some kind of hack...
|
||||
* Issue is, shapekeys' 'from' ID pointer is not actually ID usage.
|
||||
* Maybe we should even nuke it from BKE_library_foreach_ID_link, not 100% sure yet...
|
||||
*/
|
||||
if ((GS(self_id->name) == ID_KE) && (((Key *)self_id)->from == *id_p)) {
|
||||
return IDWALK_RET_NOP;
|
||||
}
|
||||
/* XXX another hack, for similar reasons as above one. */
|
||||
if ((GS(self_id->name) == ID_OB) && (((Object *)self_id)->proxy_from == (Object *)*id_p)) {
|
||||
return IDWALK_RET_NOP;
|
||||
}
|
||||
|
||||
/* If checked id is used by an assumed used ID, then it is also used and not part of any linked archipelago. */
|
||||
if (!(self_id->tag & LIB_TAG_DOIT) && ((*id_p)->tag & LIB_TAG_DOIT)) {
|
||||
(*id_p)->tag &= ~LIB_TAG_DOIT;
|
||||
*is_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return IDWALK_RET_NOP;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect orphaned linked data blocks (i.e. linked data not used (directly or indirectly) in any way by any local data),
|
||||
* including complex cases like 'linked archipelagoes', i.e. linked datablocks that use each other in loops,
|
||||
* which prevents their deletion by 'basic' usage checks...
|
||||
*
|
||||
* \param do_init_tag if \a true, all linked data are checked, if \a false, only linked datablocks already tagged with
|
||||
* LIB_TAG_DOIT are checked.
|
||||
*/
|
||||
void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag)
|
||||
{
|
||||
ListBase *lb_array[MAX_LIBARRAY];
|
||||
|
||||
if (do_init_tag) {
|
||||
int i = set_listbasepointers(bmain, lb_array);
|
||||
|
||||
while (i--) {
|
||||
for (ID *id = lb_array[i]->first; id; id = id->next) {
|
||||
if (id->lib && (id->tag & LIB_TAG_INDIRECT) != 0) {
|
||||
id->tag |= LIB_TAG_DOIT;
|
||||
}
|
||||
else {
|
||||
id->tag &= ~LIB_TAG_DOIT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool do_loop = true;
|
||||
while (do_loop) {
|
||||
int i = set_listbasepointers(bmain, lb_array);
|
||||
do_loop = false;
|
||||
|
||||
while (i--) {
|
||||
for (ID *id = lb_array[i]->first; id; id = id->next) {
|
||||
BKE_library_foreach_ID_link(id, foreach_libblock_tag_unused_linked_data_callback, &do_loop, IDWALK_NOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,7 +531,7 @@ static void ocean_compute_htilda(void *userdata, const int i)
|
||||
}
|
||||
}
|
||||
|
||||
static void ocean_compute_displacement_y(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
static void ocean_compute_displacement_y(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
{
|
||||
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
|
||||
const Ocean *o = osd->o;
|
||||
@@ -539,7 +539,7 @@ static void ocean_compute_displacement_y(TaskPool *pool, void *UNUSED(taskdata),
|
||||
fftw_execute(o->_disp_y_plan);
|
||||
}
|
||||
|
||||
static void ocean_compute_displacement_x(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
static void ocean_compute_displacement_x(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
{
|
||||
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
|
||||
const Ocean *o = osd->o;
|
||||
@@ -567,7 +567,7 @@ static void ocean_compute_displacement_x(TaskPool *pool, void *UNUSED(taskdata),
|
||||
fftw_execute(o->_disp_x_plan);
|
||||
}
|
||||
|
||||
static void ocean_compute_displacement_z(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
static void ocean_compute_displacement_z(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
{
|
||||
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
|
||||
const Ocean *o = osd->o;
|
||||
@@ -595,7 +595,7 @@ static void ocean_compute_displacement_z(TaskPool *pool, void *UNUSED(taskdata),
|
||||
fftw_execute(o->_disp_z_plan);
|
||||
}
|
||||
|
||||
static void ocean_compute_jacobian_jxx(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
static void ocean_compute_jacobian_jxx(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
{
|
||||
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
|
||||
const Ocean *o = osd->o;
|
||||
@@ -627,7 +627,7 @@ static void ocean_compute_jacobian_jxx(TaskPool *pool, void *UNUSED(taskdata), i
|
||||
}
|
||||
}
|
||||
|
||||
static void ocean_compute_jacobian_jzz(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
static void ocean_compute_jacobian_jzz(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
{
|
||||
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
|
||||
const Ocean *o = osd->o;
|
||||
@@ -659,7 +659,7 @@ static void ocean_compute_jacobian_jzz(TaskPool *pool, void *UNUSED(taskdata), i
|
||||
}
|
||||
}
|
||||
|
||||
static void ocean_compute_jacobian_jxz(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
static void ocean_compute_jacobian_jxz(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
{
|
||||
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
|
||||
const Ocean *o = osd->o;
|
||||
@@ -685,7 +685,7 @@ static void ocean_compute_jacobian_jxz(TaskPool *pool, void *UNUSED(taskdata), i
|
||||
fftw_execute(o->_Jxz_plan);
|
||||
}
|
||||
|
||||
static void ocean_compute_normal_x(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
static void ocean_compute_normal_x(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
{
|
||||
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
|
||||
const Ocean *o = osd->o;
|
||||
@@ -704,7 +704,7 @@ static void ocean_compute_normal_x(TaskPool *pool, void *UNUSED(taskdata), int U
|
||||
fftw_execute(o->_N_x_plan);
|
||||
}
|
||||
|
||||
static void ocean_compute_normal_z(TaskPool *pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
static void ocean_compute_normal_z(TaskPool * __restrict pool, void *UNUSED(taskdata), int UNUSED(threadid))
|
||||
{
|
||||
OceanSimulateData *osd = BLI_task_pool_userdata(pool);
|
||||
const Ocean *o = osd->o;
|
||||
|
||||
@@ -409,7 +409,7 @@ Palette *BKE_palette_copy(Main *bmain, Palette *palette)
|
||||
return palette_new;
|
||||
}
|
||||
|
||||
void BKE_palette_make_local(Main *bmain, Palette *palette, bool lib_local)
|
||||
void BKE_palette_make_local(Main *bmain, Palette *palette, const bool lib_local)
|
||||
{
|
||||
BKE_id_make_local_generic(bmain, &palette->id, true, lib_local);
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ static void attach_stabilization_baseline_data(
|
||||
MovieTrackingTrack *track,
|
||||
TrackStabilizationBase *private_data)
|
||||
{
|
||||
return BLI_ghash_insert(ctx->private_track_data, track, private_data);
|
||||
BLI_ghash_insert(ctx->private_track_data, track, private_data);
|
||||
}
|
||||
|
||||
static void discard_stabilization_baseline_data(void *val)
|
||||
|
||||
@@ -1305,7 +1305,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!MAIN_VERSION_ATLEAST(main, 279, 0)) {
|
||||
if (!MAIN_VERSION_ATLEAST(main, 278, 2)) {
|
||||
if (!DNA_struct_elem_find(fd->filesdna, "FFMpegCodecData", "int", "ffmpeg_preset")) {
|
||||
for (Scene *scene = main->scene.first; scene; scene = scene->id.next) {
|
||||
/* "medium" is the preset FFmpeg uses when no presets are given. */
|
||||
|
||||
@@ -3855,9 +3855,10 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
|
||||
bv = find_bevvert(bp, l->v);
|
||||
vm = bv->vmesh;
|
||||
e = find_edge_half(bv, l->e);
|
||||
BLI_assert(e != NULL);
|
||||
bme = e->e;
|
||||
eprev = find_edge_half(bv, lprev->e);
|
||||
BLI_assert(e != NULL && eprev != NULL);
|
||||
BLI_assert(eprev != NULL);
|
||||
|
||||
/* which direction around our vertex do we travel to match orientation of f? */
|
||||
if (e->prev == eprev) {
|
||||
|
||||
@@ -2218,32 +2218,6 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB
|
||||
|
||||
/* ******************* copy and paste ******************** */
|
||||
|
||||
static void ui_but_copy_data_path(uiBut *but, const bool full_path)
|
||||
{
|
||||
char *id_path;
|
||||
|
||||
if (but->rnapoin.id.data == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (full_path) {
|
||||
if (but->rnaprop) {
|
||||
id_path = RNA_path_full_property_py_ex(&but->rnapoin, but->rnaprop, but->rnaindex, true);
|
||||
}
|
||||
else {
|
||||
id_path = RNA_path_full_struct_py(&but->rnapoin);
|
||||
}
|
||||
}
|
||||
else {
|
||||
id_path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
|
||||
}
|
||||
|
||||
if (id_path) {
|
||||
WM_clipboard_text_set(id_path, false);
|
||||
MEM_freeN(id_path);
|
||||
}
|
||||
}
|
||||
|
||||
/* c = copy, v = paste */
|
||||
static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode)
|
||||
{
|
||||
@@ -6985,7 +6959,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
|
||||
if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) {
|
||||
/* handle copy-paste */
|
||||
if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS &&
|
||||
IS_EVENT_MOD(event, ctrl, oskey))
|
||||
IS_EVENT_MOD(event, ctrl, oskey) && !event->shift && !event->alt)
|
||||
{
|
||||
/* Specific handling for listrows, we try to find their overlapping tex button. */
|
||||
if (but->type == UI_BTYPE_LISTROW) {
|
||||
@@ -6995,13 +6969,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
|
||||
data = but->active;
|
||||
}
|
||||
}
|
||||
|
||||
/* special case, copy-data-path */
|
||||
if ((event->type == CKEY) && event->shift) {
|
||||
ui_but_copy_data_path(but, event->alt != 0);
|
||||
return WM_UI_HANDLER_BREAK;
|
||||
}
|
||||
|
||||
ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v');
|
||||
return WM_UI_HANDLER_BREAK;
|
||||
}
|
||||
|
||||
@@ -113,19 +113,33 @@ static int copy_data_path_button_poll(bContext *C)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
static int copy_data_path_button_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
PointerRNA ptr;
|
||||
PropertyRNA *prop;
|
||||
char *path;
|
||||
int index;
|
||||
|
||||
const bool full_path = RNA_boolean_get(op->ptr, "full_path");
|
||||
|
||||
/* try to create driver using property retrieved from UI */
|
||||
UI_context_active_but_prop_get(C, &ptr, &prop, &index);
|
||||
|
||||
if (ptr.id.data && ptr.data && prop) {
|
||||
path = RNA_path_from_ID_to_property(&ptr, prop);
|
||||
|
||||
if (ptr.id.data != NULL) {
|
||||
|
||||
if (full_path) {
|
||||
|
||||
if (prop) {
|
||||
path = RNA_path_full_property_py_ex(&ptr, prop, index, true);
|
||||
}
|
||||
else {
|
||||
path = RNA_path_full_struct_py(&ptr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
path = RNA_path_from_ID_to_property(&ptr, prop);
|
||||
}
|
||||
|
||||
if (path) {
|
||||
WM_clipboard_text_set(path, false);
|
||||
MEM_freeN(path);
|
||||
@@ -138,6 +152,8 @@ static int copy_data_path_button_exec(bContext *C, wmOperator *UNUSED(op))
|
||||
|
||||
static void UI_OT_copy_data_path_button(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* identifiers */
|
||||
ot->name = "Copy Data Path";
|
||||
ot->idname = "UI_OT_copy_data_path_button";
|
||||
@@ -149,6 +165,10 @@ static void UI_OT_copy_data_path_button(wmOperatorType *ot)
|
||||
|
||||
/* flags */
|
||||
ot->flag = OPTYPE_REGISTER;
|
||||
|
||||
/* properties */
|
||||
prop = RNA_def_boolean(ot->srna, "full_path", false, "full_path", "Copy full data path");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
static int copy_python_command_button_poll(bContext *C)
|
||||
@@ -1115,6 +1135,7 @@ void ED_operatortypes_ui(void)
|
||||
void ED_keymap_ui(wmKeyConfig *keyconf)
|
||||
{
|
||||
wmKeyMap *keymap = WM_keymap_find(keyconf, "User Interface", 0, 0);
|
||||
wmKeyMapItem *kmi;
|
||||
|
||||
/* eyedroppers - notice they all have the same shortcut, but pass the event
|
||||
* through until a suitable eyedropper for the active button is found */
|
||||
@@ -1122,6 +1143,11 @@ void ED_keymap_ui(wmKeyConfig *keyconf)
|
||||
WM_keymap_add_item(keymap, "UI_OT_eyedropper_id", EKEY, KM_PRESS, 0, 0);
|
||||
WM_keymap_add_item(keymap, "UI_OT_eyedropper_depth", EKEY, KM_PRESS, 0, 0);
|
||||
|
||||
/* Copy Data Path */
|
||||
WM_keymap_add_item(keymap, "UI_OT_copy_data_path_button", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0);
|
||||
kmi = WM_keymap_add_item(keymap, "UI_OT_copy_data_path_button", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT | KM_ALT, 0);
|
||||
RNA_boolean_set(kmi->ptr, "full_path", true);
|
||||
|
||||
/* keyframes */
|
||||
WM_keymap_add_item(keymap, "ANIM_OT_keyframe_insert_button", IKEY, KM_PRESS, 0, 0);
|
||||
WM_keymap_add_item(keymap, "ANIM_OT_keyframe_delete_button", IKEY, KM_PRESS, KM_ALT, 0);
|
||||
|
||||
@@ -2791,7 +2791,7 @@ void init_userdef_do_versions(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (!USER_VERSION_ATLEAST(278, 1)) {
|
||||
if (!USER_VERSION_ATLEAST(278, 2)) {
|
||||
bTheme *btheme;
|
||||
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
|
||||
rgba_char_args_set(btheme->tv3d.vertex_bevel, 0, 165, 255, 255);
|
||||
|
||||
@@ -377,7 +377,7 @@ static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly)
|
||||
glEnd();
|
||||
}
|
||||
|
||||
static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage)
|
||||
static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage, const int other_uv_filter)
|
||||
{
|
||||
Mesh *me = ob->data;
|
||||
MPoly *mpoly = me->mpoly;
|
||||
@@ -389,14 +389,19 @@ static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage)
|
||||
}
|
||||
|
||||
for (a = me->totpoly; a != 0; a--, mpoly++, mtpoly++) {
|
||||
if (mtpoly->tpage != curimage) {
|
||||
continue;
|
||||
if (other_uv_filter == SI_FILTER_ALL) {
|
||||
/* Nothing to compare, all UV faces are visible. */
|
||||
}
|
||||
else if (other_uv_filter == SI_FILTER_SAME_IMAGE) {
|
||||
if (mtpoly->tpage != curimage) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
draw_uvs_lineloop_mpoly(me, mpoly);
|
||||
}
|
||||
}
|
||||
static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage)
|
||||
static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage, const int other_uv_filter)
|
||||
{
|
||||
Mesh *me = ob->data;
|
||||
MPoly *mpoly = me->mpoly;
|
||||
@@ -436,27 +441,34 @@ static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage)
|
||||
}
|
||||
|
||||
for (a = me->totpoly; a != 0; a--, mpoly++) {
|
||||
const int mat_nr = mpoly->mat_nr;
|
||||
if ((mat_nr >= totcol) ||
|
||||
(BLI_BITMAP_TEST(mat_test_array, mat_nr)) == 0)
|
||||
{
|
||||
continue;
|
||||
if (other_uv_filter == SI_FILTER_ALL) {
|
||||
/* Nothing to compare, all UV faces are visible. */
|
||||
}
|
||||
else if (other_uv_filter == SI_FILTER_SAME_IMAGE) {
|
||||
const int mat_nr = mpoly->mat_nr;
|
||||
if ((mat_nr >= totcol) ||
|
||||
(BLI_BITMAP_TEST(mat_test_array, mat_nr)) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
draw_uvs_lineloop_mpoly(me, mpoly);
|
||||
}
|
||||
}
|
||||
static void draw_uvs_other_mesh(Object *ob, const Image *curimage, const bool new_shading_nodes)
|
||||
static void draw_uvs_other_mesh(Object *ob, const Image *curimage, const bool new_shading_nodes,
|
||||
const int other_uv_filter)
|
||||
{
|
||||
if (new_shading_nodes) {
|
||||
draw_uvs_other_mesh_new_shading(ob, curimage);
|
||||
draw_uvs_other_mesh_new_shading(ob, curimage, other_uv_filter);
|
||||
}
|
||||
else {
|
||||
draw_uvs_other_mesh_texface(ob, curimage);
|
||||
draw_uvs_other_mesh_texface(ob, curimage, other_uv_filter);
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage, const bool new_shading_nodes)
|
||||
static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage, const bool new_shading_nodes,
|
||||
const int other_uv_filter)
|
||||
{
|
||||
Base *base;
|
||||
|
||||
@@ -470,7 +482,7 @@ static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage,
|
||||
if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
|
||||
|
||||
if ((ob->type == OB_MESH) && (ob != obedit) && ((Mesh *)ob->data)->mloopuv) {
|
||||
draw_uvs_other_mesh(ob, curimage, new_shading_nodes);
|
||||
draw_uvs_other_mesh(ob, curimage, new_shading_nodes, other_uv_filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,7 +495,7 @@ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
|
||||
Material *ma;
|
||||
|
||||
if (sima->flag & SI_DRAW_OTHER) {
|
||||
draw_uvs_other(scene, ob, curimage, new_shading_nodes);
|
||||
draw_uvs_other(scene, ob, curimage, new_shading_nodes, sima->other_uv_filter);
|
||||
}
|
||||
|
||||
UI_ThemeColor(TH_UV_SHADOW);
|
||||
@@ -586,7 +598,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
|
||||
curimage = (activetf) ? activetf->tpage : ima;
|
||||
}
|
||||
|
||||
draw_uvs_other(scene, obedit, curimage, new_shading_nodes);
|
||||
draw_uvs_other(scene, obedit, curimage, new_shading_nodes, sima->other_uv_filter);
|
||||
}
|
||||
|
||||
/* 1. draw shadow mesh */
|
||||
|
||||
@@ -898,6 +898,10 @@ typedef struct SpaceImage {
|
||||
char dt_uvstretch;
|
||||
char around;
|
||||
|
||||
/* Filter settings when editor shows other object's UVs. */
|
||||
int other_uv_filter;
|
||||
int pad2;
|
||||
|
||||
MaskSpaceInfo mask_info;
|
||||
} SpaceImage;
|
||||
|
||||
@@ -976,6 +980,12 @@ typedef enum eSpaceImage_Flag {
|
||||
SI_SHOW_B = (1 << 29),
|
||||
} eSpaceImage_Flag;
|
||||
|
||||
/* SpaceImage->other_uv_filter */
|
||||
typedef enum eSpaceImage_OtherUVFilter {
|
||||
SI_FILTER_SAME_IMAGE = 0,
|
||||
SI_FILTER_ALL = 1,
|
||||
} eSpaceImage_OtherUVFilter;
|
||||
|
||||
/* Text Editor ============================================ */
|
||||
|
||||
/* Text Editor */
|
||||
|
||||
@@ -1967,6 +1967,13 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
static EnumPropertyItem other_uv_filter_items[] = {
|
||||
{SI_FILTER_ALL, "ALL", 0, "All", "No filter, show all islands from other objects"},
|
||||
{SI_FILTER_SAME_IMAGE, "SAME_IMAGE", ICON_IMAGE_DATA, "Same Image",
|
||||
"Only show others' UV islads who's active image matches image of the active face"},
|
||||
{0, NULL, 0, NULL, NULL}
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "SpaceUVEditor", NULL);
|
||||
RNA_def_struct_sdna(srna, "SpaceImage");
|
||||
RNA_def_struct_nested(brna, srna, "SpaceImageEditor");
|
||||
@@ -2054,6 +2061,13 @@ static void rna_def_space_image_uv(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Live Unwrap",
|
||||
"Continuously unwrap the selected UV island while transforming pinned vertices");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
|
||||
|
||||
/* Other UV filtering */
|
||||
prop = RNA_def_property(srna, "other_uv_filter", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, other_uv_filter_items);
|
||||
RNA_def_property_ui_text(prop, "Other UV filter",
|
||||
"Filter applied on the other object's UV to limit displayed");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
|
||||
}
|
||||
|
||||
static void rna_def_space_outliner(BlenderRNA *brna)
|
||||
|
||||
@@ -317,7 +317,13 @@ void bpy_app_generic_callback(struct Main *UNUSED(main), struct ID *id, void *ar
|
||||
func = PyList_GET_ITEM(cb_list, pos);
|
||||
ret = PyObject_Call(func, args, NULL);
|
||||
if (ret == NULL) {
|
||||
PyErr_Print();
|
||||
/* Don't set last system variables because they might cause some
|
||||
* dangling pointers to external render engines (when exception
|
||||
* happens during rendering) which will break logic of render pipeline
|
||||
* which expects to be the only user of render engine when rendering
|
||||
* is finished.
|
||||
*/
|
||||
PyErr_PrintEx(0);
|
||||
PyErr_Clear();
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -2648,7 +2648,8 @@ PyDoc_STRVAR(BPy_EnumProperty_doc,
|
||||
" .. warning::\n"
|
||||
"\n"
|
||||
" There is a known bug with using a callback,\n"
|
||||
" Python must keep a reference to the strings returned or Blender will crash.\n"
|
||||
" Python must keep a reference to the strings returned or Blender will misbehave\n"
|
||||
" or even crash."
|
||||
"\n"
|
||||
" :type items: sequence of string tuples or a function\n"
|
||||
BPY_PROPDEF_NAME_DOC
|
||||
|
||||
@@ -77,6 +77,10 @@ static wmKeyMapItem *wm_keymap_item_copy(wmKeyMapItem *kmi)
|
||||
kmin->properties = IDP_CopyProperty(kmin->properties);
|
||||
kmin->ptr->data = kmin->properties;
|
||||
}
|
||||
else {
|
||||
kmin->properties = NULL;
|
||||
kmin->ptr = NULL;
|
||||
}
|
||||
|
||||
return kmin;
|
||||
}
|
||||
@@ -87,6 +91,8 @@ static void wm_keymap_item_free(wmKeyMapItem *kmi)
|
||||
if (kmi->ptr) {
|
||||
WM_operator_properties_free(kmi->ptr);
|
||||
MEM_freeN(kmi->ptr);
|
||||
kmi->ptr = NULL;
|
||||
kmi->properties = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +127,6 @@ static void wm_keymap_item_properties_update_ot(wmKeyMapItem *kmi)
|
||||
else {
|
||||
/* zombie keymap item */
|
||||
wm_keymap_item_free(kmi);
|
||||
kmi->ptr = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user