From 32c2cba4ef1c940dab559cdc47b886c60cc9f2e1 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 20 Oct 2016 13:32:52 +0200 Subject: [PATCH 001/590] Fix T49797: Exception from scene update handler might leak external engine descriptors This was causing memory leaks in Cycles. Some more detailed information in the comment in the code. Seems to be safe and nice enough for 2.78a. --- source/blender/python/intern/bpy_app_handlers.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index 6a8b0b065c2..1cc2d6f1307 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -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 { From 0c4d949effa88f2ad54297a865fb2763f61c61aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Thu, 20 Oct 2016 19:43:22 +0200 Subject: [PATCH 002/590] Alembic: only export custom data (UVs, VCols) once, on the first frame. This would cause Alembic to throw an exception and fail exporting animations because it was trying to recreate and overwrite the attributes for each frame. --- source/blender/alembic/intern/abc_mesh.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index 84b89d9ab9e..bb5d5ce3566 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -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); } From f7ce482385b760135a36ff778e8c3436cdcf5404 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Fri, 21 Oct 2016 02:49:00 +0200 Subject: [PATCH 003/590] Cycles: Fix another OpenCL logging issue Previously an error message would be printed whenever the OpenCL build produced output. However, some frameworks seem to print extra information even if the build succeeded, so now the actual returned error is checked as well. When --debug-cycles is activated, the build output will always be printed, otherwise it only gets printed if there was an error. --- intern/cycles/device/opencl/opencl_base.cpp | 3 +++ intern/cycles/device/opencl/opencl_util.cpp | 19 ++++++------------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/intern/cycles/device/opencl/opencl_base.cpp b/intern/cycles/device/opencl/opencl_base.cpp index ea65be31195..e67ffb1a836 100644 --- a/intern/cycles/device/opencl/opencl_base.cpp +++ b/intern/cycles/device/opencl/opencl_base.cpp @@ -233,6 +233,9 @@ bool OpenCLDeviceBase::load_kernels(const DeviceRequestedFeatures& requested_fea #else foreach(OpenCLProgram *program, programs) { program->load(); + if(!program->is_loaded()) { + return false; + } } #endif diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp index 86aa8057604..e425ae8e2e8 100644 --- a/intern/cycles/device/opencl/opencl_util.cpp +++ b/intern/cycles/device/opencl/opencl_util.cpp @@ -316,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 build_log(ret_val_size + 1); clGetProgramBuildInfo(program, device->cdDevice, CL_PROGRAM_BUILD_LOG, ret_val_size, &build_log[0], NULL); @@ -323,22 +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')) { - add_error("OpenCL build failed: errors in console"); - if(use_stdout) { - fprintf(stderr, "OpenCL kernel build output:\n%s\n", &build_log[0]); - } - else { - compile_output = string(&build_log[0]); - } + add_log(string("OpenCL program ") + program_name + " build output: " + string(&build_log[0]), ciErr == CL_SUCCESS); } } - if(ciErr != CL_SUCCESS) { - add_error(string("OpenCL build failed: ") + clewErrorString(ciErr)); - return false; - } - - return true; + return (ciErr == CL_SUCCESS); } bool OpenCLDeviceBase::OpenCLProgram::compile_kernel(const string *debug_src) From b51874437d86a84684ed3327874285520cb886f4 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 21 Oct 2016 16:06:53 +0200 Subject: [PATCH 004/590] Fix T49804: Display grid Scale/Subdivision are sometimes disabled in View3D when they should not. Not really possible to precisely detect all cases in which they should or should not be active, but at least now it won't show as disabled when it actually has some effects. --- release/scripts/startup/bl_ui/space_view3d.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index fad52143ae5..8a3a5d3b7e8 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3231,8 +3231,10 @@ class VIEW3D_PT_view3d_display(Panel): row.prop(view, "show_axis_z", text="Z", toggle=True) sub = col.column(align=True) - sub.active = (display_all and view.show_floor) - sub.prop(view, "grid_lines", text="Lines") + sub.active = bool(view.show_floor or view.region_quadviews or not view.region_3d.is_perspective) + subsub = sub.column(align=True) + subsub.active = view.show_floor + subsub.prop(view, "grid_lines", text="Lines") sub.prop(view, "grid_scale", text="Scale") subsub = sub.column(align=True) subsub.active = scene.unit_settings.system == 'NONE' From fd4caafc53a1c2558f1a27eeaecffb130a146ff4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 21 Oct 2016 17:56:09 +0200 Subject: [PATCH 005/590] Fix T49789: Compositor mix node interpolation bug --- .../compositor/operations/COM_TextureOperation.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp index 665bffc2c1c..bba5c8702b8 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.cpp +++ b/source/blender/compositor/operations/COM_TextureOperation.cpp @@ -110,8 +110,18 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y int retval; const float cx = this->getWidth() / 2; const float cy = this->getHeight() / 2; - const float u = (x - cx) / this->getWidth() * 2; - const float v = (y - cy) / this->getHeight() * 2; + float u = (x - cx) / this->getWidth() * 2; + float v = (y - cy) / this->getHeight() * 2; + + /* When no interpolation/filtering happens in multitex() foce nearest interpolation. + * We do it here because (a) we can't easily say multitex() that we want nearest + * interpolaiton and (b) in such configuration multitex() sinply floor's the value + * which often produces artifacts. + */ + if ((m_texture->imaflag & TEX_INTERPOL) == 0) { + u += 0.5f / cx; + v += 0.5f / cy; + } this->m_inputSize->readSampled(textureSize, x, y, sampler); this->m_inputOffset->readSampled(textureOffset, x, y, sampler); From d5ee031f76137339e3af0fdadb706fbb8db4c961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20M=C3=BCller?= Date: Sat, 22 Oct 2016 13:38:41 +0200 Subject: [PATCH 006/590] Fix T49764: Audio strips crackle when animating the volume - Implemented linear interpolation for volume changes in the software mixer. - Using this in the software device. --- intern/audaspace/intern/AUD_Mixer.cpp | 15 +++++++++++++++ intern/audaspace/intern/AUD_Mixer.h | 2 ++ intern/audaspace/intern/AUD_SoftwareDevice.cpp | 10 ++++++---- intern/audaspace/intern/AUD_SoftwareDevice.h | 1 + 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/intern/audaspace/intern/AUD_Mixer.cpp b/intern/audaspace/intern/AUD_Mixer.cpp index 380affa6bd1..78dfaddd27a 100644 --- a/intern/audaspace/intern/AUD_Mixer.cpp +++ b/intern/audaspace/intern/AUD_Mixer.cpp @@ -95,6 +95,21 @@ void AUD_Mixer::mix(sample_t* buffer, int start, int length, float volume) out[i + start] += buffer[i] * volume; } +void AUD_Mixer::mix(sample_t* buffer, int start, int length, float volume_to, float volume_from) +{ + sample_t* out = m_buffer.getBuffer(); + + length = (std::min(m_length, length + start) - start); + + for(int i = 0; i < length; i++) + { + float volume = volume_from * (1.0f - i / float(length)) + volume_to * (i / float(length)); + + for(int c = 0; c < m_specs.channels; c++) + out[(i + start) * m_specs.channels + c] += buffer[i * m_specs.channels + c] * volume; + } +} + void AUD_Mixer::read(data_t* buffer, float volume) { sample_t* out = m_buffer.getBuffer(); diff --git a/intern/audaspace/intern/AUD_Mixer.h b/intern/audaspace/intern/AUD_Mixer.h index 3dd03b0a3fe..0735fee715b 100644 --- a/intern/audaspace/intern/AUD_Mixer.h +++ b/intern/audaspace/intern/AUD_Mixer.h @@ -95,6 +95,8 @@ public: */ void mix(sample_t* buffer, int start, int length, float volume); + void mix(sample_t* buffer, int start, int length, float volume_to, float volume_from); + /** * Writes the mixing buffer into an output buffer. * \param buffer The target buffer for superposing. diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.cpp b/intern/audaspace/intern/AUD_SoftwareDevice.cpp index c4277a6d02e..15594d340be 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.cpp +++ b/intern/audaspace/intern/AUD_SoftwareDevice.cpp @@ -89,7 +89,7 @@ bool AUD_SoftwareDevice::AUD_SoftwareHandle::pause(bool keep) } AUD_SoftwareDevice::AUD_SoftwareHandle::AUD_SoftwareHandle(AUD_SoftwareDevice* device, boost::shared_ptr reader, boost::shared_ptr pitch, boost::shared_ptr resampler, boost::shared_ptr mapper, bool keep) : - m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_loopcount(0), + m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_old_volume(1.0f), m_loopcount(0), m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits::max()), m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0), m_flags(AUD_RENDER_CONE), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING), m_device(device) @@ -100,6 +100,8 @@ void AUD_SoftwareDevice::AUD_SoftwareHandle::update() { int flags = 0; + m_old_volume = m_volume; + AUD_Vector3 SL; if(m_relative) SL = -m_location; @@ -404,7 +406,7 @@ bool AUD_SoftwareDevice::AUD_SoftwareHandle::setVolume(float volume) if(volume == 0) { - m_volume = volume; + m_old_volume = m_volume = volume; m_flags |= AUD_RENDER_VOLUME; } else @@ -772,7 +774,7 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length) // in case of looping while(pos + len < length && sound->m_loopcount && eos) { - m_mixer->mix(buf, pos, len, sound->m_volume); + m_mixer->mix(buf, pos, len, sound->m_volume, sound->m_old_volume); pos += len; @@ -789,7 +791,7 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length) break; } - m_mixer->mix(buf, pos, len, sound->m_volume); + m_mixer->mix(buf, pos, len, sound->m_volume, sound->m_old_volume); // in case the end of the sound is reached if(eos && !sound->m_loopcount) diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.h b/intern/audaspace/intern/AUD_SoftwareDevice.h index 3c8c1e438a3..54e49c87b27 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.h +++ b/intern/audaspace/intern/AUD_SoftwareDevice.h @@ -84,6 +84,7 @@ protected: /// The calculated final volume of the source. float m_volume; + float m_old_volume; /// The loop count of the source. int m_loopcount; From 132478d4b8bb5dc1554f7ca01ac337fe1978e5fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20M=C3=BCller?= Date: Sat, 22 Oct 2016 14:20:47 +0200 Subject: [PATCH 007/590] Fix T49657: Audio backend "Jack" should be named "JACK". --- CMakeLists.txt | 4 ++-- build_files/cmake/Modules/FindJack.cmake | 14 +++++++------- intern/audaspace/intern/AUD_C-API.cpp | 6 +++--- intern/audaspace/intern/AUD_C-API.h | 2 +- intern/audaspace/jack/AUD_JackDevice.h | 8 ++++---- intern/audaspace/jack/AUD_JackLibrary.h | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c7addc81b0c..f3c22d9b717 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -343,9 +343,9 @@ option(WITH_OPENCOLLADA "Enable OpenCollada Support (http://www.opencollada.or # Sound output option(WITH_SDL "Enable SDL for sound and joystick support" ${_init_SDL}) option(WITH_OPENAL "Enable OpenAL Support (http://www.openal.org)" ON) -option(WITH_JACK "Enable Jack Support (http://www.jackaudio.org)" ${_init_JACK}) +option(WITH_JACK "Enable JACK Support (http://www.jackaudio.org)" ${_init_JACK}) if(UNIX AND NOT APPLE) - option(WITH_JACK_DYNLOAD "Enable runtime dynamic Jack libraries loading" OFF) + option(WITH_JACK_DYNLOAD "Enable runtime dynamic JACK libraries loading" OFF) endif() if(UNIX AND NOT APPLE) option(WITH_SDL_DYNLOAD "Enable runtime dynamic SDL libraries loading" OFF) diff --git a/build_files/cmake/Modules/FindJack.cmake b/build_files/cmake/Modules/FindJack.cmake index 9a847fabf70..59aa7fcf60b 100644 --- a/build_files/cmake/Modules/FindJack.cmake +++ b/build_files/cmake/Modules/FindJack.cmake @@ -1,15 +1,15 @@ -# - Find Jack library -# Find the native Jack includes and library +# - Find JACK library +# Find the native JACK includes and library # This module defines # JACK_INCLUDE_DIRS, where to find jack.h, Set when # JACK_INCLUDE_DIR is found. -# JACK_LIBRARIES, libraries to link against to use Jack. -# JACK_ROOT_DIR, The base directory to search for Jack. +# JACK_LIBRARIES, libraries to link against to use JACK. +# JACK_ROOT_DIR, The base directory to search for JACK. # This can also be an environment variable. -# JACK_FOUND, If false, do not try to use Jack. +# JACK_FOUND, If false, do not try to use JACK. # # also defined, but not for general use are -# JACK_LIBRARY, where to find the Jack library. +# JACK_LIBRARY, where to find the JACK library. #============================================================================= # Copyright 2011 Blender Foundation. @@ -56,7 +56,7 @@ FIND_LIBRARY(JACK_LIBRARY # handle the QUIETLY and REQUIRED arguments and set JACK_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Jack DEFAULT_MSG +FIND_PACKAGE_HANDLE_STANDARD_ARGS(JACK DEFAULT_MSG JACK_LIBRARY JACK_INCLUDE_DIR) IF(JACK_FOUND) diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp index b326c9f4281..52cf256147f 100644 --- a/intern/audaspace/intern/AUD_C-API.cpp +++ b/intern/audaspace/intern/AUD_C-API.cpp @@ -155,18 +155,18 @@ AUD_Device* AUD_init(const char* device, AUD_DeviceSpecs specs, int buffersize, } #endif #ifdef WITH_JACK - else if(dname == "Jack") + else if(dname == "JACK") { #ifdef __APPLE__ struct stat st; if (stat("/Library/Frameworks/Jackmp.framework", &st) != 0) { - printf("Warning: Jack Framework not installed\n"); + printf("Warning: JACK Framework not installed\n"); return NULL; } else #endif if (!AUD_jack_supported()) { - printf("Warning: Jack cllient not installed\n"); + printf("Warning: JACK cllient not installed\n"); return NULL; } else { diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h index bdbe751b140..cc9059a8e09 100644 --- a/intern/audaspace/intern/AUD_C-API.h +++ b/intern/audaspace/intern/AUD_C-API.h @@ -61,7 +61,7 @@ typedef struct #endif /** - * Initializes audio rutines (FFMPEG/Jack if it is enabled). + * Initializes audio routines (FFMPEG/JACK if it is enabled). */ extern void AUD_initOnce(void); diff --git a/intern/audaspace/jack/AUD_JackDevice.h b/intern/audaspace/jack/AUD_JackDevice.h index a82a6bc5c38..ccf3bfd6341 100644 --- a/intern/audaspace/jack/AUD_JackDevice.h +++ b/intern/audaspace/jack/AUD_JackDevice.h @@ -41,7 +41,7 @@ typedef void (*AUD_syncFunction)(void*, int, float); /** - * This device plays back through Jack. + * This device plays back through JACK. */ class AUD_JackDevice : public AUD_SoftwareDevice { @@ -90,7 +90,7 @@ private: static int jack_sync(jack_transport_state_t state, jack_position_t* pos, void* data); /** - * Next Jack Transport state (-1 if not expected to change). + * Next JACK Transport state (-1 if not expected to change). */ jack_transport_state_t m_nextState; @@ -150,7 +150,7 @@ protected: public: /** - * Creates a Jack client for audio output. + * Creates a JACK client for audio output. * \param name The client name. * \param specs The wanted audio specification, where only the channel count * is important. @@ -160,7 +160,7 @@ public: AUD_JackDevice(std::string name, AUD_DeviceSpecs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE); /** - * Closes the Jack client. + * Closes the JACK client. */ virtual ~AUD_JackDevice(); diff --git a/intern/audaspace/jack/AUD_JackLibrary.h b/intern/audaspace/jack/AUD_JackLibrary.h index 2a737a1a4e2..d74d9ba8021 100644 --- a/intern/audaspace/jack/AUD_JackLibrary.h +++ b/intern/audaspace/jack/AUD_JackLibrary.h @@ -42,7 +42,7 @@ # define JACK_SYM extern #endif -/* All loadable Jack sumbols, prototypes from original jack.h */ +/* All loadable JACK sumbols, prototypes from original jack.h */ JACK_SYM jack_transport_state_t (*AUD_jack_transport_query) ( const jack_client_t *client, From b5d527ff6c7e01b73c14d8e01b7e33a697d30b12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20M=C3=BCller?= Date: Sat, 22 Oct 2016 15:00:32 +0200 Subject: [PATCH 008/590] Fix T49656: Crash when starting playback while using JACK audio with A/V sync When ED_screen_animation_play is called from wm_event_do_handlers,ScrArea *sa = CTX_wm_area(C); is NULL in ED_screen_animation_timer. Informing the audio system in CTX_data_main_set, that a new Main has been set. --- build_files/cmake/Modules/FindJack.cmake | 2 +- source/blender/blenkernel/intern/context.c | 2 ++ source/blender/editors/screen/screen_edit.c | 8 +++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/build_files/cmake/Modules/FindJack.cmake b/build_files/cmake/Modules/FindJack.cmake index 59aa7fcf60b..caafa3c34a1 100644 --- a/build_files/cmake/Modules/FindJack.cmake +++ b/build_files/cmake/Modules/FindJack.cmake @@ -56,7 +56,7 @@ FIND_LIBRARY(JACK_LIBRARY # handle the QUIETLY and REQUIRED arguments and set JACK_FOUND to TRUE if # all listed variables are TRUE INCLUDE(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(JACK DEFAULT_MSG +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Jack DEFAULT_MSG JACK_LIBRARY JACK_INCLUDE_DIR) IF(JACK_FOUND) diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 926ca8da192..4c01bfd35f2 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -49,6 +49,7 @@ #include "BKE_context.h" #include "BKE_main.h" #include "BKE_screen.h" +#include "BKE_sound.h" #include "RNA_access.h" @@ -882,6 +883,7 @@ Main *CTX_data_main(const bContext *C) void CTX_data_main_set(bContext *C, Main *bmain) { C->data.main = bmain; + BKE_sound_init_main(bmain); } Scene *CTX_data_scene(const bContext *C) diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 677a6472c72..5cd0d33c365 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -2076,7 +2076,13 @@ void ED_screen_animation_timer(bContext *C, int redraws, int refresh, int sync, sad->flag |= (sync == 0) ? ANIMPLAY_FLAG_NO_SYNC : (sync == 1) ? ANIMPLAY_FLAG_SYNC : 0; ScrArea *sa = CTX_wm_area(C); - sad->from_anim_edit = (ELEM(sa->spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME)); + + char spacetype = -1; + + if (sa) + spacetype = sa->spacetype; + + sad->from_anim_edit = (ELEM(spacetype, SPACE_IPO, SPACE_ACTION, SPACE_NLA, SPACE_TIME)); screen->animtimer->customdata = sad; From 9d0ac94d52268ff34ce645035d4315d6018d02b9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 22 Oct 2016 15:59:23 +0200 Subject: [PATCH 009/590] Fix T49750: Cycles wrong ray differentials for perspective and stereo cameras. --- intern/cycles/kernel/kernel_camera.h | 133 +++++++++++++++-------- intern/cycles/kernel/kernel_projection.h | 46 +++----- 2 files changed, 102 insertions(+), 77 deletions(-) diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h index ed9726e1b51..de3d70bc774 100644 --- a/intern/cycles/kernel/kernel_camera.h +++ b/intern/cycles/kernel/kernel_camera.h @@ -105,39 +105,61 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo } #endif - float3 tP = transform_point(&cameratoworld, ray->P); - float3 tD = transform_direction(&cameratoworld, ray->D); - ray->P = spherical_stereo_position(kg, tD, tP); - ray->D = spherical_stereo_direction(kg, tD, tP, ray->P); + ray->P = transform_point(&cameratoworld, ray->P); + ray->D = normalize(transform_direction(&cameratoworld, ray->D)); + + bool use_stereo = kernel_data.cam.interocular_offset != 0.0f; + if (!use_stereo) { + /* No stereo */ +#ifdef __RAY_DIFFERENTIALS__ + float3 Dcenter = transform_direction(&cameratoworld, Pcamera); + + ray->dP = differential3_zero(); + ray->dD.dx = normalize(Dcenter + float4_to_float3(kernel_data.cam.dx)) - normalize(Dcenter); + ray->dD.dy = normalize(Dcenter + float4_to_float3(kernel_data.cam.dy)) - normalize(Dcenter); +#endif + } + else { + /* Spherical stereo */ + spherical_stereo_transform(kg, &ray->P, &ray->D); #ifdef __RAY_DIFFERENTIALS__ - /* ray differential */ - ray->dP = differential3_zero(); + /* Ray differentials, computed from scratch using the raster coordinates + * because we don't want to be affected by depth of field. We compute + * ray origin and direction for the center and two neighbouring pixels + * and simply take their differences. */ + float3 Pnostereo = transform_point(&cameratoworld, make_float3(0.0f, 0.0f, 0.0f)); - float3 tD_diff = transform_direction(&cameratoworld, Pcamera); - float3 Pdiff = spherical_stereo_position(kg, tD_diff, Pcamera); - float3 Ddiff = spherical_stereo_direction(kg, tD_diff, Pcamera, Pdiff); + float3 Pcenter = Pnostereo; + float3 Dcenter = Pcamera; + Dcenter = normalize(transform_direction(&cameratoworld, Dcenter)); + spherical_stereo_transform(kg, &Pcenter, &Dcenter); - tP = transform_perspective(&rastertocamera, - make_float3(raster_x + 1.0f, raster_y, 0.0f)); - tD = tD_diff + float4_to_float3(kernel_data.cam.dx); - Pcamera = spherical_stereo_position(kg, tD, tP); - ray->dD.dx = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff; - ray->dP.dx = Pcamera - Pdiff; + float3 Px = Pnostereo; + float3 Dx = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); + Dx = normalize(transform_direction(&cameratoworld, Dx)); + spherical_stereo_transform(kg, &Px, &Dx); - tP = transform_perspective(&rastertocamera, - make_float3(raster_x, raster_y + 1.0f, 0.0f)); - tD = tD_diff + float4_to_float3(kernel_data.cam.dy); - Pcamera = spherical_stereo_position(kg, tD, tP); - ray->dD.dy = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff; - /* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */ + ray->dP.dx = Px - Pcenter; + ray->dD.dx = Dx - Dcenter; + + float3 Py = Pnostereo; + float3 Dy = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); + Dy = normalize(transform_direction(&cameratoworld, Dy)); + spherical_stereo_transform(kg, &Py, &Dy); + + ray->dP.dy = Py - Pcenter; + ray->dD.dy = Dy - Dcenter; #endif + } #ifdef __CAMERA_CLIPPING__ /* clipping */ - float3 Pclip = normalize(Pcamera); - float z_inv = 1.0f / Pclip.z; - ray->P += kernel_data.cam.nearclip*ray->D * z_inv; + float z_inv = 1.0f / normalize(Pcamera).z; + float nearclip = kernel_data.cam.nearclip * z_inv; + ray->P += nearclip * ray->D; + ray->dP.dx += nearclip * ray->dD.dx; + ray->dP.dy += nearclip * ray->dD.dy; ray->t = kernel_data.cam.cliplength * z_inv; #else ray->t = FLT_MAX; @@ -268,36 +290,57 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, } #endif - float3 tP = transform_point(&cameratoworld, ray->P); - float3 tD = transform_direction(&cameratoworld, ray->D); - ray->P = spherical_stereo_position(kg, tD, tP); - ray->D = spherical_stereo_direction(kg, tD, tP, ray->P); + ray->P = transform_point(&cameratoworld, ray->P); + ray->D = normalize(transform_direction(&cameratoworld, ray->D)); + + /* Stereo transform */ + bool use_stereo = kernel_data.cam.interocular_offset != 0.0f; + if (use_stereo) { + spherical_stereo_transform(kg, &ray->P, &ray->D); + } #ifdef __RAY_DIFFERENTIALS__ - /* ray differential */ - ray->dP = differential3_zero(); + /* Ray differentials, computed from scratch using the raster coordinates + * because we don't want to be affected by depth of field. We compute + * ray origin and direction for the center and two neighbouring pixels + * and simply take their differences. */ + float3 Pcenter = Pcamera; + float3 Dcenter = panorama_to_direction(kg, Pcenter.x, Pcenter.y); + Pcenter = transform_point(&cameratoworld, Pcenter); + Dcenter = normalize(transform_direction(&cameratoworld, Dcenter)); + if (use_stereo) { + spherical_stereo_transform(kg, &Pcenter, &Dcenter); + } - tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); - tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y)); - float3 Pdiff = spherical_stereo_position(kg, tD, tP); - float3 Ddiff = spherical_stereo_direction(kg, tD, tP, Pdiff); + float3 Px = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); + float3 Dx = panorama_to_direction(kg, Px.x, Px.y); + Px = transform_point(&cameratoworld, Px); + Dx = normalize(transform_direction(&cameratoworld, Dx)); + if (use_stereo) { + spherical_stereo_transform(kg, &Px, &Dx); + } - tP = transform_perspective(&rastertocamera, make_float3(raster_x + 1.0f, raster_y, 0.0f)); - tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y)); - Pcamera = spherical_stereo_position(kg, tD, tP); - ray->dD.dx = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff; - ray->dP.dx = Pcamera - Pdiff; + ray->dP.dx = Px - Pcenter; + ray->dD.dx = Dx - Dcenter; - tP = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); - tD = transform_direction(&cameratoworld, panorama_to_direction(kg, tP.x, tP.y)); - Pcamera = spherical_stereo_position(kg, tD, tP); - ray->dD.dy = spherical_stereo_direction(kg, tD, tP, Pcamera) - Ddiff; - /* dP.dy is zero, since the omnidirectional panorama only shift the eyes horizontally */ + float3 Py = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y + 1.0f, 0.0f)); + float3 Dy = panorama_to_direction(kg, Py.x, Py.y); + Py = transform_point(&cameratoworld, Py); + Dy = normalize(transform_direction(&cameratoworld, Dy)); + if (use_stereo) { + spherical_stereo_transform(kg, &Py, &Dy); + } + + ray->dP.dy = Py - Pcenter; + ray->dD.dy = Dy - Dcenter; #endif #ifdef __CAMERA_CLIPPING__ /* clipping */ - ray->P += kernel_data.cam.nearclip*ray->D; + float nearclip = kernel_data.cam.nearclip; + ray->P += nearclip * ray->D; + ray->dP.dx += nearclip * ray->dD.dx; + ray->dP.dy += nearclip * ray->dD.dy; ray->t = kernel_data.cam.cliplength; #else ray->t = FLT_MAX; diff --git a/intern/cycles/kernel/kernel_projection.h b/intern/cycles/kernel/kernel_projection.h index 3437d83ed7d..ba714b6c382 100644 --- a/intern/cycles/kernel/kernel_projection.h +++ b/intern/cycles/kernel/kernel_projection.h @@ -224,24 +224,18 @@ ccl_device_inline float2 direction_to_panorama(KernelGlobals *kg, float3 dir) } } -ccl_device_inline float3 spherical_stereo_position(KernelGlobals *kg, - float3 dir, - float3 pos) +ccl_device_inline void spherical_stereo_transform(KernelGlobals *kg, float3 *P, float3 *D) { float interocular_offset = kernel_data.cam.interocular_offset; /* Interocular offset of zero means either non stereo, or stereo without - * spherical stereo. - */ - if(interocular_offset == 0.0f) { - return pos; - } + * spherical stereo. */ + kernel_assert(interocular_offset != 0.0f); if(kernel_data.cam.pole_merge_angle_to > 0.0f) { - float3 normalized_direction = normalize(dir); const float pole_merge_angle_from = kernel_data.cam.pole_merge_angle_from, pole_merge_angle_to = kernel_data.cam.pole_merge_angle_to; - float altitude = fabsf(safe_asinf(normalized_direction.z)); + float altitude = fabsf(safe_asinf(D->z)); if(altitude > pole_merge_angle_to) { interocular_offset = 0.0f; } @@ -253,32 +247,20 @@ ccl_device_inline float3 spherical_stereo_position(KernelGlobals *kg, } float3 up = make_float3(0.0f, 0.0f, 1.0f); - float3 side = normalize(cross(dir, up)); + float3 side = normalize(cross(*D, up)); + float3 stereo_offset = side * interocular_offset; - return pos + (side * interocular_offset); -} + *P += stereo_offset; -/* NOTE: Ensures direction is normalized. */ -ccl_device float3 spherical_stereo_direction(KernelGlobals *kg, - float3 dir, - float3 pos, - float3 newpos) -{ + /* Convergence distance is FLT_MAX in the case of parallel convergence mode, + * no need to modify direction in this case either. */ const float convergence_distance = kernel_data.cam.convergence_distance; - const float3 normalized_dir = normalize(dir); - /* Interocular offset of zero means either no stereo, or stereo without - * spherical stereo. - * Convergence distance is FLT_MAX in the case of parallel convergence mode, - * no need to mdify direction in this case either. - */ - if(kernel_data.cam.interocular_offset == 0.0f || - convergence_distance == FLT_MAX) - { - return normalized_dir; - } - float3 screenpos = pos + (normalized_dir * convergence_distance); - return normalize(screenpos - newpos); + if(convergence_distance != FLT_MAX) + { + float3 screen_offset = convergence_distance * (*D); + *D = normalize(screen_offset - stereo_offset); + } } CCL_NAMESPACE_END From 5765deecd42eedda780b88ed7448e4b1c185d0d8 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Sat, 22 Oct 2016 16:44:11 +0200 Subject: [PATCH 010/590] GPencil: New option to lock strokes to axis Now, the strokes can be locked to a plane set in the cursor location. This option allow the artist to rotate the view and draw keeping the strokes flat over the surface. This option is similar to surface option but doesn't need a object. The option is only valid for 3D view and strokes in CURSOR mode. --- .../bl_ui/properties_grease_pencil_common.py | 6 + .../blender/editors/gpencil/gpencil_paint.c | 126 +++++++++++++++--- source/blender/makesdna/DNA_scene_types.h | 10 +- .../makesrna/intern/rna_sculpt_paint.c | 15 +++ 4 files changed, 134 insertions(+), 23 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 84442f9b2d9..bc40932018d 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -52,6 +52,12 @@ def gpencil_stroke_placement_settings(context, layout): row.active = getattr(ts, propname) in {'SURFACE', 'STROKE'} row.prop(ts, "use_gpencil_stroke_endpoints") + if context.scene.tool_settings.gpencil_stroke_placement_view3d == 'CURSOR': + row = col.row(align=True) + row.label("Lock axis:") + row = col.row(align=True) + row.prop(ts.gpencil_sculpt, "lockaxis", expand=True) + def gpencil_active_brush_settings_simple(context, layout): brush = context.active_gpencil_brush diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index cc45cbd82af..c23bfb1ff60 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -40,6 +40,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_rand.h" +#include "BLI_math_geom.h" #include "BLT_translation.h" @@ -160,6 +161,7 @@ typedef struct tGPsdata { bGPDpalettecolor *palettecolor; /* current palette color */ bGPDbrush *brush; /* current drawing brush */ short straight[2]; /* 1: line horizontal, 2: line vertical, other: not defined, second element position */ + int lock_axis; /* lock drawing to one axis */ } tGPsdata; /* ------ */ @@ -278,6 +280,64 @@ static bool gp_stroke_filtermval(tGPsdata *p, const int mval[2], int pmval[2]) return false; } +/* reproject the points of the stroke to a plane locked to axis to avoid stroke offset */ +static void gp_project_points_to_plane(RegionView3D *rv3d, bGPDstroke *gps, const float origin[3], const int axis) +{ + float plane_normal[3]; + float vn[3]; + + float ray[3]; + float rpoint[3]; + + /* normal vector for a plane locked to axis */ + zero_v3(plane_normal); + plane_normal[axis] = 1.0f; + + /* Reproject the points in the plane */ + for (int i = 0; i < gps->totpoints; i++) { + bGPDspoint *pt = &gps->points[i]; + + /* get a vector from the point with the current view direction of the viewport */ + ED_view3d_global_to_vector(rv3d, &pt->x, vn); + + /* calculate line extrem point to create a ray that cross the plane */ + mul_v3_fl(vn, -50.0f); + add_v3_v3v3(ray, &pt->x, vn); + + /* if the line never intersect, the point is not changed */ + if (isect_line_plane_v3(rpoint, &pt->x, ray, origin, plane_normal)) { + copy_v3_v3(&pt->x, rpoint); + } + } +} + +/* reproject stroke to plane locked to axis in 3d cursor location */ +static void gp_reproject_toplane(tGPsdata *p, bGPDstroke *gps) +{ + bGPdata *gpd = p->gpd; + float origin[3]; + float cursor[3]; + RegionView3D *rv3d = p->ar->regiondata; + + /* verify the stroke mode is CURSOR 3d space mode */ + if ((gpd->sbuffer_sflag & GP_STROKE_3DSPACE) == 0) { + return; + } + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) == 0) { + return; + } + if ((*p->align_flag & GP_PROJECT_DEPTH_VIEW) || (*p->align_flag & GP_PROJECT_DEPTH_STROKE)) { + return; + } + + /* get 3d cursor and set origin for locked axis only. Uses axis-1 because the enum for XYZ start with 1 */ + gp_get_3d_reference(p, cursor); + zero_v3(origin); + origin[p->lock_axis - 1] = cursor[p->lock_axis - 1]; + + gp_project_points_to_plane(rv3d, gps, origin, p->lock_axis - 1); +} + /* convert screen-coordinates to buffer-coordinates */ /* XXX this method needs a total overhaul! */ static void gp_stroke_convertcoords(tGPsdata *p, const int mval[2], float out[3], float *depth) @@ -581,6 +641,10 @@ static short gp_stroke_addpoint(tGPsdata *p, const int mval[2], float pressure, /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &pt->x, &pts->x, NULL); + /* if axis locked, reproject to plane locked (only in 3d space) */ + if (p->lock_axis > GP_LOCKAXIS_NONE) { + gp_reproject_toplane(p, gps); + } /* if parented change position relative to parent object */ if (gpl->parent != NULL) { gp_apply_parent_point(gpl, pts); @@ -679,7 +743,6 @@ static void gp_stroke_simplify(tGPsdata *p) MEM_freeN(old_points); } - /* make a new stroke from the buffer data */ static void gp_stroke_newfrombuffer(tGPsdata *p) { @@ -756,6 +819,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + /* if axis locked, reproject to plane locked (only in 3d space) */ + if (p->lock_axis > GP_LOCKAXIS_NONE) { + gp_reproject_toplane(p, gps); + } /* if parented change position relative to parent object */ if (gpl->parent != NULL) { gp_apply_parent_point(gpl, pt); @@ -775,6 +842,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + /* if axis locked, reproject to plane locked (only in 3d space) */ + if (p->lock_axis > GP_LOCKAXIS_NONE) { + gp_reproject_toplane(p, gps); + } /* if parented change position relative to parent object */ if (gpl->parent != NULL) { gp_apply_parent_point(gpl, pt); @@ -793,6 +864,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + /* if axis locked, reproject to plane locked (only in 3d space) */ + if (p->lock_axis > GP_LOCKAXIS_NONE) { + gp_reproject_toplane(p, gps); + } /* if parented change position relative to parent object */ if (gpl->parent != NULL) { gp_apply_parent_point(gpl, pt); @@ -805,30 +880,30 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) } else { float *depth_arr = NULL; - + /* get an array of depths, far depths are blended */ if (gpencil_project_check(p)) { - int mval[2], mval_prev[2] = {0}; + int mval[2], mval_prev[2] = { 0 }; int interp_depth = 0; int found_depth = 0; - + depth_arr = MEM_mallocN(sizeof(float) * gpd->sbuffer_size, "depth_points"); - + for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size; i++, ptc++, pt++) { copy_v2_v2_int(mval, &ptc->x); - + if ((ED_view3d_autodist_depth(p->ar, mval, depth_margin, depth_arr + i) == 0) && - (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0))) + (i && (ED_view3d_autodist_depth_seg(p->ar, mval, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { interp_depth = true; } else { found_depth = true; } - + copy_v2_v2_int(mval_prev, mval); } - + if (found_depth == false) { /* eeh... not much we can do.. :/, ignore depth in this case, use the 3D cursor */ for (i = gpd->sbuffer_size - 1; i >= 0; i--) @@ -839,54 +914,54 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) /* remove all info between the valid endpoints */ int first_valid = 0; int last_valid = 0; - + for (i = 0; i < gpd->sbuffer_size; i++) { if (depth_arr[i] != FLT_MAX) break; } first_valid = i; - + for (i = gpd->sbuffer_size - 1; i >= 0; i--) { if (depth_arr[i] != FLT_MAX) break; } last_valid = i; - + /* invalidate non-endpoints, so only blend between first and last */ for (i = first_valid + 1; i < last_valid; i++) depth_arr[i] = FLT_MAX; - + interp_depth = true; } - + if (interp_depth) { interp_sparse_array(depth_arr, gpd->sbuffer_size, FLT_MAX); } } } - - + + pt = gps->points; - + /* convert all points (normal behavior) */ for (i = 0, ptc = gpd->sbuffer; i < gpd->sbuffer_size && ptc; i++, ptc++, pt++) { /* convert screen-coordinates to appropriate coordinates (and store them) */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); - + /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; } - + /* subdivide the stroke */ if (sublevel > 0) { int totpoints = gps->totpoints; for (i = 0; i < sublevel; i++) { /* we're adding one new point between each pair of verts on each step */ totpoints += totpoints - 1; - + gp_subdivide_stroke(gps, totpoints); } } @@ -895,8 +970,8 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) gp_randomize_stroke(gps, brush); } - /* smooth stroke after subdiv - only if there's something to do - * for each iteration, the factor is reduced to get a better smoothing without changing too much + /* smooth stroke after subdiv - only if there's something to do + * for each iteration, the factor is reduced to get a better smoothing without changing too much * the original stroke */ if (brush->draw_smoothfac > 0.0f) { @@ -909,6 +984,11 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) reduce += 0.25f; // reduce the factor } } + + /* if axis locked, reproject to plane locked (only in 3d space) */ + if (p->lock_axis > GP_LOCKAXIS_NONE) { + gp_reproject_toplane(p, gps); + } /* if parented change position relative to parent object */ if (gpl->parent != NULL) { gp_apply_parent(gpl, gps); @@ -1467,6 +1547,8 @@ static bool gp_session_initdata(bContext *C, tGPsdata *p) bGPdata *pdata = p->gpd; copy_v4_v4(pdata->scolor, palcolor->color); pdata->sflag = palcolor->flag; + /* lock axis */ + p->lock_axis = ts->gp_sculpt.lock_axis; return 1; } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 94f23197293..9b0781ebe70 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1160,6 +1160,14 @@ typedef enum eGP_EditBrush_Types { TOT_GP_EDITBRUSH_TYPES } eGP_EditBrush_Types; +/* Lock axis options */ +typedef enum eGP_Lockaxis_Types { + GP_LOCKAXIS_NONE = 0, + GP_LOCKAXIS_X = 1, + GP_LOCKAXIS_Y = 2, + GP_LOCKAXIS_Z = 3 +} eGP_Lockaxis_Types; + /* Settings for a GPencil Stroke Sculpting Brush */ typedef struct GP_EditBrush_Data { short size; /* radius of brush */ @@ -1190,7 +1198,7 @@ typedef struct GP_BrushEdit_Settings { int brushtype; /* eGP_EditBrush_Types */ int flag; /* eGP_BrushEdit_SettingsFlag */ - char pad[4]; + int lock_axis; /* lock drawing to one axis */ float alpha; /* alpha factor for selection color */ } GP_BrushEdit_Settings; diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 7e1d0164eb4..e169ef0d822 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -75,6 +75,14 @@ EnumPropertyItem rna_enum_gpencil_sculpt_brush_items[] = { { 0, NULL, 0, NULL, NULL } }; +EnumPropertyItem rna_enum_gpencil_lockaxis_items[] = { + { GP_LOCKAXIS_NONE, "GP_LOCKAXIS_NONE", 0, "None", "" }, + { GP_LOCKAXIS_X, "GP_LOCKAXIS_X", 0, "X", "Project strokes to plane locked to X" }, + { GP_LOCKAXIS_Y, "GP_LOCKAXIS_Y", 0, "Y", "Project strokes to plane locked to Y" }, + { GP_LOCKAXIS_Z, "GP_LOCKAXIS_Z", 0, "Z", "Project strokes to plane locked to Z" }, + { 0, NULL, 0, NULL, NULL } +}; + EnumPropertyItem rna_enum_symmetrize_direction_items[] = { {BMO_SYMMETRIZE_NEGATIVE_X, "NEGATIVE_X", 0, "-X to +X", ""}, {BMO_SYMMETRIZE_POSITIVE_X, "POSITIVE_X", 0, "+X to -X", ""}, @@ -1053,6 +1061,13 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Alpha", "Alpha value for selected vertices"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_GPencil_update"); + /* lock axis */ + prop = RNA_def_property(srna, "lockaxis", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "lock_axis"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_lockaxis_items); + RNA_def_property_ui_text(prop, "Lock", ""); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + /* brush */ srna = RNA_def_struct(brna, "GPencilSculptBrush", NULL); RNA_def_struct_sdna(srna, "GP_EditBrush_Data"); From 371d3570e0a5fd04c2181a286034841919eabd34 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 22 Oct 2016 23:25:39 +0200 Subject: [PATCH 011/590] Fix Cycles address space OpenCL error after recent fix. --- intern/cycles/kernel/kernel_camera.h | 60 ++++++++++++++++------------ 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h index de3d70bc774..0888466f5ff 100644 --- a/intern/cycles/kernel/kernel_camera.h +++ b/intern/cycles/kernel/kernel_camera.h @@ -68,8 +68,8 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo } #endif - ray->P = make_float3(0.0f, 0.0f, 0.0f); - ray->D = Pcamera; + float3 P = make_float3(0.0f, 0.0f, 0.0f); + float3 D = Pcamera; /* modify ray for depth of field */ float aperturesize = kernel_data.cam.aperturesize; @@ -79,12 +79,12 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo float2 lensuv = camera_sample_aperture(kg, lens_u, lens_v)*aperturesize; /* compute point on plane of focus */ - float ft = kernel_data.cam.focaldistance/ray->D.z; - float3 Pfocus = ray->D*ft; + float ft = kernel_data.cam.focaldistance/D.z; + float3 Pfocus = D*ft; /* update ray for effect of lens */ - ray->P = make_float3(lensuv.x, lensuv.y, 0.0f); - ray->D = normalize(Pfocus - ray->P); + P = make_float3(lensuv.x, lensuv.y, 0.0f); + D = normalize(Pfocus - P); } /* transform ray from camera to world */ @@ -105,12 +105,15 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo } #endif - ray->P = transform_point(&cameratoworld, ray->P); - ray->D = normalize(transform_direction(&cameratoworld, ray->D)); + P = transform_point(&cameratoworld, P); + D = normalize(transform_direction(&cameratoworld, D)); bool use_stereo = kernel_data.cam.interocular_offset != 0.0f; if (!use_stereo) { /* No stereo */ + ray->P = P; + ray->D = D; + #ifdef __RAY_DIFFERENTIALS__ float3 Dcenter = transform_direction(&cameratoworld, Pcamera); @@ -121,7 +124,9 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo } else { /* Spherical stereo */ - spherical_stereo_transform(kg, &ray->P, &ray->D); + spherical_stereo_transform(kg, &P, &D); + ray->P = P; + ray->D = D; #ifdef __RAY_DIFFERENTIALS__ /* Ray differentials, computed from scratch using the raster coordinates @@ -173,7 +178,8 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl Transform rastertocamera = kernel_data.cam.rastertocamera; float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); - ray->D = make_float3(0.0f, 0.0f, 1.0f); + float3 P; + float3 D = make_float3(0.0f, 0.0f, 1.0f); /* modify ray for depth of field */ float aperturesize = kernel_data.cam.aperturesize; @@ -183,15 +189,15 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl float2 lensuv = camera_sample_aperture(kg, lens_u, lens_v)*aperturesize; /* compute point on plane of focus */ - float3 Pfocus = ray->D * kernel_data.cam.focaldistance; + float3 Pfocus = D * kernel_data.cam.focaldistance; /* update ray for effect of lens */ float3 lensuvw = make_float3(lensuv.x, lensuv.y, 0.0f); - ray->P = Pcamera + lensuvw; - ray->D = normalize(Pfocus - lensuvw); + P = Pcamera + lensuvw; + D = normalize(Pfocus - lensuvw); } else { - ray->P = Pcamera; + P = Pcamera; } /* transform ray from camera to world */ Transform cameratoworld = kernel_data.cam.cameratoworld; @@ -211,9 +217,8 @@ ccl_device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, fl } #endif - ray->P = transform_point(&cameratoworld, ray->P); - ray->D = transform_direction(&cameratoworld, ray->D); - ray->D = normalize(ray->D); + ray->P = transform_point(&cameratoworld, P); + ray->D = normalize(transform_direction(&cameratoworld, D)); #ifdef __RAY_DIFFERENTIALS__ /* ray differential */ @@ -242,11 +247,11 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, float3 Pcamera = transform_perspective(&rastertocamera, make_float3(raster_x, raster_y, 0.0f)); /* create ray form raster position */ - ray->P = make_float3(0.0f, 0.0f, 0.0f); - ray->D = panorama_to_direction(kg, Pcamera.x, Pcamera.y); + float3 P = make_float3(0.0f, 0.0f, 0.0f); + float3 D = panorama_to_direction(kg, Pcamera.x, Pcamera.y); /* indicates ray should not receive any light, outside of the lens */ - if(is_zero(ray->D)) { + if(is_zero(D)) { ray->t = 0.0f; return; } @@ -259,7 +264,7 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, float2 lensuv = camera_sample_aperture(kg, lens_u, lens_v)*aperturesize; /* compute point on plane of focus */ - float3 D = normalize(ray->D); + float3 D = normalize(D); float3 Pfocus = D * kernel_data.cam.focaldistance; /* calculate orthonormal coordinates perpendicular to D */ @@ -268,8 +273,8 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, V = normalize(cross(D, U)); /* update ray for effect of lens */ - ray->P = U * lensuv.x + V * lensuv.y; - ray->D = normalize(Pfocus - ray->P); + P = U * lensuv.x + V * lensuv.y; + D = normalize(Pfocus - P); } /* transform ray from camera to world */ @@ -290,15 +295,18 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, } #endif - ray->P = transform_point(&cameratoworld, ray->P); - ray->D = normalize(transform_direction(&cameratoworld, ray->D)); + P = transform_point(&cameratoworld, P); + D = normalize(transform_direction(&cameratoworld, D)); /* Stereo transform */ bool use_stereo = kernel_data.cam.interocular_offset != 0.0f; if (use_stereo) { - spherical_stereo_transform(kg, &ray->P, &ray->D); + spherical_stereo_transform(kg, &P, &D); } + ray->P = P; + ray->D = D; + #ifdef __RAY_DIFFERENTIALS__ /* Ray differentials, computed from scratch using the raster coordinates * because we don't want to be affected by depth of field. We compute From 8905c5c87495ad8fd876de83a968d79ac54f0e17 Mon Sep 17 00:00:00 2001 From: Hristo Gueorguiev <> Date: Sat, 22 Oct 2016 23:38:42 +0200 Subject: [PATCH 012/590] Cycles: OpenCL 3d textures support. Note that volume rendering is not supported yet, this is a step towards that. Reviewed By: brecht Differential Revision: https://developer.blender.org/D2299 --- intern/cycles/kernel/CMakeLists.txt | 1 + intern/cycles/kernel/geom/geom_volume.h | 16 +- intern/cycles/kernel/kernel_image_opencl.h | 227 ++++++++++++++++++ intern/cycles/kernel/kernels/opencl/kernel.cl | 1 + .../cycles/kernel/split/kernel_split_common.h | 1 + intern/cycles/kernel/svm/svm_image.h | 145 +---------- intern/cycles/kernel/svm/svm_voxel.h | 8 +- intern/cycles/render/image.cpp | 20 +- 8 files changed, 262 insertions(+), 157 deletions(-) create mode 100644 intern/cycles/kernel/kernel_image_opencl.h diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index e4341c8aca1..694f19a808a 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -57,6 +57,7 @@ set(SRC_HEADERS kernel_emission.h kernel_film.h kernel_globals.h + kernel_image_opencl.h kernel_jitter.h kernel_light.h kernel_math.h diff --git a/intern/cycles/kernel/geom/geom_volume.h b/intern/cycles/kernel/geom/geom_volume.h index fd97a63efb5..03724c955be 100644 --- a/intern/cycles/kernel/geom/geom_volume.h +++ b/intern/cycles/kernel/geom/geom_volume.h @@ -29,7 +29,7 @@ CCL_NAMESPACE_BEGIN /* Return position normalized to 0..1 in mesh bounds */ -#if defined(__KERNEL_GPU__) && __CUDA_ARCH__ < 300 +#if defined(__KERNEL_CUDA__) && __CUDA_ARCH__ < 300 ccl_device float4 volume_image_texture_3d(int id, float x, float y, float z) { float4 r; @@ -42,7 +42,7 @@ ccl_device float4 volume_image_texture_3d(int id, float x, float y, float z) } return r; } -#endif /* __KERNEL_GPU__ */ +#endif /* __KERNEL_CUDA__ */ ccl_device_inline float3 volume_normalized_position(KernelGlobals *kg, const ShaderData *sd, @@ -64,8 +64,8 @@ ccl_device_inline float3 volume_normalized_position(KernelGlobals *kg, ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy) { - float3 P = volume_normalized_position(kg, sd, sd->P); -#ifdef __KERNEL_GPU__ + float3 P = volume_normalized_position(kg, sd, ccl_fetch(sd, P)); +#ifdef __KERNEL_CUDA__ # if __CUDA_ARCH__ >= 300 CUtexObject tex = kernel_tex_fetch(__bindless_mapping, desc.offset); float f = kernel_tex_image_interp_3d_float(tex, P.x, P.y, P.z); @@ -73,6 +73,8 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, # else float4 r = volume_image_texture_3d(desc.offset, P.x, P.y, P.z); # endif +#elif defined(__KERNEL_OPENCL__) + float4 r = kernel_tex_image_interp_3d(kg, desc.offset, P.x, P.y, P.z); #else float4 r; if(sd->flag & SD_VOLUME_CUBIC) @@ -89,14 +91,16 @@ ccl_device float volume_attribute_float(KernelGlobals *kg, const ShaderData *sd, ccl_device float3 volume_attribute_float3(KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy) { - float3 P = volume_normalized_position(kg, sd, sd->P); -#ifdef __KERNEL_GPU__ + float3 P = volume_normalized_position(kg, sd, ccl_fetch(sd, P)); +#ifdef __KERNEL_CUDA__ # if __CUDA_ARCH__ >= 300 CUtexObject tex = kernel_tex_fetch(__bindless_mapping, desc.offset); float4 r = kernel_tex_image_interp_3d_float4(tex, P.x, P.y, P.z); # else float4 r = volume_image_texture_3d(desc.offset, P.x, P.y, P.z); # endif +#elif defined(__KERNEL_OPENCL__) + float4 r = kernel_tex_image_interp_3d(kg, desc.offset, P.x, P.y, P.z); #else float4 r; if(sd->flag & SD_VOLUME_CUBIC) diff --git a/intern/cycles/kernel/kernel_image_opencl.h b/intern/cycles/kernel/kernel_image_opencl.h new file mode 100644 index 00000000000..f6c31b28f2c --- /dev/null +++ b/intern/cycles/kernel/kernel_image_opencl.h @@ -0,0 +1,227 @@ +/* + * Copyright 2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/* For OpenCL all images are packed in a single array, and we do manual lookup + * and interpolation. */ + +ccl_device_inline float4 svm_image_texture_read(KernelGlobals *kg, int id, int offset) +{ + /* Float4 */ + if(id < TEX_START_BYTE4_OPENCL) { + return kernel_tex_fetch(__tex_image_float4_packed, offset); + } + /* Byte4 */ + else if(id < TEX_START_FLOAT_OPENCL) { + uchar4 r = kernel_tex_fetch(__tex_image_byte4_packed, offset); + float f = 1.0f/255.0f; + return make_float4(r.x*f, r.y*f, r.z*f, r.w*f); + } + /* Float */ + else if(id < TEX_START_BYTE_OPENCL) { + float f = kernel_tex_fetch(__tex_image_float_packed, offset); + return make_float4(f, f, f, 1.0f); + } + /* Byte */ + else { + uchar r = kernel_tex_fetch(__tex_image_byte_packed, offset); + float f = r * (1.0f/255.0f); + return make_float4(f, f, f, 1.0f); + } +} + +ccl_device_inline int svm_image_texture_wrap_periodic(int x, int width) +{ + x %= width; + if(x < 0) + x += width; + return x; +} + +ccl_device_inline int svm_image_texture_wrap_clamp(int x, int width) +{ + return clamp(x, 0, width-1); +} + +ccl_device_inline float svm_image_texture_frac(float x, int *ix) +{ + int i = float_to_int(x) - ((x < 0.0f)? 1: 0); + *ix = i; + return x - (float)i; +} + +ccl_device float4 kernel_tex_image_interp(KernelGlobals *kg, int id, float x, float y) +{ + uint4 info = kernel_tex_fetch(__tex_image_packed_info, id*2); + uint width = info.x; + uint height = info.y; + uint offset = info.z; + + /* Image Options */ + uint interpolation = (info.w & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR; + uint extension; + if(info.w & (1 << 1)) + extension = EXTENSION_REPEAT; + else if(info.w & (1 << 2)) + extension = EXTENSION_EXTEND; + else + extension = EXTENSION_CLIP; + + float4 r; + int ix, iy, nix, niy; + if(interpolation == INTERPOLATION_CLOSEST) { + svm_image_texture_frac(x*width, &ix); + svm_image_texture_frac(y*height, &iy); + + if(extension == EXTENSION_REPEAT) { + ix = svm_image_texture_wrap_periodic(ix, width); + iy = svm_image_texture_wrap_periodic(iy, height); + } + else { + if(extension == EXTENSION_CLIP) { + if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) { + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + } + /* Fall through. */ + /* EXTENSION_EXTEND */ + ix = svm_image_texture_wrap_clamp(ix, width); + iy = svm_image_texture_wrap_clamp(iy, height); + } + + r = svm_image_texture_read(kg, id, offset + ix + iy*width); + } + else { /* INTERPOLATION_LINEAR */ + float tx = svm_image_texture_frac(x*width - 0.5f, &ix); + float ty = svm_image_texture_frac(y*height - 0.5f, &iy); + + if(extension == EXTENSION_REPEAT) { + ix = svm_image_texture_wrap_periodic(ix, width); + iy = svm_image_texture_wrap_periodic(iy, height); + + nix = svm_image_texture_wrap_periodic(ix+1, width); + niy = svm_image_texture_wrap_periodic(iy+1, height); + } + else { + if(extension == EXTENSION_CLIP) { + if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) { + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + } + nix = svm_image_texture_wrap_clamp(ix+1, width); + niy = svm_image_texture_wrap_clamp(iy+1, height); + ix = svm_image_texture_wrap_clamp(ix, width); + iy = svm_image_texture_wrap_clamp(iy, height); + } + + r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width); + r += (1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width); + r += ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width); + r += ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width); + } + + return r; +} + + +ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x, float y, float z) +{ + uint4 info = kernel_tex_fetch(__tex_image_packed_info, id*2); + uint width = info.x; + uint height = info.y; + uint offset = info.z; + uint depth = kernel_tex_fetch(__tex_image_packed_info, id*2+1).x; + + /* Image Options */ + uint interpolation = (info.w & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR; + uint extension; + if(info.w & (1 << 1)) + extension = EXTENSION_REPEAT; + else if(info.w & (1 << 2)) + extension = EXTENSION_EXTEND; + else + extension = EXTENSION_CLIP; + + float4 r; + int ix, iy, iz, nix, niy, niz; + if(interpolation == INTERPOLATION_CLOSEST) { + svm_image_texture_frac(x*width, &ix); + svm_image_texture_frac(y*height, &iy); + svm_image_texture_frac(z*depth, &iz); + + if (extension == EXTENSION_REPEAT) { + ix = svm_image_texture_wrap_periodic(ix, width); + iy = svm_image_texture_wrap_periodic(iy, height); + iz = svm_image_texture_wrap_periodic(iz, depth); + } + else { + if (extension == EXTENSION_CLIP) { + if(x < 0.0f || y < 0.0f || z < 0.0f || + x > 1.0f || y > 1.0f || z > 1.0f) + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + /* Fall through. */ + /* EXTENSION_EXTEND */ + ix = svm_image_texture_wrap_clamp(ix, width); + iy = svm_image_texture_wrap_clamp(iy, height); + iz = svm_image_texture_wrap_clamp(iz, depth); + } + r = svm_image_texture_read(kg, id, offset + ix + iy*width + iz*width*height); + } + else { /* INTERPOLATION_LINEAR */ + float tx = svm_image_texture_frac(x*(float)width - 0.5f, &ix); + float ty = svm_image_texture_frac(y*(float)height - 0.5f, &iy); + float tz = svm_image_texture_frac(z*(float)depth - 0.5f, &iz); + + if(extension == EXTENSION_REPEAT) { + ix = svm_image_texture_wrap_periodic(ix, width); + iy = svm_image_texture_wrap_periodic(iy, height); + iz = svm_image_texture_wrap_periodic(iz, depth); + + nix = svm_image_texture_wrap_periodic(ix+1, width); + niy = svm_image_texture_wrap_periodic(iy+1, height); + niz = svm_image_texture_wrap_periodic(iz+1, depth); + } + else { + if (extension == EXTENSION_CLIP) + if(x < 0.0f || y < 0.0f || z < 0.0f || + x > 1.0f || y > 1.0f || z > 1.0f) + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + /* Fall through. */ + /* EXTENSION_EXTEND */ + nix = svm_image_texture_wrap_clamp(ix+1, width); + niy = svm_image_texture_wrap_clamp(iy+1, height); + niz = svm_image_texture_wrap_clamp(iz+1, depth); + + ix = svm_image_texture_wrap_clamp(ix, width); + iy = svm_image_texture_wrap_clamp(iy, height); + iz = svm_image_texture_wrap_clamp(iz, depth); + } + + r = (1.0f - tz)*(1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width + iz*width*height); + r += (1.0f - tz)*(1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width + iz*width*height); + r += (1.0f - tz)*ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width + iz*width*height); + r += (1.0f - tz)*ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width + iz*width*height); + + r += tz*(1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width + niz*width*height); + r += tz*(1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width + niz*width*height); + r += tz*ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width + niz*width*height); + r += tz*ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width + niz*width*height); + + } + + return r; +} diff --git a/intern/cycles/kernel/kernels/opencl/kernel.cl b/intern/cycles/kernel/kernels/opencl/kernel.cl index 37907cd8fdc..a68f97857b6 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel.cl @@ -20,6 +20,7 @@ #include "../../kernel_math.h" #include "../../kernel_types.h" #include "../../kernel_globals.h" +#include "../../kernel_image_opencl.h" #include "../../kernel_film.h" diff --git a/intern/cycles/kernel/split/kernel_split_common.h b/intern/cycles/kernel/split/kernel_split_common.h index 88d6dab04d0..2135ee22b2e 100644 --- a/intern/cycles/kernel/split/kernel_split_common.h +++ b/intern/cycles/kernel/split/kernel_split_common.h @@ -21,6 +21,7 @@ #include "kernel_math.h" #include "kernel_types.h" #include "kernel_globals.h" +#include "kernel_image_opencl.h" #include "util_atomic.h" diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 378ce650129..9606064492e 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -29,147 +29,6 @@ CCL_NAMESPACE_BEGIN # define TEX_NUM_FLOAT4_IMAGES TEX_NUM_FLOAT4_OPENCL #endif -#ifdef __KERNEL_OPENCL__ - -/* For OpenCL all images are packed in a single array, and we do manual lookup - * and interpolation. */ - -ccl_device_inline float4 svm_image_texture_read(KernelGlobals *kg, int id, int offset) -{ - /* Float4 */ - if(id < TEX_START_BYTE4_OPENCL) { - return kernel_tex_fetch(__tex_image_float4_packed, offset); - } - /* Byte4 */ - else if(id < TEX_START_FLOAT_OPENCL) { - uchar4 r = kernel_tex_fetch(__tex_image_byte4_packed, offset); - float f = 1.0f/255.0f; - return make_float4(r.x*f, r.y*f, r.z*f, r.w*f); - } - /* Float */ - else if(id < TEX_START_BYTE_OPENCL) { - float f = kernel_tex_fetch(__tex_image_float_packed, offset); - return make_float4(f, f, f, 1.0f); - } - /* Byte */ - else { - uchar r = kernel_tex_fetch(__tex_image_byte_packed, offset); - float f = r * (1.0f/255.0f); - return make_float4(f, f, f, 1.0f); - } -} - -ccl_device_inline int svm_image_texture_wrap_periodic(int x, int width) -{ - x %= width; - if(x < 0) - x += width; - return x; -} - -ccl_device_inline int svm_image_texture_wrap_clamp(int x, int width) -{ - return clamp(x, 0, width-1); -} - -ccl_device_inline float svm_image_texture_frac(float x, int *ix) -{ - int i = float_to_int(x) - ((x < 0.0f)? 1: 0); - *ix = i; - return x - (float)i; -} - -ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint use_alpha) -{ - uint4 info = kernel_tex_fetch(__tex_image_packed_info, id); - uint width = info.x; - uint height = info.y; - uint offset = info.z; - - /* Image Options */ - uint interpolation = (info.w & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR; - uint extension; - if(info.w & (1 << 1)) - extension = EXTENSION_REPEAT; - else if(info.w & (1 << 2)) - extension = EXTENSION_EXTEND; - else - extension = EXTENSION_CLIP; - - float4 r; - int ix, iy, nix, niy; - if(interpolation == INTERPOLATION_CLOSEST) { - svm_image_texture_frac(x*width, &ix); - svm_image_texture_frac(y*height, &iy); - - if(extension == EXTENSION_REPEAT) { - ix = svm_image_texture_wrap_periodic(ix, width); - iy = svm_image_texture_wrap_periodic(iy, height); - } - else if(extension == EXTENSION_CLIP) { - if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - else { /* EXTENSION_EXTEND */ - ix = svm_image_texture_wrap_clamp(ix, width); - iy = svm_image_texture_wrap_clamp(iy, height); - } - - r = svm_image_texture_read(kg, id, offset + ix + iy*width); - } - else { /* INTERPOLATION_LINEAR */ - float tx = svm_image_texture_frac(x*width - 0.5f, &ix); - float ty = svm_image_texture_frac(y*height - 0.5f, &iy); - - if(extension == EXTENSION_REPEAT) { - ix = svm_image_texture_wrap_periodic(ix, width); - iy = svm_image_texture_wrap_periodic(iy, height); - - nix = svm_image_texture_wrap_periodic(ix+1, width); - niy = svm_image_texture_wrap_periodic(iy+1, height); - } - else { - if(extension == EXTENSION_CLIP) { - if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) { - return make_float4(0.0f, 0.0f, 0.0f, 0.0f); - } - } - nix = svm_image_texture_wrap_clamp(ix+1, width); - niy = svm_image_texture_wrap_clamp(iy+1, height); - ix = svm_image_texture_wrap_clamp(ix, width); - iy = svm_image_texture_wrap_clamp(iy, height); - } - - r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width); - r += (1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width); - r += ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width); - r += ty*tx*svm_image_texture_read(kg, id, offset + nix + niy*width); - } - - if(use_alpha && r.w != 1.0f && r.w != 0.0f) { - float invw = 1.0f/r.w; - r.x *= invw; - r.y *= invw; - r.z *= invw; - - if(id >= TEX_NUM_FLOAT4_IMAGES) { - r.x = min(r.x, 1.0f); - r.y = min(r.y, 1.0f); - r.z = min(r.z, 1.0f); - } - } - - if(srgb) { - r.x = color_srgb_to_scene_linear(r.x); - r.y = color_srgb_to_scene_linear(r.y); - r.z = color_srgb_to_scene_linear(r.z); - } - - return r; -} - -#else - ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint srgb, uint use_alpha) { #ifdef __KERNEL_CPU__ @@ -180,6 +39,8 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, # else float4 r = kernel_tex_image_interp(id, x, y); # endif +#elif defined(__KERNEL_OPENCL__) + float4 r = kernel_tex_image_interp(kg, id, x, y); #else float4 r; @@ -339,8 +200,6 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, return r; } -#endif - /* Remap coordnate from 0..1 box to -1..-1 */ ccl_device_inline float3 texco_remap_square(float3 co) { diff --git a/intern/cycles/kernel/svm/svm_voxel.h b/intern/cycles/kernel/svm/svm_voxel.h index f54f4e8e888..a8b3604a8a7 100644 --- a/intern/cycles/kernel/svm/svm_voxel.h +++ b/intern/cycles/kernel/svm/svm_voxel.h @@ -43,7 +43,7 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg, co = transform_point(&tfm, co); } float4 r; -# if defined(__KERNEL_GPU__) +# if defined(__KERNEL_CUDA__) # if __CUDA_ARCH__ >= 300 CUtexObject tex = kernel_tex_fetch(__bindless_mapping, id); if(id < 2048) /* TODO(dingto): Make this a variable */ @@ -55,9 +55,11 @@ ccl_device void svm_node_tex_voxel(KernelGlobals *kg, # else /* __CUDA_ARCH__ >= 300 */ r = volume_image_texture_3d(id, co.x, co.y, co.z); # endif -# else /* __KERNEL_GPU__ */ +# elif defined(__KERNEL_OPENCL__) + r = kernel_tex_image_interp_3d(kg, id, co.x, co.y, co.z); +# else r = kernel_tex_image_interp_3d(id, co.x, co.y, co.z); -# endif +# endif /* __KERNEL_CUDA__ */ #else float4 r = make_float4(0.0f, 0.0f, 0.0f, 0.0f); #endif diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 7e24664b3fe..3cb0aa961ec 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -1107,7 +1107,7 @@ void ImageManager::device_pack_images(Device *device, int info_size = tex_num_images[IMAGE_DATA_TYPE_FLOAT4] + tex_num_images[IMAGE_DATA_TYPE_BYTE4] + tex_num_images[IMAGE_DATA_TYPE_FLOAT] + tex_num_images[IMAGE_DATA_TYPE_BYTE]; - uint4 *info = dscene->tex_image_packed_info.resize(info_size); + uint4 *info = dscene->tex_image_packed_info.resize(info_size*2); /* Byte4 Textures*/ type = IMAGE_DATA_TYPE_BYTE4; @@ -1130,7 +1130,9 @@ void ImageManager::device_pack_images(Device *device, uint8_t options = pack_image_options(type, slot); - info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); + int index = type_index_to_flattened_slot(slot, type) * 2; + info[index] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); + info[index+1] = make_uint4(tex_img.data_depth, 0, 0, 0); memcpy(pixels_byte4+offset, (void*)tex_img.data_pointer, tex_img.memory_size()); offset += tex_img.size(); @@ -1159,7 +1161,10 @@ void ImageManager::device_pack_images(Device *device, /* todo: support 3D textures, only CPU for now */ uint8_t options = pack_image_options(type, slot); - info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); + + int index = type_index_to_flattened_slot(slot, type) * 2; + info[index] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); + info[index+1] = make_uint4(tex_img.data_depth, 0, 0, 0); memcpy(pixels_float4+offset, (void*)tex_img.data_pointer, tex_img.memory_size()); offset += tex_img.size(); @@ -1187,7 +1192,9 @@ void ImageManager::device_pack_images(Device *device, uint8_t options = pack_image_options(type, slot); - info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); + int index = type_index_to_flattened_slot(slot, type) * 2; + info[index] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); + info[index+1] = make_uint4(tex_img.data_depth, 0, 0, 0); memcpy(pixels_byte+offset, (void*)tex_img.data_pointer, tex_img.memory_size()); offset += tex_img.size(); @@ -1216,7 +1223,10 @@ void ImageManager::device_pack_images(Device *device, /* todo: support 3D textures, only CPU for now */ uint8_t options = pack_image_options(type, slot); - info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); + + int index = type_index_to_flattened_slot(slot, type) * 2; + info[index] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); + info[index+1] = make_uint4(tex_img.data_depth, 0, 0, 0); memcpy(pixels_float+offset, (void*)tex_img.data_pointer, tex_img.memory_size()); offset += tex_img.size(); From 672e906d49e6edee056bc1df7c413fb98f04f24a Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Sun, 23 Oct 2016 11:14:48 +0200 Subject: [PATCH 013/590] Add a built-in sphinx extension to allow cross-linking to the blender manual. This works by downloading the objects.inv file (https://www.blender.org/manual/objects.inv) and using it to resolve links with blender-manual: before them. --- doc/python_api/rst/info_tutorial_addon.rst | 10 ++-------- doc/python_api/sphinx_doc_gen.py | 7 +++++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/python_api/rst/info_tutorial_addon.rst b/doc/python_api/rst/info_tutorial_addon.rst index 9326f80d4c3..60b4196d6d4 100644 --- a/doc/python_api/rst/info_tutorial_addon.rst +++ b/doc/python_api/rst/info_tutorial_addon.rst @@ -121,14 +121,8 @@ Add the following script to the text editor in Blender. obj.location.x += 1.0 -.. image:: run_script.png - :width: 924px - :align: center - :height: 574px - :alt: Run Script button - -Click the Run Script button, all objects in the active scene are moved by 1.0 Blender unit. -Next we will make this script into an add-on. +Click the :ref:`Run Script button `, +all objects in the active scene are moved by 1.0 Blender unit. Write the Add-on (Simple) diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 5034de7c02b..6c1b694333f 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1632,6 +1632,13 @@ def write_sphinx_conf_py(basepath): file = open(filepath, "w", encoding="utf-8") fw = file.write + fw("import sys, os\n") + fw("\n") + fw("extensions = ['sphinx.ext.intersphinx']\n") + fw("\n") + fw("intersphinx_mapping = {'blender_manual': ('https://www.blender.org/manual/', None)}\n") + fw("\n") + fw("project = 'Blender'\n") # fw("master_doc = 'index'\n") fw("copyright = u'Blender Foundation'\n") From 5d2620e9c22eabfa3df712bbca18b19be72b9fc3 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sun, 23 Oct 2016 13:05:47 +0200 Subject: [PATCH 014/590] System info: also report enabled add-ons. Based on idea & patch by @lijenstina over IRC (iirc :/ ). --- release/scripts/modules/sys_info.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py index 30b9cdfaf37..176051870b0 100644 --- a/release/scripts/modules/sys_info.py +++ b/release/scripts/modules/sys_info.py @@ -212,4 +212,14 @@ def write_sysinfo(filepath): output.write(title("Cycles")) output.write(cycles.engine.system_info()) + import addon_utils + addon_utils.modules() + output.write(title("Enabled add-ons")) + for addon in bpy.context.user_preferences.addons.keys(): + addon_mod = addon_utils.addons_fake_modules.get(addon, None) + if addon_mod is None: + output.write("\t %s (MISSING)\n" % (addon)) + else: + output.write("\t %s (%s, %s)\n" % (addon, addon_mod.bl_info.get('version', "UNKNOWN"), addon_mod.__file__)) + output.close() From 35fde5ff7d848130c30f95c4d281bfc77ae91179 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sun, 23 Oct 2016 13:12:58 +0200 Subject: [PATCH 015/590] System info: make it more resiliant to errors. Using context manager for output file itself, and whole try/except block to at least catch and print error in file. Also some minor tweaks to previous 'list add-ons' commit. --- release/scripts/modules/sys_info.py | 335 ++++++++++++++-------------- 1 file changed, 168 insertions(+), 167 deletions(-) diff --git a/release/scripts/modules/sys_info.py b/release/scripts/modules/sys_info.py index 176051870b0..5b81df28524 100644 --- a/release/scripts/modules/sys_info.py +++ b/release/scripts/modules/sys_info.py @@ -39,187 +39,188 @@ def write_sysinfo(filepath): r = r[1:-1] return r - output = open(filepath, 'w', encoding="utf-8") + with open(filepath, 'w', encoding="utf-8") as output: + try: + header = "= Blender %s System Information =\n" % bpy.app.version_string + lilies = "%s\n\n" % ((len(header) - 1) * "=") + output.write(lilies[:-1]) + output.write(header) + output.write(lilies) - header = "= Blender %s System Information =\n" % bpy.app.version_string - lilies = "%s\n\n" % ((len(header) - 1) * "=") - output.write(lilies[:-1]) - output.write(header) - output.write(lilies) + def title(text): + return "\n%s:\n%s" % (text, lilies) - def title(text): - return "\n%s:\n%s" % (text, lilies) - - # build info - output.write(title("Blender")) - output.write( - "version: %s, branch: %s, commit date: %s %s, hash: %s, type: %s\n" % - (bpy.app.version_string, - prepr(bpy.app.build_branch), - prepr(bpy.app.build_commit_date), - prepr(bpy.app.build_commit_time), - prepr(bpy.app.build_hash), - prepr(bpy.app.build_type), - )) - - output.write("build date: %s, %s\n" % (prepr(bpy.app.build_date), prepr(bpy.app.build_time))) - output.write("platform: %s\n" % prepr(bpy.app.build_platform)) - output.write("binary path: %s\n" % prepr(bpy.app.binary_path)) - output.write("build cflags: %s\n" % prepr(bpy.app.build_cflags)) - output.write("build cxxflags: %s\n" % prepr(bpy.app.build_cxxflags)) - output.write("build linkflags: %s\n" % prepr(bpy.app.build_linkflags)) - output.write("build system: %s\n" % prepr(bpy.app.build_system)) - - # python info - output.write(title("Python")) - output.write("version: %s\n" % (sys.version)) - output.write("paths:\n") - for p in sys.path: - output.write("\t%r\n" % p) - - output.write(title("Python (External Binary)")) - output.write("binary path: %s\n" % prepr(bpy.app.binary_path_python)) - try: - py_ver = prepr(subprocess.check_output([ - bpy.app.binary_path_python, - "--version", - ]).strip()) - except Exception as e: - py_ver = str(e) - output.write("version: %s\n" % py_ver) - del py_ver - - output.write(title("Directories")) - output.write("scripts:\n") - for p in bpy.utils.script_paths(): - output.write("\t%r\n" % p) - output.write("user scripts: %r\n" % (bpy.utils.script_path_user())) - output.write("pref scripts: %r\n" % (bpy.utils.script_path_pref())) - output.write("datafiles: %r\n" % (bpy.utils.user_resource('DATAFILES'))) - output.write("config: %r\n" % (bpy.utils.user_resource('CONFIG'))) - output.write("scripts : %r\n" % (bpy.utils.user_resource('SCRIPTS'))) - output.write("autosave: %r\n" % (bpy.utils.user_resource('AUTOSAVE'))) - output.write("tempdir: %r\n" % (bpy.app.tempdir)) - - output.write(title("FFmpeg")) - ffmpeg = bpy.app.ffmpeg - if ffmpeg.supported: - for lib in ("avcodec", "avdevice", "avformat", "avutil", "swscale"): + # build info + output.write(title("Blender")) output.write( - "%s:%s%r\n" % (lib, " " * (10 - len(lib)), - getattr(ffmpeg, lib + "_version_string"))) - else: - output.write("Blender was built without FFmpeg support\n") + "version: %s, branch: %s, commit date: %s %s, hash: %s, type: %s\n" % + (bpy.app.version_string, + prepr(bpy.app.build_branch), + prepr(bpy.app.build_commit_date), + prepr(bpy.app.build_commit_time), + prepr(bpy.app.build_hash), + prepr(bpy.app.build_type), + )) - if bpy.app.build_options.sdl: - output.write(title("SDL")) - output.write("Version: %s\n" % bpy.app.sdl.version_string) - output.write("Loading method: ") - if bpy.app.build_options.sdl_dynload: - output.write("dynamically loaded by Blender (WITH_SDL_DYNLOAD=ON)\n") - else: - output.write("linked (WITH_SDL_DYNLOAD=OFF)\n") - if not bpy.app.sdl.available: - output.write("WARNING: Blender could not load SDL library\n") + output.write("build date: %s, %s\n" % (prepr(bpy.app.build_date), prepr(bpy.app.build_time))) + output.write("platform: %s\n" % prepr(bpy.app.build_platform)) + output.write("binary path: %s\n" % prepr(bpy.app.binary_path)) + output.write("build cflags: %s\n" % prepr(bpy.app.build_cflags)) + output.write("build cxxflags: %s\n" % prepr(bpy.app.build_cxxflags)) + output.write("build linkflags: %s\n" % prepr(bpy.app.build_linkflags)) + output.write("build system: %s\n" % prepr(bpy.app.build_system)) - output.write(title("Other Libraries")) - ocio = bpy.app.ocio - output.write("OpenColorIO: ") - if ocio.supported: - if ocio.version_string == "fallback": - output.write("Blender was built with OpenColorIO, " + - "but it currently uses fallback color management.\n") - else: - output.write("%s\n" % (ocio.version_string)) - else: - output.write("Blender was built without OpenColorIO support\n") + # python info + output.write(title("Python")) + output.write("version: %s\n" % (sys.version)) + output.write("paths:\n") + for p in sys.path: + output.write("\t%r\n" % p) - oiio = bpy.app.oiio - output.write("OpenImageIO: ") - if ocio.supported: - output.write("%s\n" % (oiio.version_string)) - else: - output.write("Blender was built without OpenImageIO support\n") + output.write(title("Python (External Binary)")) + output.write("binary path: %s\n" % prepr(bpy.app.binary_path_python)) + try: + py_ver = prepr(subprocess.check_output([ + bpy.app.binary_path_python, + "--version", + ]).strip()) + except Exception as e: + py_ver = str(e) + output.write("version: %s\n" % py_ver) + del py_ver - output.write("OpenShadingLanguage: ") - if bpy.app.build_options.cycles: - if bpy.app.build_options.cycles_osl: - from _cycles import osl_version_string - output.write("%s\n" % (osl_version_string)) - else: - output.write("Blender was built without OpenShadingLanguage support in Cycles\n") - else: - output.write("Blender was built without Cycles support\n") + output.write(title("Directories")) + output.write("scripts:\n") + for p in bpy.utils.script_paths(): + output.write("\t%r\n" % p) + output.write("user scripts: %r\n" % (bpy.utils.script_path_user())) + output.write("pref scripts: %r\n" % (bpy.utils.script_path_pref())) + output.write("datafiles: %r\n" % (bpy.utils.user_resource('DATAFILES'))) + output.write("config: %r\n" % (bpy.utils.user_resource('CONFIG'))) + output.write("scripts : %r\n" % (bpy.utils.user_resource('SCRIPTS'))) + output.write("autosave: %r\n" % (bpy.utils.user_resource('AUTOSAVE'))) + output.write("tempdir: %r\n" % (bpy.app.tempdir)) - openvdb = bpy.app.openvdb - output.write("OpenVDB: ") - if openvdb.supported: - output.write("%s\n" % openvdb.version_string) - else: - output.write("Blender was built without OpenVDB support\n") + output.write(title("FFmpeg")) + ffmpeg = bpy.app.ffmpeg + if ffmpeg.supported: + for lib in ("avcodec", "avdevice", "avformat", "avutil", "swscale"): + output.write( + "%s:%s%r\n" % (lib, " " * (10 - len(lib)), + getattr(ffmpeg, lib + "_version_string"))) + else: + output.write("Blender was built without FFmpeg support\n") - alembic = bpy.app.alembic - output.write("Alembic: ") - if alembic.supported: - output.write("%s\n" % alembic.version_string) - else: - output.write("Blender was built without Alembic support\n") + if bpy.app.build_options.sdl: + output.write(title("SDL")) + output.write("Version: %s\n" % bpy.app.sdl.version_string) + output.write("Loading method: ") + if bpy.app.build_options.sdl_dynload: + output.write("dynamically loaded by Blender (WITH_SDL_DYNLOAD=ON)\n") + else: + output.write("linked (WITH_SDL_DYNLOAD=OFF)\n") + if not bpy.app.sdl.available: + output.write("WARNING: Blender could not load SDL library\n") - if not bpy.app.build_options.sdl: - output.write("SDL: Blender was built without SDL support\n") + output.write(title("Other Libraries")) + ocio = bpy.app.ocio + output.write("OpenColorIO: ") + if ocio.supported: + if ocio.version_string == "fallback": + output.write("Blender was built with OpenColorIO, " + + "but it currently uses fallback color management.\n") + else: + output.write("%s\n" % (ocio.version_string)) + else: + output.write("Blender was built without OpenColorIO support\n") - if bpy.app.background: - output.write("\nOpenGL: missing, background mode\n") - else: - output.write(title("OpenGL")) - version = bgl.glGetString(bgl.GL_RENDERER) - output.write("renderer:\t%r\n" % version) - output.write("vendor:\t\t%r\n" % (bgl.glGetString(bgl.GL_VENDOR))) - output.write("version:\t%r\n" % (bgl.glGetString(bgl.GL_VERSION))) - output.write("extensions:\n") + oiio = bpy.app.oiio + output.write("OpenImageIO: ") + if ocio.supported: + output.write("%s\n" % (oiio.version_string)) + else: + output.write("Blender was built without OpenImageIO support\n") - glext = sorted(bgl.glGetString(bgl.GL_EXTENSIONS).split()) - for l in glext: - output.write("\t%s\n" % l) + output.write("OpenShadingLanguage: ") + if bpy.app.build_options.cycles: + if bpy.app.build_options.cycles_osl: + from _cycles import osl_version_string + output.write("%s\n" % (osl_version_string)) + else: + output.write("Blender was built without OpenShadingLanguage support in Cycles\n") + else: + output.write("Blender was built without Cycles support\n") - output.write(title("Implementation Dependent OpenGL Limits")) - limit = bgl.Buffer(bgl.GL_INT, 1) - bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_UNITS, limit) - output.write("Maximum Fixed Function Texture Units:\t%d\n" % limit[0]) - bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_VERTICES, limit) - output.write("Maximum DrawElements Vertices:\t%d\n" % limit[0]) - bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_INDICES, limit) - output.write("Maximum DrawElements Indices:\t%d\n" % limit[0]) + openvdb = bpy.app.openvdb + output.write("OpenVDB: ") + if openvdb.supported: + output.write("%s\n" % openvdb.version_string) + else: + output.write("Blender was built without OpenVDB support\n") - output.write("\nGLSL:\n") - bgl.glGetIntegerv(bgl.GL_MAX_VARYING_FLOATS, limit) - output.write("Maximum Varying Floats:\t%d\n" % limit[0]) - bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_ATTRIBS, limit) - output.write("Maximum Vertex Attributes:\t%d\n" % limit[0]) - bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_UNIFORM_COMPONENTS, limit) - output.write("Maximum Vertex Uniform Components:\t%d\n" % limit[0]) - bgl.glGetIntegerv(bgl.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, limit) - output.write("Maximum Fragment Uniform Components:\t%d\n" % limit[0]) - bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, limit) - output.write("Maximum Vertex Image Units:\t%d\n" % limit[0]) - bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_IMAGE_UNITS, limit) - output.write("Maximum Fragment Image Units:\t%d\n" % limit[0]) - bgl.glGetIntegerv(bgl.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, limit) - output.write("Maximum Pipeline Image Units:\t%d\n" % limit[0]) + alembic = bpy.app.alembic + output.write("Alembic: ") + if alembic.supported: + output.write("%s\n" % alembic.version_string) + else: + output.write("Blender was built without Alembic support\n") - if bpy.app.build_options.cycles: - import cycles - output.write(title("Cycles")) - output.write(cycles.engine.system_info()) + if not bpy.app.build_options.sdl: + output.write("SDL: Blender was built without SDL support\n") - import addon_utils - addon_utils.modules() - output.write(title("Enabled add-ons")) - for addon in bpy.context.user_preferences.addons.keys(): - addon_mod = addon_utils.addons_fake_modules.get(addon, None) - if addon_mod is None: - output.write("\t %s (MISSING)\n" % (addon)) - else: - output.write("\t %s (%s, %s)\n" % (addon, addon_mod.bl_info.get('version', "UNKNOWN"), addon_mod.__file__)) + if bpy.app.background: + output.write("\nOpenGL: missing, background mode\n") + else: + output.write(title("OpenGL")) + version = bgl.glGetString(bgl.GL_RENDERER) + output.write("renderer:\t%r\n" % version) + output.write("vendor:\t\t%r\n" % (bgl.glGetString(bgl.GL_VENDOR))) + output.write("version:\t%r\n" % (bgl.glGetString(bgl.GL_VERSION))) + output.write("extensions:\n") - output.close() + glext = sorted(bgl.glGetString(bgl.GL_EXTENSIONS).split()) + for l in glext: + output.write("\t%s\n" % l) + + output.write(title("Implementation Dependent OpenGL Limits")) + limit = bgl.Buffer(bgl.GL_INT, 1) + bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_UNITS, limit) + output.write("Maximum Fixed Function Texture Units:\t%d\n" % limit[0]) + bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_VERTICES, limit) + output.write("Maximum DrawElements Vertices:\t%d\n" % limit[0]) + bgl.glGetIntegerv(bgl.GL_MAX_ELEMENTS_INDICES, limit) + output.write("Maximum DrawElements Indices:\t%d\n" % limit[0]) + + output.write("\nGLSL:\n") + bgl.glGetIntegerv(bgl.GL_MAX_VARYING_FLOATS, limit) + output.write("Maximum Varying Floats:\t%d\n" % limit[0]) + bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_ATTRIBS, limit) + output.write("Maximum Vertex Attributes:\t%d\n" % limit[0]) + bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_UNIFORM_COMPONENTS, limit) + output.write("Maximum Vertex Uniform Components:\t%d\n" % limit[0]) + bgl.glGetIntegerv(bgl.GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, limit) + output.write("Maximum Fragment Uniform Components:\t%d\n" % limit[0]) + bgl.glGetIntegerv(bgl.GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, limit) + output.write("Maximum Vertex Image Units:\t%d\n" % limit[0]) + bgl.glGetIntegerv(bgl.GL_MAX_TEXTURE_IMAGE_UNITS, limit) + output.write("Maximum Fragment Image Units:\t%d\n" % limit[0]) + bgl.glGetIntegerv(bgl.GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, limit) + output.write("Maximum Pipeline Image Units:\t%d\n" % limit[0]) + + if bpy.app.build_options.cycles: + import cycles + output.write(title("Cycles")) + output.write(cycles.engine.system_info()) + + import addon_utils + addon_utils.modules() + output.write(title("Enabled add-ons")) + for addon in bpy.context.user_preferences.addons.keys(): + addon_mod = addon_utils.addons_fake_modules.get(addon, None) + if addon_mod is None: + output.write("%s (MISSING)\n" % (addon)) + else: + output.write("%s (version: %s, path: %s)\n" % + (addon, addon_mod.bl_info.get('version', "UNKNOWN"), addon_mod.__file__)) + except Exception as e: + output.write("ERROR: %s\n" % e) From e0a34e963fff4e569f6953325854b1c7acb6f1c6 Mon Sep 17 00:00:00 2001 From: Quentin Wenger Date: Sun, 23 Oct 2016 14:04:27 +0200 Subject: [PATCH 016/590] Displace modifier: add global/local space option for X/Y/Z/XYZ directions. Reviewed By: brecht Differential Revision: https://developer.blender.org/D2309 --- .../startup/bl_ui/properties_data_modifier.py | 3 + source/blender/makesdna/DNA_modifier_types.h | 8 ++- source/blender/makesrna/intern/rna_modifier.c | 11 ++++ .../blender/modifiers/intern/MOD_displace.c | 60 ++++++++++++++++--- 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 84ee06c7d70..540c29f31e4 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -336,6 +336,9 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col = split.column(align=True) col.label(text="Direction:") col.prop(md, "direction", text="") + if md.direction in {'X', 'Y', 'Z', 'RGB_TO_XYZ'}: + col.label(text="Space:") + col.prop(md, "space", text="") col.label(text="Vertex Group:") col.prop_search(md, "vertex_group", ob, "vertex_groups", text="") diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 9187b76f012..1398e9de76f 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -383,7 +383,7 @@ typedef struct DisplaceModifierData { int direction; char defgrp_name[64]; /* MAX_VGROUP_NAME */ float midlevel; - int pad; + int space; } DisplaceModifierData; /* DisplaceModifierData->direction */ @@ -404,6 +404,12 @@ enum { MOD_DISP_MAP_UV = 3, }; +/* DisplaceModifierData->space */ +enum { + MOD_DISP_SPACE_LOCAL = 0, + MOD_DISP_SPACE_GLOBAL = 1, +}; + typedef struct UVProjectModifierData { ModifierData modifier; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 34ca6a12fc3..39f6298ca61 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -2100,6 +2100,12 @@ static void rna_def_modifier_displace(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_space_items[] = { + {MOD_DISP_SPACE_LOCAL, "LOCAL", 0, "Local", "Direction is defined in local coordinates"}, + {MOD_DISP_SPACE_GLOBAL, "GLOBAL", 0, "Global", "Direction is defined in global coordinates"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "DisplaceModifier", "Modifier"); RNA_def_struct_ui_text(srna, "Displace Modifier", "Displacement modifier"); RNA_def_struct_sdna(srna, "DisplaceModifierData"); @@ -2130,6 +2136,11 @@ static void rna_def_modifier_displace(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Direction", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "space", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_space_items); + RNA_def_property_ui_text(prop, "Space", ""); + RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update"); + rna_def_modifier_generic_map_info(srna); } diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c index 9ba2d214d50..059e096ddb4 100644 --- a/source/blender/modifiers/intern/MOD_displace.c +++ b/source/blender/modifiers/intern/MOD_displace.c @@ -46,6 +46,7 @@ #include "BKE_modifier.h" #include "BKE_texture.h" #include "BKE_deform.h" +#include "BKE_object.h" #include "depsgraph_private.h" #include "MEM_guardedalloc.h" @@ -65,6 +66,7 @@ static void initData(ModifierData *md) dmd->strength = 1; dmd->direction = MOD_DISP_DIR_NOR; dmd->midlevel = 0.5; + dmd->space = MOD_DISP_SPACE_LOCAL; } static void copyData(ModifierData *md, ModifierData *target) @@ -171,10 +173,13 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, } - if (dmd->texmapping == MOD_DISP_MAP_GLOBAL) + if (dmd->texmapping == MOD_DISP_MAP_GLOBAL || + (ELEM(dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) && + dmd->space == MOD_DISP_SPACE_GLOBAL)) + { dag_add_relation(forest, obNode, obNode, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Displace Modifier"); - + } } static void updateDepsgraph(ModifierData *md, @@ -187,7 +192,10 @@ static void updateDepsgraph(ModifierData *md, if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) { DEG_add_object_relation(node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier"); } - if (dmd->texmapping == MOD_DISP_MAP_GLOBAL) { + if (dmd->texmapping == MOD_DISP_MAP_GLOBAL || + (ELEM(dmd->direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) && + dmd->space == MOD_DISP_SPACE_GLOBAL)) + { DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Displace Modifier"); } } @@ -206,6 +214,8 @@ static void displaceModifier_do( float weight = 1.0f; /* init value unused but some compilers may complain */ const float delta_fixed = 1.0f - dmd->midlevel; /* when no texture is used, we fallback to white */ float (*vert_clnors)[3] = NULL; + float local_mat[4][4]; + const bool use_global_direction = dmd->space == MOD_DISP_SPACE_GLOBAL; if (!dmd->texture && dmd->direction == MOD_DISP_DIR_RGB_XYZ) return; if (dmd->strength == 0.0f) return; @@ -243,11 +253,17 @@ static void displaceModifier_do( direction = MOD_DISP_DIR_NOR; } } + else if (ELEM(direction, MOD_DISP_DIR_X, MOD_DISP_DIR_Y, MOD_DISP_DIR_Z, MOD_DISP_DIR_RGB_XYZ) && + use_global_direction) + { + copy_m4_m4(local_mat, ob->obmat); + } for (i = 0; i < numVerts; i++) { TexResult texres; float strength = dmd->strength; float delta; + float local_vec[3]; if (dvert) { weight = defvert_find_weight(dvert + i, defgrp_index); @@ -270,18 +286,44 @@ static void displaceModifier_do( switch (direction) { case MOD_DISP_DIR_X: - vertexCos[i][0] += delta; + if (use_global_direction) { + vertexCos[i][0] += delta * local_mat[0][0]; + vertexCos[i][1] += delta * local_mat[1][0]; + vertexCos[i][2] += delta * local_mat[2][0]; + } + else { + vertexCos[i][0] += delta; + } break; case MOD_DISP_DIR_Y: - vertexCos[i][1] += delta; + if (use_global_direction) { + vertexCos[i][0] += delta * local_mat[0][1]; + vertexCos[i][1] += delta * local_mat[1][1]; + vertexCos[i][2] += delta * local_mat[2][1]; + } + else { + vertexCos[i][1] += delta; + } break; case MOD_DISP_DIR_Z: - vertexCos[i][2] += delta; + if (use_global_direction) { + vertexCos[i][0] += delta * local_mat[0][2]; + vertexCos[i][1] += delta * local_mat[1][2]; + vertexCos[i][2] += delta * local_mat[2][2]; + } + else { + vertexCos[i][2] += delta; + } break; case MOD_DISP_DIR_RGB_XYZ: - vertexCos[i][0] += (texres.tr - dmd->midlevel) * strength; - vertexCos[i][1] += (texres.tg - dmd->midlevel) * strength; - vertexCos[i][2] += (texres.tb - dmd->midlevel) * strength; + local_vec[0] = texres.tr - dmd->midlevel; + local_vec[1] = texres.tg - dmd->midlevel; + local_vec[2] = texres.tb - dmd->midlevel; + if (use_global_direction) { + mul_transposed_mat3_m4_v3(local_mat, local_vec); + } + mul_v3_fl(local_vec, strength); + add_v3_v3(vertexCos[i], local_vec); break; case MOD_DISP_DIR_NOR: vertexCos[i][0] += delta * (mvert[i].no[0] / 32767.0f); From 1d13950ae544d532ed5a89b5fe4184c60214ee71 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Sun, 23 Oct 2016 17:47:56 +0200 Subject: [PATCH 017/590] API doc: enable 'split index' option. --- doc/python_api/sphinx_doc_gen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 6c1b694333f..432cceece1c 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1655,6 +1655,7 @@ def write_sphinx_conf_py(basepath): # not helpful since the source is generated, adds to upload size. fw("html_copy_source = False\n") + fw("html_split_index = True\n") fw("\n") # needed for latex, pdf gen From c013280eec2fa1e5431b3346fa342e9681b1c1a3 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 24 Oct 2016 10:06:00 +0200 Subject: [PATCH 018/590] Fix mistake in BKE_mesh_new_from_object handling of materials in MetaBall case. Typo, spoted by Coverity scan. To be backported to 2.78a. --- source/blender/blenkernel/intern/mesh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 446aef9be65..d21f43ac484 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2389,7 +2389,7 @@ Mesh *BKE_mesh_new_from_object( /* are we an object material or data based? */ tmpmesh->mat[i] = give_current_material(ob, i + 1); - if (((ob->matbits[i] && ob->matbits) || do_mat_id_data_us) && tmpmesh->mat[i]) { + if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) { id_us_plus(&tmpmesh->mat[i]->id); } } From 89a3b178534c042f97f18f5ecaac3456733c77d4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 24 Oct 2016 10:09:13 +0200 Subject: [PATCH 019/590] Fix T49827L Crash linking material while in Material viewport shading mode Material linking might and does change the way how drawObject is calculated but does not tag drawObject for recalculation in any way. Now use dependency graph to tag draw object for reclaculation. Currently do this using OB_RECALC_DATA taq since tagging is not very granular yet. In the future we can introduce ore granular tagging in the new dependency graph easily. Simple and safe for 2.78a. --- source/blender/editors/object/object_relations.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 79544f80e95..d1232fd2aab 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1575,7 +1575,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) Material *ma = give_current_material(ob_src, a + 1); assign_material(ob_dst, ma, a + 1, BKE_MAT_ASSIGN_USERPREF); /* also works with ma==NULL */ } - DAG_id_tag_update(&ob_dst->id, 0); + DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); break; case MAKE_LINKS_ANIMDATA: BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false); From 0b749d57ee88863702b13cb5a746ed04410511b7 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 24 Oct 2016 10:25:04 +0200 Subject: [PATCH 020/590] Fix unlikely uninitialized pointer usage. Reported by Coverity. --- source/blender/editors/screen/screen_ops.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index a6b6ccd5a66..860a865466a 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -4197,7 +4197,7 @@ static int space_context_cycle_poll(bContext *C) /** * Helper to get the correct RNA pointer/property pair for changing - * the display context of active space type in \sa. + * the display context of active space type in \a sa. */ static void context_cycle_prop_get( bScreen *screen, const ScrArea *sa, @@ -4214,6 +4214,9 @@ static void context_cycle_prop_get( RNA_pointer_create(NULL, &RNA_UserPreferences, &U, r_ptr); propname = "active_section"; break; + default: + BLI_assert(0); + propname = ""; } *r_prop = RNA_struct_find_property(r_ptr, propname); From 1e1811357d3aeaffec0457f9827c698b05f231e8 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 24 Oct 2016 11:10:35 +0200 Subject: [PATCH 021/590] Cycles: Cleanup, spaces --- intern/cycles/bvh/bvh.cpp | 2 +- intern/cycles/bvh/bvh_build.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 39b2a0cf436..9f2468e4d95 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -343,7 +343,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size(); for(size_t i = 0, j = 0; i < leaf_nodes_offset_size; - i+= BVH_NODE_LEAF_SIZE, j++) + i += BVH_NODE_LEAF_SIZE, j++) { int4 data = leaf_nodes_offset[i]; data.x += prim_offset; diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index f2a735d12e3..c8aeeb886c8 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -787,7 +787,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, if(params.use_unaligned_nodes && !alignment_found) { alignment_found = unaligned_heuristic.compute_aligned_space(p_ref[i][j], - &aligned_space); + &aligned_space); } } LeafNode *leaf_node = new LeafNode(bounds[i], From 3f292596769d699c8347be075a6d4bff8fffd556 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 24 Oct 2016 11:46:26 +0200 Subject: [PATCH 022/590] Fix T49818: Crash when rendering with motion blur It was possible to have non-initialized unaligned BVH split to be used when regular BVH split SAH was inf. Now we ensure that unaligned splitter is only used when it's really initialized. It's a regression and should be in 2.78a. --- intern/cycles/bvh/bvh_build.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index c8aeeb886c8..190f57ba455 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -477,6 +477,7 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) float unalignedSplitSAH = FLT_MAX; float unalignedLeafSAH = FLT_MAX; Transform aligned_space; + bool do_unalinged_split = false; if(params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold*leafSAH) { @@ -496,11 +497,15 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) return create_leaf_node(range, references); } } + /* Check whether unaligned split is better than the regulat one. */ + if(unalignedSplitSAH < splitSAH) { + do_unalinged_split = true; + } } /* Perform split. */ BVHObjectBinning left, right; - if(unalignedSplitSAH < splitSAH) { + if(do_unalinged_split) { unaligned_range.split(&references[0], left, right); } else { @@ -508,7 +513,7 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) } BoundBox bounds; - if(unalignedSplitSAH < splitSAH) { + if(do_unalinged_split) { bounds = unaligned_heuristic.compute_aligned_boundbox( range, &references[0], aligned_space); } @@ -533,7 +538,7 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) task_pool.push(new BVHBuildTask(this, inner, 1, right, level + 1), true); } - if(unalignedSplitSAH < splitSAH) { + if(do_unalinged_split) { inner->set_aligned_space(aligned_space); } @@ -583,6 +588,7 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, float unalignedSplitSAH = FLT_MAX; /* float unalignedLeafSAH = FLT_MAX; */ Transform aligned_space; + bool do_unalinged_split; if(params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold*leafSAH) { @@ -599,11 +605,15 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() + params.sah_primitive_cost * unaligned_split.nodeSAH; /* TOOD(sergey): Check we can create leaf already. */ + /* Check whether unaligned split is better than the regulat one. */ + if(unalignedSplitSAH < splitSAH) { + do_unalinged_split = true; + } } /* Do split. */ BVHRange left, right; - if(unalignedSplitSAH < splitSAH) { + if(do_unalinged_split) { unaligned_split.split(this, left, right, range); } else { @@ -613,7 +623,7 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, progress_total += left.size() + right.size() - range.size(); BoundBox bounds; - if(unalignedSplitSAH < splitSAH) { + if(do_unalinged_split) { bounds = unaligned_heuristic.compute_aligned_boundbox( range, &references->at(0), aligned_space); } @@ -657,7 +667,7 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, true); } - if(unalignedSplitSAH < splitSAH) { + if(do_unalinged_split) { inner->set_aligned_space(aligned_space); } From 48997d2e40a74a83fb9edfb9de0999139392f634 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 24 Oct 2016 12:26:12 +0200 Subject: [PATCH 023/590] Cycles: Cleanup, style --- intern/cycles/blender/blender_mesh.cpp | 4 ++-- intern/cycles/bvh/bvh.cpp | 8 ++++---- intern/cycles/bvh/bvh_node.h | 2 +- intern/cycles/device/opencl/opencl_base.cpp | 2 +- intern/cycles/kernel/kernel_camera.h | 10 +++++----- intern/cycles/kernel/kernel_image_opencl.h | 10 +++++++--- intern/cycles/kernel/svm/svm_ramp_util.h | 14 ++++++++------ intern/cycles/render/camera.cpp | 3 ++- intern/cycles/render/graph.cpp | 7 ++++--- intern/cycles/render/image.cpp | 2 +- intern/cycles/render/mesh.cpp | 2 +- intern/cycles/render/nodes.cpp | 15 +++++++++------ intern/cycles/render/object.cpp | 5 +++-- intern/cycles/render/osl.cpp | 5 ++--- intern/cycles/subd/subd_patch_table.cpp | 2 +- intern/cycles/test/render_graph_finalize_test.cpp | 3 ++- 16 files changed, 53 insertions(+), 41 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index ff1d49ffd12..fab03c7659b 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -847,7 +847,7 @@ static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh) /* Only export previous and next frame, we don't have any in between data. */ float motion_times[2] = {-1.0f, 1.0f}; - for (int step = 0; step < 2; step++) { + for(int step = 0; step < 2; step++) { float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f; float3 *mP = attr_mP->data_float3() + step*mesh->verts.size(); @@ -1081,7 +1081,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, /* fluid motion is exported immediate with mesh, skip here */ BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); - if (b_fluid_domain) + if(b_fluid_domain) return; if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 9f2468e4d95..4851de5b481 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -147,7 +147,7 @@ void BVH::pack_primitives() /* Count number of triangles primitives in BVH. */ for(unsigned int i = 0; i < tidx_size; i++) { if((pack.prim_index[i] != -1)) { - if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { ++num_prim_triangles; } } @@ -450,7 +450,7 @@ void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1) { - if (e0.node->is_unaligned() || e1.node->is_unaligned()) { + if(e0.node->is_unaligned() || e1.node->is_unaligned()) { pack_unaligned_inner(e, e0, e1); } else { pack_aligned_inner(e, e0, e1); @@ -597,8 +597,8 @@ void RegularBVH::pack_nodes(const BVHNode *root) else { /* innner node */ int idx[2]; - for (int i = 0; i < 2; ++i) { - if (e.node->get_child(i)->is_leaf()) { + for(int i = 0; i < 2; ++i) { + if(e.node->get_child(i)->is_leaf()) { idx[i] = nextLeafNodeIdx++; } else { diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h index f2965a785e6..2faa40ab657 100644 --- a/intern/cycles/bvh/bvh_node.h +++ b/intern/cycles/bvh/bvh_node.h @@ -66,7 +66,7 @@ public: inline void set_aligned_space(const Transform& aligned_space) { m_is_unaligned = true; - if (m_aligned_space == NULL) { + if(m_aligned_space == NULL) { m_aligned_space = new Transform(aligned_space); } else { diff --git a/intern/cycles/device/opencl/opencl_base.cpp b/intern/cycles/device/opencl/opencl_base.cpp index e67ffb1a836..a2b900312e7 100644 --- a/intern/cycles/device/opencl/opencl_base.cpp +++ b/intern/cycles/device/opencl/opencl_base.cpp @@ -409,7 +409,7 @@ void OpenCLDeviceBase::enqueue_kernel(cl_kernel kernel, size_t w, size_t h) * much work per pixel (if we don't check global ID on Y axis) or will * be checking for global ID to always have Y of 0. */ - if (h == 1) { + if(h == 1) { global_size[h] = 1; } diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h index 0888466f5ff..b99a82b0203 100644 --- a/intern/cycles/kernel/kernel_camera.h +++ b/intern/cycles/kernel/kernel_camera.h @@ -109,7 +109,7 @@ ccl_device void camera_sample_perspective(KernelGlobals *kg, float raster_x, flo D = normalize(transform_direction(&cameratoworld, D)); bool use_stereo = kernel_data.cam.interocular_offset != 0.0f; - if (!use_stereo) { + if(!use_stereo) { /* No stereo */ ray->P = P; ray->D = D; @@ -300,7 +300,7 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, /* Stereo transform */ bool use_stereo = kernel_data.cam.interocular_offset != 0.0f; - if (use_stereo) { + if(use_stereo) { spherical_stereo_transform(kg, &P, &D); } @@ -316,7 +316,7 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, float3 Dcenter = panorama_to_direction(kg, Pcenter.x, Pcenter.y); Pcenter = transform_point(&cameratoworld, Pcenter); Dcenter = normalize(transform_direction(&cameratoworld, Dcenter)); - if (use_stereo) { + if(use_stereo) { spherical_stereo_transform(kg, &Pcenter, &Dcenter); } @@ -324,7 +324,7 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, float3 Dx = panorama_to_direction(kg, Px.x, Px.y); Px = transform_point(&cameratoworld, Px); Dx = normalize(transform_direction(&cameratoworld, Dx)); - if (use_stereo) { + if(use_stereo) { spherical_stereo_transform(kg, &Px, &Dx); } @@ -335,7 +335,7 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, float3 Dy = panorama_to_direction(kg, Py.x, Py.y); Py = transform_point(&cameratoworld, Py); Dy = normalize(transform_direction(&cameratoworld, Dy)); - if (use_stereo) { + if(use_stereo) { spherical_stereo_transform(kg, &Py, &Dy); } diff --git a/intern/cycles/kernel/kernel_image_opencl.h b/intern/cycles/kernel/kernel_image_opencl.h index f6c31b28f2c..0352c58037d 100644 --- a/intern/cycles/kernel/kernel_image_opencl.h +++ b/intern/cycles/kernel/kernel_image_opencl.h @@ -162,16 +162,18 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x, svm_image_texture_frac(y*height, &iy); svm_image_texture_frac(z*depth, &iz); - if (extension == EXTENSION_REPEAT) { + if(extension == EXTENSION_REPEAT) { ix = svm_image_texture_wrap_periodic(ix, width); iy = svm_image_texture_wrap_periodic(iy, height); iz = svm_image_texture_wrap_periodic(iz, depth); } else { - if (extension == EXTENSION_CLIP) { + if(extension == EXTENSION_CLIP) { if(x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) + { return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } } /* Fall through. */ /* EXTENSION_EXTEND */ @@ -196,10 +198,12 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals *kg, int id, float x, niz = svm_image_texture_wrap_periodic(iz+1, depth); } else { - if (extension == EXTENSION_CLIP) + if(extension == EXTENSION_CLIP) if(x < 0.0f || y < 0.0f || z < 0.0f || x > 1.0f || y > 1.0f || z > 1.0f) + { return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } /* Fall through. */ /* EXTENSION_EXTEND */ nix = svm_image_texture_wrap_clamp(ix+1, width); diff --git a/intern/cycles/kernel/svm/svm_ramp_util.h b/intern/cycles/kernel/svm/svm_ramp_util.h index 9f2ce1276f9..b0adadae9b7 100644 --- a/intern/cycles/kernel/svm/svm_ramp_util.h +++ b/intern/cycles/kernel/svm/svm_ramp_util.h @@ -27,9 +27,9 @@ ccl_device_inline float3 rgb_ramp_lookup(const float3 *ramp, bool extrapolate, int table_size) { - if ((f < 0.0f || f > 1.0f) && extrapolate) { + if((f < 0.0f || f > 1.0f) && extrapolate) { float3 t0, dy; - if (f < 0.0f) { + if(f < 0.0f) { t0 = ramp[0]; dy = t0 - ramp[1], f = -f; @@ -50,8 +50,9 @@ ccl_device_inline float3 rgb_ramp_lookup(const float3 *ramp, float3 result = ramp[i]; - if (interpolate && t > 0.0f) + if(interpolate && t > 0.0f) { result = (1.0f - t) * result + t * ramp[i + 1]; + } return result; } @@ -62,9 +63,9 @@ ccl_device float float_ramp_lookup(const float *ramp, bool extrapolate, int table_size) { - if ((f < 0.0f || f > 1.0f) && extrapolate) { + if((f < 0.0f || f > 1.0f) && extrapolate) { float t0, dy; - if (f < 0.0f) { + if(f < 0.0f) { t0 = ramp[0]; dy = t0 - ramp[1], f = -f; @@ -85,8 +86,9 @@ ccl_device float float_ramp_lookup(const float *ramp, float result = ramp[i]; - if (interpolate && t > 0.0f) + if(interpolate && t > 0.0f) { result = (1.0f - t) * result + t * ramp[i + 1]; + } return result; } diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index a6df656d220..c8c51ec96d2 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -32,8 +32,9 @@ CCL_NAMESPACE_BEGIN static float shutter_curve_eval(float x, array& shutter_curve) { - if (shutter_curve.size() == 0) + if(shutter_curve.size() == 0) { return 1.0f; + } x *= shutter_curve.size(); int index = (int)x; diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 131ec824be3..f6c83fb5c7e 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -148,8 +148,9 @@ void ShaderNode::attributes(Shader *shader, AttributeRequestSet *attributes) bool ShaderNode::equals(const ShaderNode& other) { - if (type != other.type || bump != other.bump) + if(type != other.type || bump != other.bump) { return false; + } assert(inputs.size() == other.inputs.size()); @@ -597,13 +598,13 @@ void ShaderGraph::deduplicate_nodes() /* Try to merge this node with another one. */ ShaderNode *merge_with = NULL; foreach(ShaderNode *other_node, candidates[node->type->name]) { - if (node != other_node && node->equals(*other_node)) { + if(node != other_node && node->equals(*other_node)) { merge_with = other_node; break; } } /* If found an equivalent, merge; otherwise keep node for later merges */ - if (merge_with != NULL) { + if(merge_with != NULL) { for(int i = 0; i < node->outputs.size(); ++i) { relink(node, node->outputs[i], merge_with->outputs[i]); } diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 3cb0aa961ec..073a0aa2ac9 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -43,7 +43,7 @@ ImageManager::ImageManager(const DeviceInfo& info) * be screwed on so many levels.. */ DeviceType device_type = info.type; - if (device_type == DEVICE_MULTI) { + if(device_type == DEVICE_MULTI) { device_type = info.multi_devices[0].type; } diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 039bb49d82f..ac369a0d5f8 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1462,7 +1462,7 @@ void MeshManager::device_update_mesh(Device *device, else { PackedBVH& pack = bvh->pack; for(size_t i = 0; i < pack.prim_index.size(); ++i) { - if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { tri_prim_index[pack.prim_index[i]] = pack.prim_tri_index[i]; } } diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 7ea52b28b9c..3b4aa389c13 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -2378,8 +2378,9 @@ void EmissionNode::constant_fold(const ConstantFolder& folder) ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength == 0.0f)) { + if((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)) + { folder.discard(); } } @@ -2430,8 +2431,9 @@ void BackgroundNode::constant_fold(const ConstantFolder& folder) ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength == 0.0f)) { + if((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)) + { folder.discard(); } } @@ -4864,8 +4866,9 @@ void CurvesNode::constant_fold(const ConstantFolder& folder, ShaderInput *value_ /* evaluate fully constant node */ if(folder.all_inputs_constant()) { - if (curves.size() == 0) + if(curves.size() == 0) { return; + } float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x); float3 result; @@ -5140,7 +5143,7 @@ OSLNode* OSLNode::create(size_t num_inputs, const OSLNode *from) char *node_memory = (char*) operator new(node_size + inputs_size); memset(node_memory, 0, node_size + inputs_size); - if (!from) { + if(!from) { return new(node_memory) OSLNode(); } else { diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index d8f3ce58505..8b8b988b969 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -253,7 +253,7 @@ vector Object::motion_times() bool Object::is_traceable() { /* Mesh itself can be empty,can skip all such objects. */ - if (!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) { + if(!bounds.valid() || bounds.size() == make_float3(0.0f, 0.0f, 0.0f)) { return false; } /* TODO(sergey): Check for mesh vertices/curves. visibility flags. */ @@ -624,8 +624,9 @@ void ObjectManager::device_update_flags(Device *device, void ObjectManager::device_update_patch_map_offsets(Device *device, DeviceScene *dscene, Scene *scene) { - if (scene->objects.size() == 0) + if(scene->objects.size() == 0) { return; + } uint4* objects = (uint4*)dscene->objects.get_data(); diff --git a/intern/cycles/render/osl.cpp b/intern/cycles/render/osl.cpp index 18a32f7f328..67b68e63cb2 100644 --- a/intern/cycles/render/osl.cpp +++ b/intern/cycles/render/osl.cpp @@ -825,7 +825,7 @@ void OSLCompiler::parameter(ShaderNode* node, const char *name) // OSL does not support booleans, so convert to int const array& value = node->get_bool_array(socket); array intvalue(value.size()); - for (size_t i = 0; i < value.size(); i++) + for(size_t i = 0; i < value.size(); i++) intvalue[i] = value[i]; ss->Parameter(uname, array_typedesc(TypeDesc::TypeInt, value.size()), intvalue.data()); break; @@ -861,8 +861,7 @@ void OSLCompiler::parameter(ShaderNode* node, const char *name) // convert to tightly packed array since float3 has padding const array& value = node->get_float3_array(socket); array fvalue(value.size() * 3); - for (size_t i = 0, j = 0; i < value.size(); i++) - { + for(size_t i = 0, j = 0; i < value.size(); i++) { fvalue[j++] = value[i].x; fvalue[j++] = value[i].y; fvalue[j++] = value[i].z; diff --git a/intern/cycles/subd/subd_patch_table.cpp b/intern/cycles/subd/subd_patch_table.cpp index 62572efa88a..d437b045c07 100644 --- a/intern/cycles/subd/subd_patch_table.cpp +++ b/intern/cycles/subd/subd_patch_table.cpp @@ -46,7 +46,7 @@ struct PatchMapQuadNode { /* sets all the children to point to the patch of index */ void set_child(int index) { - for (int i = 0; i < 4; i++) { + for(int i = 0; i < 4; i++) { children[i] = index | PATCH_MAP_NODE_IS_SET | PATCH_MAP_NODE_IS_LEAF; } } diff --git a/intern/cycles/test/render_graph_finalize_test.cpp b/intern/cycles/test/render_graph_finalize_test.cpp index 6f1c0b88b51..32b4c7265ee 100644 --- a/intern/cycles/test/render_graph_finalize_test.cpp +++ b/intern/cycles/test/render_graph_finalize_test.cpp @@ -1407,8 +1407,9 @@ void init_test_curve(array &buffer, T start, T end, int steps) { buffer.resize(steps); - for (int i = 0; i < steps; i++) + for(int i = 0; i < steps; i++) { buffer[i] = lerp(start, end, float(i)/(steps-1)); + } } /* From 80a6e5beb5be532916513025303025f961028c8d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 24 Oct 2016 12:31:11 +0200 Subject: [PATCH 024/590] Cycles: Remove explicit std:: from types where possible We have our own abstraction level on top of the STL's implementation. This commit will guarantee our tweaks are used for all cases. --- intern/cycles/blender/blender_python.cpp | 7 ++++--- intern/cycles/blender/blender_shader.cpp | 3 ++- intern/cycles/blender/blender_sync.h | 2 +- intern/cycles/device/device.cpp | 10 +++++----- intern/cycles/graph/node_type.h | 4 ++-- intern/cycles/render/mesh_subdivision.cpp | 2 +- 6 files changed, 15 insertions(+), 13 deletions(-) diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index 0161b5b192c..a50f5edb1df 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -26,6 +26,7 @@ #include "util_md5.h" #include "util_opengl.h" #include "util_path.h" +#include "util_string.h" #include "util_types.h" #ifdef WITH_OSL @@ -437,13 +438,13 @@ static PyObject *osl_update_node_func(PyObject * /*self*/, PyObject *args) continue; /* determine socket type */ - std::string socket_type; + string socket_type; BL::NodeSocket::type_enum data_type = BL::NodeSocket::type_VALUE; float4 default_float4 = make_float4(0.0f, 0.0f, 0.0f, 1.0f); float default_float = 0.0f; int default_int = 0; - std::string default_string = ""; - + string default_string = ""; + if(param->isclosure) { socket_type = "NodeSocketShader"; data_type = BL::NodeSocket::type_SHADER; diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 534bc6cc897..f63f94ab37a 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -27,12 +27,13 @@ #include "blender_util.h" #include "util_debug.h" +#include "util_string.h" CCL_NAMESPACE_BEGIN typedef map PtrInputMap; typedef map PtrOutputMap; -typedef map ProxyMap; +typedef map ProxyMap; /* Find */ diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index b8b9597914e..9a01b4f2b6e 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -165,7 +165,7 @@ private: id_map particle_system_map; set mesh_synced; set mesh_motion_synced; - std::set motion_times; + set motion_times; void *world_map; bool world_recalc; diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 85e736ad635..909ec7a6d60 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -49,17 +49,17 @@ std::ostream& operator <<(std::ostream &os, /* TODO(sergey): Decode bitflag into list of names. */ os << "Nodes features: " << requested_features.nodes_features << std::endl; os << "Use hair: " - << string_from_bool(requested_features.use_hair) << std::endl; + << string_from_bool(requested_features.use_hair) << std::endl; os << "Use object motion: " - << string_from_bool(requested_features.use_object_motion) << std::endl; + << string_from_bool(requested_features.use_object_motion) << std::endl; os << "Use camera motion: " - << string_from_bool(requested_features.use_camera_motion) << std::endl; + << string_from_bool(requested_features.use_camera_motion) << std::endl; os << "Use Baking: " - << string_from_bool(requested_features.use_baking) << std::endl; + << string_from_bool(requested_features.use_baking) << std::endl; os << "Use Subsurface: " << string_from_bool(requested_features.use_subsurface) << std::endl; os << "Use Volume: " - << string_from_bool(requested_features.use_volume) << std::endl; + << string_from_bool(requested_features.use_volume) << std::endl; os << "Use Branched Integrator: " << string_from_bool(requested_features.use_integrator_branched) << std::endl; os << "Use Patch Evaluation: " diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h index 60c3244028d..e89bb5b3c1f 100644 --- a/intern/cycles/graph/node_type.h +++ b/intern/cycles/graph/node_type.h @@ -125,8 +125,8 @@ struct NodeType ustring name; Type type; - std::vector inputs; - std::vector outputs; + vector inputs; + vector outputs; CreateFunc create; static NodeType *add(const char *name, CreateFunc create, Type type = NONE); diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp index 813b23ed91e..913c3c74b42 100644 --- a/intern/cycles/render/mesh_subdivision.cpp +++ b/intern/cycles/render/mesh_subdivision.cpp @@ -92,7 +92,7 @@ namespace Far { if(vert_edges.size() == 2) { float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]); - sharpness = std::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1])); + sharpness = min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1])); setBaseVertexSharpness(refiner, i, sharpness); } From 963aa7e270816c1654ed668ee0dd370e9598f86a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 24 Oct 2016 12:54:24 +0200 Subject: [PATCH 025/590] Cycles: Fix uninitialized variable from the previous commit --- intern/cycles/bvh/bvh_build.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 190f57ba455..14f66aca70f 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -588,7 +588,7 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, float unalignedSplitSAH = FLT_MAX; /* float unalignedLeafSAH = FLT_MAX; */ Transform aligned_space; - bool do_unalinged_split; + bool do_unalinged_split = false; if(params.use_unaligned_nodes && splitSAH > params.unaligned_split_threshold*leafSAH) { From cde18cf3b349a3a4d3b435fd3f76e5304ee446d6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 24 Oct 2016 13:43:55 +0200 Subject: [PATCH 026/590] Cycles: Fix static initialization order fiasco Initialization order of global stats and node types was not strictly defined and it was possible to have node types initialized first and stats after that. This will zero out memory which was allocated from the statistics causing assert failure when de-initializing node types. --- intern/cycles/util/util_guarded_allocator.cpp | 2 +- intern/cycles/util/util_stats.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/intern/cycles/util/util_guarded_allocator.cpp b/intern/cycles/util/util_guarded_allocator.cpp index 8de6e254cbf..615ac95f324 100644 --- a/intern/cycles/util/util_guarded_allocator.cpp +++ b/intern/cycles/util/util_guarded_allocator.cpp @@ -19,7 +19,7 @@ CCL_NAMESPACE_BEGIN -static Stats global_stats; +static Stats global_stats(Stats::static_init); /* Internal API. */ diff --git a/intern/cycles/util/util_stats.h b/intern/cycles/util/util_stats.h index ce27067dc5e..b970b017270 100644 --- a/intern/cycles/util/util_stats.h +++ b/intern/cycles/util/util_stats.h @@ -23,7 +23,10 @@ CCL_NAMESPACE_BEGIN class Stats { public: + enum static_init_t { static_init = 0 }; + Stats() : mem_used(0), mem_peak(0) {} + explicit Stats(static_init_t) {} void mem_alloc(size_t size) { atomic_add_z(&mem_used, size); From 14a55bc059e40ae72021262510e8c0942e4cc89f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 24 Oct 2016 14:04:31 +0200 Subject: [PATCH 027/590] Cycles: Fix shadowing variable which also causes use of uninitialized variable Was causing wrong aperture for panorama cameras. Seems to be a regression in 371d357. --- intern/cycles/kernel/kernel_camera.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h index b99a82b0203..dedac6b1465 100644 --- a/intern/cycles/kernel/kernel_camera.h +++ b/intern/cycles/kernel/kernel_camera.h @@ -264,13 +264,13 @@ ccl_device_inline void camera_sample_panorama(KernelGlobals *kg, float2 lensuv = camera_sample_aperture(kg, lens_u, lens_v)*aperturesize; /* compute point on plane of focus */ - float3 D = normalize(D); - float3 Pfocus = D * kernel_data.cam.focaldistance; + float3 Dfocus = normalize(D); + float3 Pfocus = Dfocus * kernel_data.cam.focaldistance; - /* calculate orthonormal coordinates perpendicular to D */ + /* calculate orthonormal coordinates perpendicular to Dfocus */ float3 U, V; - U = normalize(make_float3(1.0f, 0.0f, 0.0f) - D.x * D); - V = normalize(cross(D, U)); + U = normalize(make_float3(1.0f, 0.0f, 0.0f) - Dfocus.x * Dfocus); + V = normalize(cross(Dfocus, U)); /* update ray for effect of lens */ P = U * lensuv.x + V * lensuv.y; From da8f5d6eac58f18193fdfd22e35fee5e1a13f12b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 24 Oct 2016 14:18:22 +0200 Subject: [PATCH 028/590] Cycles: Don't use guarded vector for statically initialized data This will confuse hell of a guarded allocators because it is possible to have allocation happened prior to Blender's guarded allocator is fully initialized. This was causing crashes and assert failures when running blender with fully guarded memory allocator. --- intern/cycles/graph/node_type.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h index e89bb5b3c1f..1fb135f6d22 100644 --- a/intern/cycles/graph/node_type.h +++ b/intern/cycles/graph/node_type.h @@ -125,8 +125,8 @@ struct NodeType ustring name; Type type; - vector inputs; - vector outputs; + vector > inputs; + vector > outputs; CreateFunc create; static NodeType *add(const char *name, CreateFunc create, Type type = NONE); From 10a25b655af60ca097177058be9ee2cfb2bf4597 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 24 Oct 2016 16:56:41 +0200 Subject: [PATCH 029/590] Cycles: Add AVX2 path to subsurface triangle intersection Similar to regular triangle intersection case. Gives about 3% speedup rendering SSS object on my desktop, Question: how to avoid such a code duplication in a nice way without speed loss? --- .../kernel/geom/geom_triangle_intersect.h | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index b505bd54e5e..8d17e1240a5 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -269,6 +269,67 @@ ccl_device_inline void triangle_intersect_subsurface( const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); + +#if defined(__KERNEL_AVX2__) + const avxf avxf_P(P.m128, P.m128); + + const avxf tri_ab = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 0); + const avxf tri_bc = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 1); + + const avxf AB = tri_ab - avxf_P; + const avxf BC = tri_bc - avxf_P; + + const __m256i permuteMask = _mm256_set_epi32(0x3, kz, ky, kx, 0x3, kz, ky, kx); + + const avxf AB_k = shuffle(AB, permuteMask); + const avxf BC_k = shuffle(BC, permuteMask); + + /* Akz, Akz, Bkz, Bkz, Bkz, Bkz, Ckz, Ckz */ + const avxf ABBC_kz = shuffle<2>(AB_k, BC_k); + + /* Akx, Aky, Bkx, Bky, Bkx,Bky, Ckx, Cky */ + const avxf ABBC_kxy = shuffle<0,1,0,1>(AB_k, BC_k); + + const avxf Sxy(Sy, Sx, Sy, Sx); + + /* Ax, Ay, Bx, By, Bx, By, Cx, Cy */ + const avxf ABBC_xy = nmadd(ABBC_kz, Sxy, ABBC_kxy); + + float ABBC_kz_array[8]; + _mm256_storeu_ps((float*)&ABBC_kz_array, ABBC_kz); + + const float A_kz = ABBC_kz_array[0]; + const float B_kz = ABBC_kz_array[2]; + const float C_kz = ABBC_kz_array[6]; + + /* By, Bx, Cy, Cx, By, Bx, Ay, Ax */ + const avxf BCBA_yx = permute<3,2,7,6,3,2,1,0>(ABBC_xy); + + const avxf negMask(0,0,0,0,0x80000000, 0x80000000, 0x80000000, 0x80000000); + + /* W U V + * (AxBy-AyBx) (BxCy-ByCx) XX XX (BxBy-ByBx) (CxAy-CyAx) XX XX + */ + const avxf WUxxxxVxx_neg = _mm256_hsub_ps(ABBC_xy * BCBA_yx, negMask /* Dont care */); + + const avxf WUVWnegWUVW = permute<0,1,5,0,0,1,5,0>(WUxxxxVxx_neg) ^ negMask; + + /* Calculate scaled barycentric coordinates. */ + float WUVW_array[4]; + _mm_storeu_ps((float*)&WUVW_array, _mm256_castps256_ps128 (WUVWnegWUVW)); + + const float W = WUVW_array[0]; + const float U = WUVW_array[1]; + const float V = WUVW_array[2]; + + const int WUVW_mask = 0x7 & _mm256_movemask_ps(WUVWnegWUVW); + const int WUVW_zero = 0x7 & _mm256_movemask_ps(_mm256_cmp_ps(WUVWnegWUVW, + _mm256_setzero_ps(), 0)); + + if(!((WUVW_mask == 7) || (WUVW_mask == 0)) && ((WUVW_mask | WUVW_zero) != 7)) { + return; + } +#else const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z); const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z); const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z); @@ -295,6 +356,7 @@ ccl_device_inline void triangle_intersect_subsurface( { return; } +#endif /* Calculate determinant. */ float det = U + V + W; From d2fe875f8c9d7cbe8edd0bd71dac1a7b16945613 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 09:28:25 +0200 Subject: [PATCH 030/590] Fix possible compilation error with OIIO enabled OIIO library has plugin API which uses dlopen()/dlclose() so need to link OIO libraries against dl library. --- build_files/cmake/platform/platform_unix.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index e33141f8012..62f44cf1739 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -298,6 +298,7 @@ if(WITH_OPENIMAGEIO) ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES} ${BOOST_LIBRARIES} + ${CMAKE_DL_LIBS} ) set(OPENIMAGEIO_LIBPATH) # TODO, remove and reference the absolute path everywhere set(OPENIMAGEIO_DEFINITIONS "") From 3e7100644861368b5ec951cf36c631e0828012f8 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 10:22:03 +0200 Subject: [PATCH 031/590] CMake: Followup to previous commit, try to ensure -ldl is always last Seems CMake will rearrange and copy libraries which are passed to the linker when some of the libraries is listed twice (for example, -lz from png libraries and -l for blender itself). This was causing libopenimageio to be added somewhere at the end of linking flags without -ldl followed after which was causing linking issues. --- build_files/cmake/macros.cmake | 3 ++- build_files/cmake/platform/platform_unix.cmake | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 5a67ac981a3..2e3a1907063 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -518,7 +518,8 @@ function(setup_liblinks target_link_libraries(${target} ${BLENDER_GL_LIBRARIES}) - target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS}) + #target_link_libraries(${target} ${PLATFORM_LINKLIBS} ${CMAKE_DL_LIBS}) + target_link_libraries(${target} ${PLATFORM_LINKLIBS}) endfunction() diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index 62f44cf1739..e33141f8012 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -298,7 +298,6 @@ if(WITH_OPENIMAGEIO) ${JPEG_LIBRARIES} ${ZLIB_LIBRARIES} ${BOOST_LIBRARIES} - ${CMAKE_DL_LIBS} ) set(OPENIMAGEIO_LIBPATH) # TODO, remove and reference the absolute path everywhere set(OPENIMAGEIO_DEFINITIONS "") From af411d918e68b487155309f5c1e29bb50924b69a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 13:54:17 +0200 Subject: [PATCH 032/590] Cycles: Implement SSE-optimized path of util_max_axis() The idea here is to avoid if statements which could cause wrong branch prediction. Gives a bit of measurable speedup up to ~1%. Still nice :) Inspired by Maxym Dmytrychenko, thanks! --- intern/cycles/util/util_math.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index b9594f7ec69..57cad39d1eb 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -1629,6 +1629,14 @@ ccl_device_inline float2 map_to_sphere(const float3 co) ccl_device_inline int util_max_axis(float3 vec) { +#ifdef __KERNEL_SSE__ + __m128 a = shuffle<0,0,1,1>(vec.m128); + __m128 b = shuffle<1,2,2,1>(vec.m128); + __m128 c = _mm_cmpgt_ps(a, b); + int mask = _mm_movemask_ps(c) & 0x7; + static const char tab[8] = {2, 2, 2, 0, 1, 2, 1, 0}; + return tab[mask]; +#else if(vec.x > vec.y) { if(vec.x > vec.z) return 0; @@ -1641,6 +1649,7 @@ ccl_device_inline int util_max_axis(float3 vec) else return 2; } +#endif } CCL_NAMESPACE_END From 81c9e0d2958a1274f8cb76386a3bafc08a181eed Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 14:18:32 +0200 Subject: [PATCH 033/590] Cycles: Avoid branching in SSE version of intersection pre-calculation Similar to the previous commit, avoid negative effect of bad branch prediction. Gives measurable performance up to ~2% in tests here. Once again, thanks to Maxym Dmytrychenko! --- .../cycles/kernel/geom/geom_triangle_intersect.h | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index 8d17e1240a5..5d76fc3dc58 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -59,21 +59,33 @@ void triangle_intersect_precalc(float3 dir, IsectPrecalc *isect_precalc) { /* Calculate dimension where the ray direction is maximal. */ +#ifndef __KERNEL_SSE__ int kz = util_max_axis(make_float3(fabsf(dir.x), fabsf(dir.y), fabsf(dir.z))); int kx = kz + 1; if(kx == 3) kx = 0; int ky = kx + 1; if(ky == 3) ky = 0; +#else + int kx, ky, kz; + /* Avoiding mispredicted branch on direction. */ + kz = util_max_axis(fabs(dir)); + static const char inc_xaxis[] = {1, 2, 0, 55}; + static const char inc_yaxis[] = {2, 0, 1, 55}; + kx = inc_xaxis[kz]; + ky = inc_yaxis[kz]; +#endif + + float dir_kz = IDX(dir, kz); /* Swap kx and ky dimensions to preserve winding direction of triangles. */ - if(IDX(dir, kz) < 0.0f) { + if(dir_kz < 0.0f) { int tmp = kx; kx = ky; ky = tmp; } /* Calculate the shear constants. */ - float inv_dir_z = 1.0f / IDX(dir, kz); + float inv_dir_z = 1.0f / dir_kz; isect_precalc->Sx = IDX(dir, kx) * inv_dir_z; isect_precalc->Sy = IDX(dir, ky) * inv_dir_z; isect_precalc->Sz = inv_dir_z; From 064caae7b2943aa35953642fd4b15d0e9ec05a87 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 14:47:34 +0200 Subject: [PATCH 034/590] Cycles: BVH-related SSE optimization Several ideas here: - Optimize calculation of near_{x,y,z} in a way that does not require 3 if() statements per update, which avoids negative effect of wrong branch prediction. - Optimization of direction clamping for BVH. - Optimization of point/direction transform. Brings ~1.5% speedup again depending on a scene (unfortunately, this speedup can't be sum across all previous commits because speedup of each of the changes varies from scene to scene, but it still seems to be nice solid speedup of few percent on Linux and bigger speedup was reported on Windows). Once again ,thanks Maxym for inspiration! Still TODO: We have multiple places where we need to calculate near x,y,z indices in BVH, for now it's only done for main BVH traversal. Will try to move this calculation to an utility function and see if that can be easily re-used across all the BVH flavors. --- intern/cycles/kernel/bvh/qbvh_traversal.h | 46 +++++++++++++++++++++++ intern/cycles/kernel/geom/geom_object.h | 19 +++++++++- intern/cycles/util/util_transform.h | 35 +++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h index a1e154d6dcf..b9da539306b 100644 --- a/intern/cycles/kernel/bvh/qbvh_traversal.h +++ b/intern/cycles/kernel/bvh/qbvh_traversal.h @@ -100,12 +100,27 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #endif /* Offsets to select the side that becomes the lower or upper bound. */ +#ifdef __KERNEL_SSE__ + int near_x = 0, near_y = 2, near_z = 4; + int far_x = 1, far_y = 3, far_z = 5; + + const size_t mask = movemask(ssef(idir.m128)); + + const int mask_x = mask & 1; + const int mask_y = (mask & 2) >> 1; + const int mask_z = (mask & 4) >> 2; + + near_x += mask_x; far_x -= mask_x; + near_y += mask_y; far_y -= mask_y; + near_z += mask_z; far_z -= mask_z; +#else int near_x, near_y, near_z; int far_x, far_y, far_z; if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } +#endif IsectPrecalc isect_precalc; triangle_intersect_precalc(dir, &isect_precalc); @@ -427,9 +442,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &node_dist); # endif +#ifdef __KERNEL_SSE__ + near_x = 0; near_y = 2; near_z = 4; + far_x = 1; far_y = 3; far_z = 5; + + const size_t mask = movemask(ssef(idir.m128)); + + const int mask_x = mask & 1; + const int mask_y = (mask & 2) >> 1; + const int mask_z = (mask & 4) >> 2; + + near_x += mask_x; far_x -= mask_x; + near_y += mask_y; far_y -= mask_y; + near_z += mask_z; far_z -= mask_z; +#else if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } +#endif tfar = ssef(isect->t); # if BVH_FEATURE(BVH_HAIR) dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); @@ -469,9 +499,25 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t); # endif +#ifdef __KERNEL_SSE__ + near_x = 0; near_y = 2; near_z = 4; + far_x = 1; far_y = 3; far_z = 5; + + const size_t mask = movemask(ssef(idir.m128)); + + const int mask_x = mask & 1; + const int mask_y = (mask & 2) >> 1; + const int mask_z = (mask & 4) >> 2; + + near_x += mask_x; far_x -= mask_x; + near_y += mask_y; far_y -= mask_y; + near_z += mask_z; far_z -= mask_z; +#else if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } +#endif + tfar = ssef(isect->t); # if BVH_FEATURE(BVH_HAIR) dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index c2ec774362a..0e0932512e9 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -376,15 +376,32 @@ ccl_device float3 particle_angular_velocity(KernelGlobals *kg, int particle) ccl_device_inline float3 bvh_clamp_direction(float3 dir) { /* clamp absolute values by exp2f(-80.0f) to avoid division by zero when calculating inverse direction */ - float ooeps = 8.271806E-25f; +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) + const ssef oopes(8.271806E-25f,8.271806E-25f,8.271806E-25f,0.0f); + const ssef mask = _mm_cmpgt_ps(fabs(dir),oopes); + const ssef signdir = signmsk(dir.m128) | oopes; +# ifndef __KERNEL_AVX__ + ssef res = mask & dir; + res = _mm_or_ps(res,_mm_andnot_ps(mask, signdir)); +# else + ssef res = _mm_blendv_ps(signdir,dir,mask); +# endif + return float3(res); +#else /* __KERNEL_SSE__ && __KERNEL_SSE2__ */ + const float ooeps = 8.271806E-25f; return make_float3((fabsf(dir.x) > ooeps)? dir.x: copysignf(ooeps, dir.x), (fabsf(dir.y) > ooeps)? dir.y: copysignf(ooeps, dir.y), (fabsf(dir.z) > ooeps)? dir.z: copysignf(ooeps, dir.z)); +#endif /* __KERNEL_SSE__ && __KERNEL_SSE2__ */ } ccl_device_inline float3 bvh_inverse_direction(float3 dir) { +#ifdef __KERNEL_SSE__ + return rcp(dir); +#else return 1.0f / dir; +#endif } /* Transform ray into object space to enter static object in BVH */ diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index bfc8f55feed..771a9442cb3 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -73,22 +73,57 @@ ccl_device_inline float3 transform_perspective(const Transform *t, const float3 ccl_device_inline float3 transform_point(const Transform *t, const float3 a) { +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) + ssef x, y, z, w, aa; + aa = a.m128; + + x = _mm_loadu_ps(&t->x.x); + y = _mm_loadu_ps(&t->y.x); + z = _mm_loadu_ps(&t->z.x); + w = _mm_loadu_ps(&t->w.x); + + _MM_TRANSPOSE4_PS(x, y, z, w); + + ssef tmp = madd(x, shuffle<0>(aa), w); + tmp = madd(y, shuffle<1>(aa), tmp); + tmp = madd(z, shuffle<2>(aa), tmp); + + return float3(tmp.m128); +#else float3 c = make_float3( a.x*t->x.x + a.y*t->x.y + a.z*t->x.z + t->x.w, a.x*t->y.x + a.y*t->y.y + a.z*t->y.z + t->y.w, a.x*t->z.x + a.y*t->z.y + a.z*t->z.z + t->z.w); return c; +#endif } ccl_device_inline float3 transform_direction(const Transform *t, const float3 a) { +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) + ssef x, y, z, w, aa; + aa = a.m128; + x = _mm_loadu_ps(&t->x.x); + y = _mm_loadu_ps(&t->y.x); + z = _mm_loadu_ps(&t->z.x); + w = _mm_setzero_ps(); + + _MM_TRANSPOSE4_PS(x, y, z, w); + + ssef tmp = x * shuffle<0>(aa); + tmp = madd(y, shuffle<1>(aa), tmp); + tmp = madd(z, shuffle<2>(aa), tmp); + + return float3(tmp.m128); +#else float3 c = make_float3( a.x*t->x.x + a.y*t->x.y + a.z*t->x.z, a.x*t->y.x + a.y*t->y.y + a.z*t->y.z, a.x*t->z.x + a.y*t->z.y + a.z*t->z.z); return c; +#endif } ccl_device_inline float3 transform_direction_transposed(const Transform *t, const float3 a) From f7cf2f659afc97cf4d4a8603d4dcafb97031ba79 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 15:08:33 +0200 Subject: [PATCH 035/590] Cycles: Move QBVH near/far offset calculation to an utility function Just preparing for new optimization to be used in all traversal implementation. Should be no measurable difference. --- intern/cycles/kernel/bvh/qbvh_nodes.h | 30 +++++++++++ intern/cycles/kernel/bvh/qbvh_traversal.h | 65 ++++------------------- 2 files changed, 39 insertions(+), 56 deletions(-) diff --git a/intern/cycles/kernel/bvh/qbvh_nodes.h b/intern/cycles/kernel/bvh/qbvh_nodes.h index 2ee2a393e80..6d22f0b0d6a 100644 --- a/intern/cycles/kernel/bvh/qbvh_nodes.h +++ b/intern/cycles/kernel/bvh/qbvh_nodes.h @@ -21,6 +21,36 @@ struct QBVHStackItem { float dist; }; +ccl_device_inline void qbvh_near_far_idx_calc(const float3& idir, + int *ccl_restrict near_x, + int *ccl_restrict near_y, + int *ccl_restrict near_z, + int *ccl_restrict far_x, + int *ccl_restrict far_y, + int *ccl_restrict far_z) + +{ +#ifdef __KERNEL_SSE__ + *near_x = 0; *far_x = 1; + *near_y = 2; *far_y = 3; + *near_z = 4; *far_z = 5; + + const size_t mask = movemask(ssef(idir.m128)); + + const int mask_x = mask & 1; + const int mask_y = (mask & 2) >> 1; + const int mask_z = (mask & 4) >> 2; + + *near_x += mask_x; *far_x -= mask_x; + *near_y += mask_y; *far_y -= mask_y; + *near_z += mask_z; *far_z -= mask_z; +#else + if(idir.x >= 0.0f) { *near_x = 0; *far_x = 1; } else { *near_x = 1; *far_x = 0; } + if(idir.y >= 0.0f) { *near_y = 2; *far_y = 3; } else { *near_y = 3; *far_y = 2; } + if(idir.z >= 0.0f) { *near_z = 4; *far_z = 5; } else { *near_z = 5; *far_z = 4; } +#endif +} + /* TOOD(sergey): Investigate if using intrinsics helps for both * stack item swap and float comparison. */ diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h index b9da539306b..f2d8e558dcc 100644 --- a/intern/cycles/kernel/bvh/qbvh_traversal.h +++ b/intern/cycles/kernel/bvh/qbvh_traversal.h @@ -100,27 +100,11 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #endif /* Offsets to select the side that becomes the lower or upper bound. */ -#ifdef __KERNEL_SSE__ - int near_x = 0, near_y = 2, near_z = 4; - int far_x = 1, far_y = 3, far_z = 5; - - const size_t mask = movemask(ssef(idir.m128)); - - const int mask_x = mask & 1; - const int mask_y = (mask & 2) >> 1; - const int mask_z = (mask & 4) >> 2; - - near_x += mask_x; far_x -= mask_x; - near_y += mask_y; far_y -= mask_y; - near_z += mask_z; far_z -= mask_z; -#else int near_x, near_y, near_z; int far_x, far_y, far_z; - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } -#endif + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); IsectPrecalc isect_precalc; triangle_intersect_precalc(dir, &isect_precalc); @@ -442,24 +426,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &node_dist); # endif -#ifdef __KERNEL_SSE__ - near_x = 0; near_y = 2; near_z = 4; - far_x = 1; far_y = 3; far_z = 5; - - const size_t mask = movemask(ssef(idir.m128)); - - const int mask_x = mask & 1; - const int mask_y = (mask & 2) >> 1; - const int mask_z = (mask & 4) >> 2; - - near_x += mask_x; far_x -= mask_x; - near_y += mask_y; far_y -= mask_y; - near_z += mask_z; far_z -= mask_z; -#else - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } -#endif + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); tfar = ssef(isect->t); # if BVH_FEATURE(BVH_HAIR) dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); @@ -499,25 +468,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t); # endif -#ifdef __KERNEL_SSE__ - near_x = 0; near_y = 2; near_z = 4; - far_x = 1; far_y = 3; far_z = 5; - - const size_t mask = movemask(ssef(idir.m128)); - - const int mask_x = mask & 1; - const int mask_y = (mask & 2) >> 1; - const int mask_z = (mask & 4) >> 2; - - near_x += mask_x; far_x -= mask_x; - near_y += mask_y; far_y -= mask_y; - near_z += mask_z; far_z -= mask_z; -#else - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } -#endif - + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); tfar = ssef(isect->t); # if BVH_FEATURE(BVH_HAIR) dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); From 8c761ff83883248780c61a83dbc194f0ec080bed Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 15:27:50 +0200 Subject: [PATCH 036/590] Cycles: Use new SSE version of offset calculation for all QBVH flavors Gives up to ~1% speedup again. While it seems to be small, still nice since the code now is actually more clean that it used to be before. --- intern/cycles/kernel/bvh/qbvh_shadow_all.h | 19 +++++++++---------- intern/cycles/kernel/bvh/qbvh_subsurface.h | 7 +++---- intern/cycles/kernel/bvh/qbvh_volume.h | 19 +++++++++---------- intern/cycles/kernel/bvh/qbvh_volume_all.h | 19 +++++++++---------- 4 files changed, 30 insertions(+), 34 deletions(-) diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index ae7aec2082f..5f4d06f12ea 100644 --- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -92,10 +92,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Offsets to select the side that becomes the lower or upper bound. */ int near_x, near_y, near_z; int far_x, far_y, far_z; - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); IsectPrecalc isect_precalc; triangle_intersect_precalc(dir, &isect_precalc); @@ -392,9 +391,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, num_hits_in_instance = 0; isect_array->t = isect_t; - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); tfar = ssef(isect_t); # if BVH_FEATURE(BVH_HAIR) dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); @@ -450,9 +449,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, isect_t = tmax; isect_array->t = isect_t; - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); tfar = ssef(isect_t); # if BVH_FEATURE(BVH_HAIR) dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); diff --git a/intern/cycles/kernel/bvh/qbvh_subsurface.h b/intern/cycles/kernel/bvh/qbvh_subsurface.h index 24aca96a298..ccd36df034a 100644 --- a/intern/cycles/kernel/bvh/qbvh_subsurface.h +++ b/intern/cycles/kernel/bvh/qbvh_subsurface.h @@ -101,10 +101,9 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Offsets to select the side that becomes the lower or upper bound. */ int near_x, near_y, near_z; int far_x, far_y, far_z; - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); IsectPrecalc isect_precalc; triangle_intersect_precalc(dir, &isect_precalc); diff --git a/intern/cycles/kernel/bvh/qbvh_volume.h b/intern/cycles/kernel/bvh/qbvh_volume.h index db9779351d2..424710b69f2 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume.h +++ b/intern/cycles/kernel/bvh/qbvh_volume.h @@ -87,10 +87,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Offsets to select the side that becomes the lower or upper bound. */ int near_x, near_y, near_z; int far_x, far_y, far_z; - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); IsectPrecalc isect_precalc; triangle_intersect_precalc(dir, &isect_precalc); @@ -303,9 +302,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t); # endif - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); tfar = ssef(isect->t); # if BVH_FEATURE(BVH_HAIR) dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); @@ -349,9 +348,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t); # endif - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); tfar = ssef(isect->t); # if BVH_FEATURE(BVH_HAIR) dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); diff --git a/intern/cycles/kernel/bvh/qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h index 88f1f764e4c..eb48af6fc68 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume_all.h +++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h @@ -91,10 +91,9 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Offsets to select the side that becomes the lower or upper bound. */ int near_x, near_y, near_z; int far_x, far_y, far_z; - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); IsectPrecalc isect_precalc; triangle_intersect_precalc(dir, &isect_precalc); @@ -354,9 +353,9 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, bvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect_t); # endif - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); tfar = ssef(isect_t); idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # if BVH_FEATURE(BVH_HAIR) @@ -420,9 +419,9 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, isect_t = tmax; isect_array->t = isect_t; - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + qbvh_near_far_idx_calc(idir, + &near_x, &near_y, &near_z, + &far_x, &far_y, &far_z); tfar = ssef(isect_t); # if BVH_FEATURE(BVH_HAIR) dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); From c54381488bd6066b2b9c66d6a570c8b181c80216 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 16:10:47 +0200 Subject: [PATCH 037/590] Cycles: Enable SSE math optimization for AVX kernels This gives about 5% speedup for AVX processors. Benefit of such optimization on other microarchitectures is still under investigation. --- intern/cycles/kernel/kernels/cpu/kernel.cpp | 1 + intern/cycles/kernel/kernels/cpu/kernel_avx.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp index 1559b0d7322..72dbbd9a416 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp @@ -42,6 +42,7 @@ # define __KERNEL_SSE41__ # endif # ifdef __AVX__ +# define __KERNEL_SSE__ # define __KERNEL_AVX__ # endif # ifdef __AVX2__ diff --git a/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp b/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp index 533ab46b741..1350d9e5c2e 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel_avx.cpp @@ -20,6 +20,7 @@ /* SSE optimization disabled for now on 32 bit, see bug #36316 */ #if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86))) +# define __KERNEL_SSE__ # define __KERNEL_SSE2__ # define __KERNEL_SSE3__ # define __KERNEL_SSSE3__ From 42a91f7ad85b6f1ebfc2db18d3a455037d3faf87 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 16:53:13 +0200 Subject: [PATCH 038/590] Partial fix for T49836: Camera DOF properties not updating via graph editor Do this for the new dependency graph: was missing handle of OB_UPDATE_TIME in tag update. Hopefully it's all correct still. Old dependency graph needs work, but i'm tempting to call it unsupported and move on to 2.8 branch. --- source/blender/depsgraph/intern/depsgraph_tag.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index b7b62bd59f9..4f27dab258d 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -235,6 +235,9 @@ void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag) if (flag & (OB_RECALC_OB | OB_RECALC_DATA)) { DEG_graph_id_tag_update(bmain, graph, id); } + else if (flag & OB_RECALC_TIME) { + DEG_graph_id_tag_update(bmain, graph, id); + } } } From cf9a6b416c91e1495639220594aa39de7a2205a4 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Tue, 25 Oct 2016 17:32:58 +0200 Subject: [PATCH 039/590] API: Fix Links Self-explanatory. to find broken links run `sphinx-build -b linkcheck sphinx-in sphinx-out` Reviewers: mont29 Tags: #bf_blender, #python, #infrastructure:_websites Differential Revision: https://developer.blender.org/D2297 --- .../mystery_of_the_blend.html | 2 +- doc/doxygen/Doxyfile | 6 +- .../examples/bpy.app.translations.py | 4 +- doc/python_api/examples/mathutils.Vector.py | 2 +- doc/python_api/rst/bgl.rst | 304 +++++++++--------- doc/python_api/rst/include__bmesh.rst | 7 +- doc/python_api/rst/info_best_practice.rst | 4 +- doc/python_api/rst/info_gotcha.rst | 11 +- doc/python_api/rst/info_overview.rst | 5 +- doc/python_api/rst/info_quickstart.rst | 3 +- doc/python_api/rst/info_tips_and_tricks.rst | 4 +- doc/python_api/rst/info_tutorial_addon.rst | 4 +- intern/audaspace/Python/AUD_PyAPI.cpp | 2 +- .../blenkernel/intern/particle_child.c | 2 +- .../blenkernel/intern/particle_system.c | 2 +- source/blender/blenlib/intern/BLI_ghash.c | 2 +- source/blender/blenlib/intern/astar.c | 2 +- .../blenlib/intern/math_color_inline.c | 2 +- source/blender/blenlib/intern/path_util.c | 2 +- source/blender/blenlib/intern/smallhash.c | 2 +- .../operations/COM_SunBeamsOperation.cpp | 4 +- .../intern/builder/deg_builder_transitive.cc | 2 +- source/blender/physics/intern/hair_volume.cpp | 4 +- .../python/mathutils/mathutils_Matrix.c | 12 +- 24 files changed, 195 insertions(+), 199 deletions(-) diff --git a/doc/blender_file_format/mystery_of_the_blend.html b/doc/blender_file_format/mystery_of_the_blend.html index b34493ffa3e..599cb4a05bc 100644 --- a/doc/blender_file_format/mystery_of_the_blend.html +++ b/doc/blender_file_format/mystery_of_the_blend.html @@ -187,7 +187,7 @@ The next table describes the information in the file-header.

-Endianness addresses the way values are ordered in a sequence of bytes(see the example below): +Endianness addresses the way values are ordered in a sequence of bytes(see the example below):

    diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index 9834cda43bc..8b3a97816ba 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -699,7 +699,7 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. @@ -1145,7 +1145,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1752,7 +1752,7 @@ LATEX_SOURCE_CODE = NO # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. diff --git a/doc/python_api/examples/bpy.app.translations.py b/doc/python_api/examples/bpy.app.translations.py index 41b024a4d2b..e41623d2885 100644 --- a/doc/python_api/examples/bpy.app.translations.py +++ b/doc/python_api/examples/bpy.app.translations.py @@ -24,8 +24,8 @@ Then, call ``bpy.app.translations.register(__name__, your_dict)`` in your ``regi The ``Manage UI translations`` add-on has several functions to help you collect strings to translate, and generate the needed python code (the translation dictionary), as well as optional intermediary po files if you want some... See -`How to Translate Blender `_ and -`Using i18n in Blender Code `_ +`How to Translate Blender `_ and +`Using i18n in Blender Code `_ for more info. Module References diff --git a/doc/python_api/examples/mathutils.Vector.py b/doc/python_api/examples/mathutils.Vector.py index 3f79fdebff1..a8db4aa6691 100644 --- a/doc/python_api/examples/mathutils.Vector.py +++ b/doc/python_api/examples/mathutils.Vector.py @@ -49,7 +49,7 @@ vec2d[:] = vec3d[:2] # Vectors support 'swizzle' operations -# See http://en.wikipedia.org/wiki/Swizzling_(computer_graphics) +# See https://en.wikipedia.org/wiki/Swizzling_(computer_graphics) vec.xyz = vec.zyx vec.xy = vec4d.zw vec.xyz = vec4d.wzz diff --git a/doc/python_api/rst/bgl.rst b/doc/python_api/rst/bgl.rst index 36e07a17cdc..99f481ce998 100644 --- a/doc/python_api/rst/bgl.rst +++ b/doc/python_api/rst/bgl.rst @@ -12,10 +12,10 @@ contents: dir(bgl). A simple search on the web can point to more than enough material to teach OpenGL programming, from books to many collections of tutorials. -Here is a comprehensive `list of books `__ (non free). -The `arcsynthesis tutorials `__ +Here is a comprehensive `list of books `__ (non free). +The `arcsynthesis tutorials `__ is one of the best resources to learn modern OpenGL and -`g-truc `__ +`g-truc `__ offers a set of extensive examples, including advanced features. @@ -30,7 +30,7 @@ offers a set of extensive examples, including advanced features. Operate on the accumulation buffer. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type op: Enumerated constant :arg op: The accumulation buffer operation. @@ -42,7 +42,7 @@ offers a set of extensive examples, including advanced features. Specify the alpha test function. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type func: Enumerated constant :arg func: Specifies the alpha comparison function. @@ -55,7 +55,7 @@ offers a set of extensive examples, including advanced features. Determine if textures are loaded in texture memory - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type n: int :arg n: Specifies the number of textures to be queried. @@ -71,7 +71,7 @@ offers a set of extensive examples, including advanced features. Delimit the vertices of a primitive or a group of like primatives - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mode: Enumerated constant :arg mode: Specifies the primitive that will be create from vertices between @@ -82,7 +82,7 @@ offers a set of extensive examples, including advanced features. Bind a named texture to a texturing target - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies the target to which the texture is bound. @@ -94,7 +94,7 @@ offers a set of extensive examples, including advanced features. Draw a bitmap - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type width, height: int :arg width, height: Specify the pixel width and height of the bitmap image. @@ -112,7 +112,7 @@ offers a set of extensive examples, including advanced features. Specify pixel arithmetic - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type sfactor: Enumerated constant :arg sfactor: Specifies how the red, green, blue, and alpha source blending factors are @@ -126,7 +126,7 @@ offers a set of extensive examples, including advanced features. Execute a display list - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type list: unsigned int :arg list: Specifies the integer name of the display list to be executed. @@ -136,7 +136,7 @@ offers a set of extensive examples, including advanced features. Execute a list of display lists - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type n: int :arg n: Specifies the number of display lists to be executed. @@ -152,7 +152,7 @@ offers a set of extensive examples, including advanced features. Clear buffers to preset values - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mask: Enumerated constant(s) :arg mask: Bitwise OR of masks that indicate the buffers to be cleared. @@ -162,7 +162,7 @@ offers a set of extensive examples, including advanced features. Specify clear values for the accumulation buffer - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type red, green, blue, alpha: float :arg red, green, blue, alpha: Specify the red, green, blue, and alpha values used when the @@ -173,7 +173,7 @@ offers a set of extensive examples, including advanced features. Specify clear values for the color buffers - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type red, green, blue, alpha: float :arg red, green, blue, alpha: Specify the red, green, blue, and alpha values used when the @@ -184,7 +184,7 @@ offers a set of extensive examples, including advanced features. Specify the clear value for the depth buffer - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type depth: int :arg depth: Specifies the depth value used when the depth buffer is cleared. @@ -195,7 +195,7 @@ offers a set of extensive examples, including advanced features. Specify the clear value for the color index buffers - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type c: float :arg c: Specifies the index used when the color index buffers are cleared. @@ -206,7 +206,7 @@ offers a set of extensive examples, including advanced features. Specify the clear value for the stencil buffer - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type s: int :arg s: Specifies the index used when the stencil buffer is cleared. The initial value is 0. @@ -216,7 +216,7 @@ offers a set of extensive examples, including advanced features. Specify a plane against which all geometry is clipped - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type plane: Enumerated constant :arg plane: Specifies which clipping plane is being positioned. @@ -235,7 +235,7 @@ offers a set of extensive examples, including advanced features. Set a new color. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type red, green, blue, alpha: Depends on function prototype. :arg red, green, blue: Specify new red, green, and blue values for the current color. @@ -247,7 +247,7 @@ offers a set of extensive examples, including advanced features. Enable and disable writing of frame buffer color components - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type red, green, blue, alpha: int (boolean) :arg red, green, blue, alpha: Specify whether red, green, blue, and alpha can or cannot be @@ -259,7 +259,7 @@ offers a set of extensive examples, including advanced features. Cause a material color to track the current color - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type face: Enumerated constant :arg face: Specifies whether front, back, or both front and back material parameters should @@ -272,7 +272,7 @@ offers a set of extensive examples, including advanced features. Copy pixels in the frame buffer - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type x, y: int :arg x, y: Specify the window coordinates of the lower left corner of the rectangular @@ -288,7 +288,7 @@ offers a set of extensive examples, including advanced features. Copy pixels into a 2D texture image - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies the target texture. @@ -317,7 +317,7 @@ offers a set of extensive examples, including advanced features. Specify whether front- or back-facing facets can be culled - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mode: Enumerated constant :arg mode: Specifies whether front- or back-facing facets are candidates for culling. @@ -327,7 +327,7 @@ offers a set of extensive examples, including advanced features. Delete a contiguous group of display lists - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type list: unsigned int :arg list: Specifies the integer name of the first display list to delete @@ -339,7 +339,7 @@ offers a set of extensive examples, including advanced features. Delete named textures - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type n: int :arg n: Specifies the number of textures to be deleted @@ -351,7 +351,7 @@ offers a set of extensive examples, including advanced features. Specify the value used for depth buffer comparisons - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type func: Enumerated constant :arg func: Specifies the depth comparison function. @@ -361,7 +361,7 @@ offers a set of extensive examples, including advanced features. Enable or disable writing into the depth buffer - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type flag: int (boolean) :arg flag: Specifies whether the depth buffer is enabled for writing. If flag is GL_FALSE, @@ -373,7 +373,7 @@ offers a set of extensive examples, including advanced features. Specify mapping of depth values from normalized device coordinates to window coordinates - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type zNear: int :arg zNear: Specifies the mapping of the near clipping plane to window coordinates. @@ -387,7 +387,7 @@ offers a set of extensive examples, including advanced features. Disable server-side GL capabilities - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type cap: Enumerated constant :arg cap: Specifies a symbolic constant indicating a GL capability. @@ -397,7 +397,7 @@ offers a set of extensive examples, including advanced features. Specify which color buffers are to be drawn into - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mode: Enumerated constant :arg mode: Specifies up to four color buffers to be drawn into. @@ -407,7 +407,7 @@ offers a set of extensive examples, including advanced features. Write a block of pixels to the frame buffer - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type width, height: int :arg width, height: Specify the dimensions of the pixel rectangle to be @@ -426,7 +426,7 @@ offers a set of extensive examples, including advanced features. Flag edges as either boundary or non-boundary - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type flag: Depends of function prototype :arg flag: Specifies the current edge flag value.The initial value is GL_TRUE. @@ -436,7 +436,7 @@ offers a set of extensive examples, including advanced features. Enable server-side GL capabilities - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type cap: Enumerated constant :arg cap: Specifies a symbolic constant indicating a GL capability. @@ -446,14 +446,14 @@ offers a set of extensive examples, including advanced features. Delimit the vertices of a primitive or group of like primitives - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glEndList(): Create or replace a display list - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glEvalCoord (u,v): @@ -463,7 +463,7 @@ offers a set of extensive examples, including advanced features. Evaluate enabled one- and two-dimensional maps - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type u: Depends on function prototype. :arg u: Specifies a value that is the domain coordinate u to the basis function defined @@ -481,7 +481,7 @@ offers a set of extensive examples, including advanced features. Compute a one- or two-dimensional grid of points or lines - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mode: Enumerated constant :arg mode: In glEvalMesh1, specifies whether to compute a one-dimensional @@ -496,7 +496,7 @@ offers a set of extensive examples, including advanced features. Generate and evaluate a single point in a mesh - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type i: int :arg i: Specifies the integer value for grid domain variable i. @@ -508,7 +508,7 @@ offers a set of extensive examples, including advanced features. Controls feedback mode - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type size: int :arg size: Specifies the maximum number of values that can be written into buffer. @@ -523,14 +523,14 @@ offers a set of extensive examples, including advanced features. Block until all GL execution is complete - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glFlush(): Force Execution of GL commands in finite time - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glFog (pname, param): @@ -539,7 +539,7 @@ offers a set of extensive examples, including advanced features. Specify fog parameters - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type pname: Enumerated constant :arg pname: Specifies a single-valued fog parameter. If the function prototype @@ -554,7 +554,7 @@ offers a set of extensive examples, including advanced features. Define front- and back-facing polygons - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mode: Enumerated constant :arg mode: Specifies the orientation of front-facing polygons. @@ -564,7 +564,7 @@ offers a set of extensive examples, including advanced features. Multiply the current matrix by a perspective matrix - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type left, right: double (float) :arg left, right: Specify the coordinates for the left and right vertical @@ -581,7 +581,7 @@ offers a set of extensive examples, including advanced features. Generate a contiguous set of empty display lists - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type range: int :arg range: Specifies the number of contiguous empty display lists to be generated. @@ -591,7 +591,7 @@ offers a set of extensive examples, including advanced features. Generate texture names - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type n: int :arg n: Specifies the number of textures name to be generated. @@ -605,7 +605,7 @@ offers a set of extensive examples, including advanced features. Return the value or values of a selected parameter - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type pname: Enumerated constant :arg pname: Specifies the parameter value to be returned. @@ -617,7 +617,7 @@ offers a set of extensive examples, including advanced features. Return the coefficients of the specified clipping plane - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type plane: Enumerated constant :arg plane: Specifies a clipping plane. The number of clipping planes depends on the @@ -632,7 +632,7 @@ offers a set of extensive examples, including advanced features. Return error information - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glGetLight (light, pname, params): @@ -641,7 +641,7 @@ offers a set of extensive examples, including advanced features. Return light source parameter values - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type light: Enumerated constant :arg light: Specifies a light source. The number of possible lights depends on the @@ -659,7 +659,7 @@ offers a set of extensive examples, including advanced features. Return evaluator parameters - .. seealso:: `OpenGL Docs `_ + .. seealso:: `OpenGL Docs `_ :type target: Enumerated constant :arg target: Specifies the symbolic name of a map. @@ -675,7 +675,7 @@ offers a set of extensive examples, including advanced features. Return material parameters - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type face: Enumerated constant :arg face: Specifies which of the two materials is being queried. @@ -692,7 +692,7 @@ offers a set of extensive examples, including advanced features. Return the specified pixel map - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type map: Enumerated constant :arg map: Specifies the name of the pixel map to return. @@ -704,7 +704,7 @@ offers a set of extensive examples, including advanced features. Return the polygon stipple pattern - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mask: :class:`bgl.Buffer` object I{type GL_BYTE} :arg mask: Returns the stipple pattern. The initial value is all 1's. @@ -714,7 +714,7 @@ offers a set of extensive examples, including advanced features. Return a string describing the current GL connection - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type name: Enumerated constant :arg name: Specifies a symbolic constant. @@ -727,7 +727,7 @@ offers a set of extensive examples, including advanced features. Return texture environment parameters - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies a texture environment. Must be GL_TEXTURE_ENV. @@ -743,7 +743,7 @@ offers a set of extensive examples, including advanced features. Return texture coordinate generation parameters - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type coord: Enumerated constant :arg coord: Specifies a texture coordinate. @@ -757,7 +757,7 @@ offers a set of extensive examples, including advanced features. Return a texture image - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies which texture is to be obtained. @@ -779,7 +779,7 @@ offers a set of extensive examples, including advanced features. return texture parameter values for a specific level of detail - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies the symbolic name of the target texture. @@ -798,7 +798,7 @@ offers a set of extensive examples, including advanced features. Return texture parameter values - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies the symbolic name of the target texture. @@ -812,7 +812,7 @@ offers a set of extensive examples, including advanced features. Specify implementation-specific hints - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies a symbolic constant indicating the behavior to be @@ -827,7 +827,7 @@ offers a set of extensive examples, including advanced features. Set the current color index - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type c: :class:`bgl.Buffer` object. Depends on function prototype. :arg c: Specifies a pointer to a one element array that contains the new value for @@ -838,7 +838,7 @@ offers a set of extensive examples, including advanced features. Control the writing of individual bits in the color index buffers - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mask: int :arg mask: Specifies a bit mask to enable and disable the writing of individual bits @@ -850,14 +850,14 @@ offers a set of extensive examples, including advanced features. Initialize the name stack - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glIsEnabled(cap): Test whether a capability is enabled - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type cap: Enumerated constant :arg cap: Specifies a constant representing a GL capability. @@ -867,7 +867,7 @@ offers a set of extensive examples, including advanced features. Determine if a name corresponds to a display-list - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type list: unsigned int :arg list: Specifies a potential display-list name. @@ -877,7 +877,7 @@ offers a set of extensive examples, including advanced features. Determine if a name corresponds to a texture - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type texture: unsigned int :arg texture: Specifies a value that may be the name of a texture. @@ -889,7 +889,7 @@ offers a set of extensive examples, including advanced features. Set the light source parameters - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type light: Enumerated constant :arg light: Specifies a light. The number of lights depends on the implementation, @@ -909,7 +909,7 @@ offers a set of extensive examples, including advanced features. Set the lighting model parameters - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type pname: Enumerated constant :arg pname: Specifies a single-value light model parameter. @@ -922,7 +922,7 @@ offers a set of extensive examples, including advanced features. Specify the line stipple pattern - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type factor: int :arg factor: Specifies a multiplier for each bit in the line stipple pattern. @@ -939,7 +939,7 @@ offers a set of extensive examples, including advanced features. Specify the width of rasterized lines. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type width: float :arg width: Specifies the width of rasterized lines. The initial value is 1. @@ -949,7 +949,7 @@ offers a set of extensive examples, including advanced features. Set the display-list base for glCallLists - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type base: unsigned int :arg base: Specifies an integer offset that will be added to glCallLists @@ -960,7 +960,7 @@ offers a set of extensive examples, including advanced features. Replace the current matrix with the identity matrix - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glLoadMatrix (m): @@ -969,7 +969,7 @@ offers a set of extensive examples, including advanced features. Replace the current matrix with the specified matrix - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type m: :class:`bgl.Buffer` object. Depends on function prototype. :arg m: Specifies a pointer to 16 consecutive values, which are used as the elements @@ -980,7 +980,7 @@ offers a set of extensive examples, including advanced features. Load a name onto the name stack. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type name: unsigned int :arg name: Specifies a name that will replace the top value on the name stack. @@ -990,7 +990,7 @@ offers a set of extensive examples, including advanced features. Specify a logical pixel operation for color index rendering - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type opcode: Enumerated constant :arg opcode: Specifies a symbolic constant that selects a logical operation. @@ -1002,7 +1002,7 @@ offers a set of extensive examples, including advanced features. Define a one-dimensional evaluator - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies the kind of values that are generated by the evaluator. @@ -1027,7 +1027,7 @@ offers a set of extensive examples, including advanced features. Define a two-dimensional evaluator - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies the kind of values that are generated by the evaluator. @@ -1068,7 +1068,7 @@ offers a set of extensive examples, including advanced features. Define a one- or two-dimensional mesh - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type un: int :arg un: Specifies the number of partitions in the grid range interval @@ -1087,7 +1087,7 @@ offers a set of extensive examples, including advanced features. Specify material parameters for the lighting model. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type face: Enumerated constant :arg face: Specifies which face or faces are being updated. Must be one of: @@ -1104,7 +1104,7 @@ offers a set of extensive examples, including advanced features. Specify which matrix is the current matrix. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mode: Enumerated constant :arg mode: Specifies which matrix stack is the target for subsequent matrix operations. @@ -1116,7 +1116,7 @@ offers a set of extensive examples, including advanced features. Multiply the current matrix with the specified matrix - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type m: :class:`bgl.Buffer` object. Depends on function prototype. :arg m: Points to 16 consecutive values that are used as the elements of a 4x4 column @@ -1127,7 +1127,7 @@ offers a set of extensive examples, including advanced features. Create or replace a display list - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type list: unsigned int :arg list: Specifies the display list name @@ -1142,7 +1142,7 @@ offers a set of extensive examples, including advanced features. Set the current normal vector - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type nx, ny, nz: Depends on function prototype. (non - 'v' prototypes only) :arg nx, ny, nz: Specify the x, y, and z coordinates of the new current normal. @@ -1156,7 +1156,7 @@ offers a set of extensive examples, including advanced features. Multiply the current matrix with an orthographic matrix - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type left, right: double (float) :arg left, right: Specify the coordinates for the left and @@ -1173,7 +1173,7 @@ offers a set of extensive examples, including advanced features. Place a marker in the feedback buffer - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type token: float :arg token: Specifies a marker value to be placed in the feedback @@ -1186,7 +1186,7 @@ offers a set of extensive examples, including advanced features. Set up pixel transfer maps - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type map: Enumerated constant :arg map: Specifies a symbolic map name. @@ -1202,7 +1202,7 @@ offers a set of extensive examples, including advanced features. Set pixel storage modes - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type pname: Enumerated constant :arg pname: Specifies the symbolic name of the parameter to be set. @@ -1218,7 +1218,7 @@ offers a set of extensive examples, including advanced features. Set pixel transfer modes - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type pname: Enumerated constant :arg pname: Specifies the symbolic name of the pixel transfer parameter to be set. @@ -1230,7 +1230,7 @@ offers a set of extensive examples, including advanced features. Specify the pixel zoom factors - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type xfactor, yfactor: float :arg xfactor, yfactor: Specify the x and y zoom factors for pixel write operations. @@ -1240,7 +1240,7 @@ offers a set of extensive examples, including advanced features. Specify the diameter of rasterized points - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type size: float :arg size: Specifies the diameter of rasterized points. The initial value is 1. @@ -1250,7 +1250,7 @@ offers a set of extensive examples, including advanced features. Select a polygon rasterization mode - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type face: Enumerated constant :arg face: Specifies the polygons that mode applies to. @@ -1265,7 +1265,7 @@ offers a set of extensive examples, including advanced features. Set the scale and units used to calculate depth values - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type factor: float :arg factor: Specifies a scale factor that is used to create a variable depth @@ -1279,7 +1279,7 @@ offers a set of extensive examples, including advanced features. Set the polygon stippling pattern - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mask: :class:`bgl.Buffer` object I{type GL_BYTE} :arg mask: Specifies a pointer to a 32x32 stipple pattern that will be unpacked @@ -1290,35 +1290,35 @@ offers a set of extensive examples, including advanced features. Pop the server attribute stack - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glPopClientAttrib(): Pop the client attribute stack - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glPopMatrix(): Pop the current matrix stack - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glPopName(): Pop the name stack - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glPrioritizeTextures(n, textures, priorities): Set texture residence priority - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type n: int :arg n: Specifies the number of textures to be prioritized. @@ -1334,7 +1334,7 @@ offers a set of extensive examples, including advanced features. Push the server attribute stack - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mask: Enumerated constant(s) :arg mask: Specifies a mask that indicates which attributes to save. @@ -1344,7 +1344,7 @@ offers a set of extensive examples, including advanced features. Push the client attribute stack - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mask: Enumerated constant(s) :arg mask: Specifies a mask that indicates which attributes to save. @@ -1354,14 +1354,14 @@ offers a set of extensive examples, including advanced features. Push the current matrix stack - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ .. function:: glPushName(name): Push the name stack - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type name: unsigned int :arg name: Specifies a name that will be pushed onto the name stack. @@ -1377,7 +1377,7 @@ offers a set of extensive examples, including advanced features. Specify the raster position for pixel operations - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type x, y, z, w: Depends on function prototype. (z and w for '3' and '4' prototypes only) :arg x, y, z, w: Specify the x,y,z, and w object coordinates (if present) for the @@ -1409,7 +1409,7 @@ offers a set of extensive examples, including advanced features. Select a color buffer source for pixels. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mode: Enumerated constant :arg mode: Specifies a color buffer. @@ -1419,7 +1419,7 @@ offers a set of extensive examples, including advanced features. Read a block of pixels from the frame buffer - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type x, y: int :arg x, y: Specify the window coordinates of the first pixel that is read @@ -1442,7 +1442,7 @@ offers a set of extensive examples, including advanced features. Draw a rectangle - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type x1, y1: Depends on function prototype. (for non 'v' prototypes only) :arg x1, y1: Specify one vertex of a rectangle @@ -1457,7 +1457,7 @@ offers a set of extensive examples, including advanced features. Set rasterization mode - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mode: Enumerated constant :arg mode: Specifies the rasterization mode. @@ -1469,7 +1469,7 @@ offers a set of extensive examples, including advanced features. Multiply the current matrix by a rotation matrix - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type angle: Depends on function prototype. :arg angle: Specifies the angle of rotation in degrees. @@ -1483,7 +1483,7 @@ offers a set of extensive examples, including advanced features. Multiply the current matrix by a general scaling matrix - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type x, y, z: Depends on function prototype. :arg x, y, z: Specify scale factors along the x, y, and z axes, respectively. @@ -1493,7 +1493,7 @@ offers a set of extensive examples, including advanced features. Define the scissor box - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type x, y: int :arg x, y: Specify the lower left corner of the scissor box. Initially (0, 0). @@ -1507,7 +1507,7 @@ offers a set of extensive examples, including advanced features. Establish a buffer for selection mode values - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type size: int :arg size: Specifies the size of buffer @@ -1519,7 +1519,7 @@ offers a set of extensive examples, including advanced features. Select flat or smooth shading - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mode: Enumerated constant :arg mode: Specifies a symbolic value representing a shading technique. @@ -1529,7 +1529,7 @@ offers a set of extensive examples, including advanced features. Set function and reference value for stencil testing - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type func: Enumerated constant :arg func: Specifies the test function. @@ -1546,7 +1546,7 @@ offers a set of extensive examples, including advanced features. Control the writing of individual bits in the stencil planes - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type mask: unsigned int :arg mask: Specifies a bit mask to enable and disable writing of individual bits @@ -1557,7 +1557,7 @@ offers a set of extensive examples, including advanced features. Set stencil test actions - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type fail: Enumerated constant :arg fail: Specifies the action to take when the stencil test fails. @@ -1585,7 +1585,7 @@ offers a set of extensive examples, including advanced features. Set the current texture coordinates - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type s, t, r, q: Depends on function prototype. (r and q for '3' and '4' prototypes only) :arg s, t, r, q: Specify s, t, r, and q texture coordinates. Not all parameters are @@ -1601,7 +1601,7 @@ offers a set of extensive examples, including advanced features. Set texture environment parameters - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies a texture environment. Must be GL_TEXTURE_ENV. @@ -1620,7 +1620,7 @@ offers a set of extensive examples, including advanced features. Control the generation of texture coordinates - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type coord: Enumerated constant :arg coord: Specifies a texture coordinate. @@ -1638,7 +1638,7 @@ offers a set of extensive examples, including advanced features. Specify a one-dimensional texture image - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies the target texture. @@ -1665,7 +1665,7 @@ offers a set of extensive examples, including advanced features. Specify a two-dimensional texture image - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies the target texture. @@ -1698,7 +1698,7 @@ offers a set of extensive examples, including advanced features. Set texture parameters - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type target: Enumerated constant :arg target: Specifies the target texture. @@ -1715,7 +1715,7 @@ offers a set of extensive examples, including advanced features. Multiply the current matrix by a translation matrix - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type x, y, z: Depends on function prototype. :arg x, y, z: Specify the x, y, and z coordinates of a translation vector. @@ -1730,7 +1730,7 @@ offers a set of extensive examples, including advanced features. Specify a vertex - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type x, y, z, w: Depends on function prototype (z and w for '3' and '4' prototypes only) :arg x, y, z, w: Specify x, y, z, and w coordinates of a vertex. Not all parameters @@ -1746,7 +1746,7 @@ offers a set of extensive examples, including advanced features. Set the viewport - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type x, y: int :arg x, y: Specify the lower left corner of the viewport rectangle, @@ -1761,7 +1761,7 @@ offers a set of extensive examples, including advanced features. Set up a perspective projection matrix. - .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5577288} + .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml :type fovY: double :arg fovY: Specifies the field of view angle, in degrees, in the y direction. @@ -1778,7 +1778,7 @@ offers a set of extensive examples, including advanced features. Define a viewing transformation. - .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5573042} + .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml :type eyex, eyey, eyez: double :arg eyex, eyey, eyez: Specifies the position of the eye point. @@ -1792,7 +1792,7 @@ offers a set of extensive examples, including advanced features. Define a 2-D orthographic projection matrix. - .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074} + .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluOrtho2D.xml :type left, right: double :arg left, right: Specify the coordinates for the left and right vertical clipping planes. @@ -1804,7 +1804,7 @@ offers a set of extensive examples, including advanced features. Define a picking region. - .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074} + .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluPickMatrix.xml :type x, y: double :arg x, y: Specify the center of a picking region in window coordinates. @@ -1818,7 +1818,7 @@ offers a set of extensive examples, including advanced features. Map object coordinates to window coordinates. - .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5578074} + .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluProject.xml :type objx, objy, objz: double :arg objx, objy, objz: Specify the object coordinates. @@ -1836,7 +1836,7 @@ offers a set of extensive examples, including advanced features. Map object coordinates to window coordinates. - .. seealso:: U{http://biology.ncsa.uiuc.edu/cgi-bin/infosrch.cgi?cmd=getdoc&coll=0650&db=bks&fname=/SGI_Developer/OpenGL_RM/ch06.html#id5582204} + .. seealso:: https://www.opengl.org/sdk/docs/man2/xhtml/gluUnProject.xml :type winx, winy, winz: double :arg winx, winy, winz: Specify the window coordinates to be mapped. @@ -1854,7 +1854,7 @@ offers a set of extensive examples, including advanced features. Installs a program object as part of current rendering state - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type program: int :arg program: Specifies the handle of the program object whose executables are to be used as part of current rendering state. @@ -1864,7 +1864,7 @@ offers a set of extensive examples, including advanced features. Validates a program object - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type program: int :arg program: Specifies the handle of the program object to be validated. @@ -1874,7 +1874,7 @@ offers a set of extensive examples, including advanced features. Links a program object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type program: int :arg program: Specifies the handle of the program object to be linked. @@ -1884,7 +1884,7 @@ offers a set of extensive examples, including advanced features. Select active texture unit. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type texture: int :arg texture: Constant in ``GL_TEXTURE0`` 0 - 8 @@ -1894,7 +1894,7 @@ offers a set of extensive examples, including advanced features. Attaches a shader object to a program object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type program: int :arg program: Specifies the program object to which a shader object will be attached. @@ -1906,7 +1906,7 @@ offers a set of extensive examples, including advanced features. Compiles a shader object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type shader: int :arg shader: Specifies the shader object to be compiled. @@ -1916,7 +1916,7 @@ offers a set of extensive examples, including advanced features. Creates a program object - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :rtype: int :return: The new program or zero if an error occurs. @@ -1926,7 +1926,7 @@ offers a set of extensive examples, including advanced features. Creates a shader object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type shaderType: Specifies the type of shader to be created. Must be one of ``GL_VERTEX_SHADER``, @@ -1943,7 +1943,7 @@ offers a set of extensive examples, including advanced features. Deletes a program object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type program: int :arg program: Specifies the program object to be deleted. @@ -1953,7 +1953,7 @@ offers a set of extensive examples, including advanced features. Deletes a shader object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type shader: int :arg shader: Specifies the shader object to be deleted. @@ -1963,7 +1963,7 @@ offers a set of extensive examples, including advanced features. Detaches a shader object from a program object to which it is attached. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type program: int :arg program: Specifies the program object from which to detach the shader object. @@ -1975,7 +1975,7 @@ offers a set of extensive examples, including advanced features. Returns the handles of the shader objects attached to a program object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type program: int :arg program: Specifies the program object to be queried. @@ -1991,7 +1991,7 @@ offers a set of extensive examples, including advanced features. Returns the information log for a program object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type program: int :arg program: Specifies the program object whose information log is to be queried. @@ -2007,7 +2007,7 @@ offers a set of extensive examples, including advanced features. Returns the information log for a shader object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type shader: int :arg shader: Specifies the shader object whose information log is to be queried. @@ -2023,7 +2023,7 @@ offers a set of extensive examples, including advanced features. Returns a parameter from a program object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type program: int :arg program: Specifies the program object to be queried. @@ -2037,7 +2037,7 @@ offers a set of extensive examples, including advanced features. Determines if a name corresponds to a shader object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type shader: int :arg shader: Specifies a potential shader object. @@ -2047,7 +2047,7 @@ offers a set of extensive examples, including advanced features. Determines if a name corresponds to a program object - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type program: int :arg program: Specifies a potential program object. @@ -2057,7 +2057,7 @@ offers a set of extensive examples, including advanced features. Returns the source code string from a shader object - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type shader: int :arg shader: Specifies the shader object to be queried. @@ -2073,7 +2073,7 @@ offers a set of extensive examples, including advanced features. Replaces the source code in a shader object. - .. seealso:: `OpenGL Docs `__ + .. seealso:: `OpenGL Docs `__ :type shader: int :arg shader: Specifies the handle of the shader object whose source code is to be replaced. diff --git a/doc/python_api/rst/include__bmesh.rst b/doc/python_api/rst/include__bmesh.rst index dc43d2c016e..83e3e73cea4 100644 --- a/doc/python_api/rst/include__bmesh.rst +++ b/doc/python_api/rst/include__bmesh.rst @@ -23,7 +23,7 @@ The features exposed closely follow the C API, giving python access to the functions used by blenders own mesh editing tools. For an overview of BMesh data types and how they reference each other see: -`BMesh Design Document `_ . +`BMesh Design Document `_ . .. note:: @@ -31,13 +31,12 @@ For an overview of BMesh data types and how they reference each other see: **Disk** and **Radial** data is not exposed by the python api since this is for internal use only. -.. warning:: - - TODO items are... +.. warning:: TODO items are... * add access to BMesh **walkers** * add custom-data manipulation functions add/remove/rename. + Example Script -------------- diff --git a/doc/python_api/rst/info_best_practice.rst b/doc/python_api/rst/info_best_practice.rst index 9b95ada2b2c..418f636030c 100644 --- a/doc/python_api/rst/info_best_practice.rst +++ b/doc/python_api/rst/info_best_practice.rst @@ -18,7 +18,7 @@ amongst our own scripts and make it easier to use python scripts from other proj Using our style guide for your own scripts makes it easier if you eventually want to contribute them to blender. -This style guide is known as pep8 and can be found `here `_ +This style guide is known as pep8 and can be found `here `_ A brief listing of pep8 criteria. @@ -316,7 +316,7 @@ use to join a list of strings (the list may be temporary). In the following exam Join is fastest on many strings, -`string formatting `__ +`string formatting `__ is quite fast too (better for converting data types). String arithmetic is slowest. diff --git a/doc/python_api/rst/info_gotcha.rst b/doc/python_api/rst/info_gotcha.rst index 430a862cf7b..2b361d476da 100644 --- a/doc/python_api/rst/info_gotcha.rst +++ b/doc/python_api/rst/info_gotcha.rst @@ -1,3 +1,4 @@ + ******* Gotchas ******* @@ -38,7 +39,6 @@ but some operators are more picky about when they run. In most cases you can figure out what context an operator needs simply be seeing how it's used in Blender and thinking about what it does. - Unfortunately if you're still stuck - the only way to **really** know whats going on is to read the source code for the poll function and see what its checking. @@ -82,7 +82,6 @@ it should be reported to the bug tracker. Stale Data ========== - No updates after setting values ------------------------------- @@ -174,8 +173,8 @@ In this situation you can... .. _info_gotcha_mesh_faces: -NGons and Tessellation Faces -============================ +N-Gons and Tessellation Faces +============================= Since 2.63 NGons are supported, this adds some complexity since in some cases you need to access triangles/quads still (some exporters for example). @@ -509,7 +508,7 @@ Unicode Problems Python supports many different encodings so there is nothing stopping you from writing a script in ``latin1`` or ``iso-8859-15``. -See `pep-0263 `_ +See `pep-0263 `_ However this complicates matters for Blender's Python API because ``.blend`` files don't have an explicit encoding. @@ -657,7 +656,7 @@ Here are some general hints to avoid running into these problems. .. note:: To find the line of your script that crashes you can use the ``faulthandler`` module. - See `faulthandler docs `_. + See the `faulthandler docs `_. While the crash may be in Blenders C/C++ code, this can help a lot to track down the area of the script that causes the crash. diff --git a/doc/python_api/rst/info_overview.rst b/doc/python_api/rst/info_overview.rst index 07c7d5793c2..b4ae906277d 100644 --- a/doc/python_api/rst/info_overview.rst +++ b/doc/python_api/rst/info_overview.rst @@ -43,8 +43,7 @@ scene manipulation, automation, defining your own toolset and customization. On startup Blender scans the ``scripts/startup/`` directory for Python modules and imports them. The exact location of this directory depends on your installation. -`See the directory layout docs -`__ +See the :ref:`directory layout docs `. Script Loading @@ -92,7 +91,7 @@ variable which Blender uses to read metadata such as name, author, category and The User Preferences add-on listing uses **bl_info** to display information about each add-on. -`See Add-ons `__ +`See Add-ons `__ for details on the ``bl_info`` dictionary. diff --git a/doc/python_api/rst/info_quickstart.rst b/doc/python_api/rst/info_quickstart.rst index f0e1bee58e7..7a899e040a6 100644 --- a/doc/python_api/rst/info_quickstart.rst +++ b/doc/python_api/rst/info_quickstart.rst @@ -51,8 +51,7 @@ A quick list of helpful things to know before starting: | ``scripts/startup/bl_operators`` for operators. Exact location depends on platform, see: - `Configuration and Data Paths - `__. + :ref:`Configuration and Data Paths `. Running Scripts diff --git a/doc/python_api/rst/info_tips_and_tricks.rst b/doc/python_api/rst/info_tips_and_tricks.rst index e8928e07671..97bc682894a 100644 --- a/doc/python_api/rst/info_tips_and_tricks.rst +++ b/doc/python_api/rst/info_tips_and_tricks.rst @@ -27,7 +27,7 @@ There are 3 main uses for the terminal, these are: .. note:: - For Linux and OSX users this means starting the terminal first, then running Blender from within it. + For Linux and macOS users this means starting the terminal first, then running Blender from within it. On Windows the terminal can be enabled from the help menu. @@ -306,7 +306,7 @@ Advantages include: This is marked advanced because to run Blender as a Python module requires a special build option. For instructions on building see -`Building Blender as a Python module `_ +`Building Blender as a Python module `_ Python Safety (Build Option) diff --git a/doc/python_api/rst/info_tutorial_addon.rst b/doc/python_api/rst/info_tutorial_addon.rst index 60b4196d6d4..92fbf9b8787 100644 --- a/doc/python_api/rst/info_tutorial_addon.rst +++ b/doc/python_api/rst/info_tutorial_addon.rst @@ -232,7 +232,7 @@ if you want it to be enabled on restart, press *Save as Default*. print(addon_utils.paths()) More is written on this topic here: - `Directory Layout `_ + :ref:`Directory Layout `. Your Second Add-on @@ -630,6 +630,6 @@ Here are some sites you might like to check on after completing this tutorial. *Great info for those who are still learning Python.* - `Blender Development (Wiki) `_ - *Blender Development, general information and helpful links.* -- `Blender Artists (Coding Section) `_ - +- `Blender Artists (Coding Section) `_ - *forum where people ask Python development questions* diff --git a/intern/audaspace/Python/AUD_PyAPI.cpp b/intern/audaspace/Python/AUD_PyAPI.cpp index de5c0a2f463..6d4939bf96c 100644 --- a/intern/audaspace/Python/AUD_PyAPI.cpp +++ b/intern/audaspace/Python/AUD_PyAPI.cpp @@ -2698,7 +2698,7 @@ Device_set_doppler_factor(Device *self, PyObject *args, void* nothing) PyDoc_STRVAR(M_aud_Device_distance_model_doc, "The distance model of the device.\n\n" - ".. seealso:: http://connect.creativelabs.com/openal/Documentation/OpenAL%201.1%20Specification.htm#_Toc199835864"); + ".. seealso:: `OpenAL documentation `"); static PyObject * Device_get_distance_model(Device *self, void* nothing) diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c index ec5f73f87ce..842de869291 100644 --- a/source/blender/blenkernel/intern/particle_child.c +++ b/source/blender/blenkernel/intern/particle_child.c @@ -136,7 +136,7 @@ static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const * * The "density" parameter b is defined by the shape parameter * and goes up to the Golden Spiral for 1.0 - * http://en.wikipedia.org/wiki/Golden_spiral + * https://en.wikipedia.org/wiki/Golden_spiral */ const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f; /* angle of the spiral against the curve (rotated opposite to make a smooth transition) */ diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index efaf1f9df2b..ee435051151 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -2180,7 +2180,7 @@ static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, f * The algorithm is roughly: * 1. Use a BVH tree to search for faces that a particle may collide with. * 2. Use Newton's method to find the exact time at which the collision occurs. - * http://en.wikipedia.org/wiki/Newton's_method + * https://en.wikipedia.org/wiki/Newton's_method * ************************************************/ #define COLLISION_MIN_RADIUS 0.001f diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c index f943a8119c4..944ee18e6b2 100644 --- a/source/blender/blenlib/intern/BLI_ghash.c +++ b/source/blender/blenlib/intern/BLI_ghash.c @@ -1588,7 +1588,7 @@ double BLI_ghash_calc_quality_ex( if (r_variance) { /* We already know our mean (i.e. load factor), easy to compute variance. - * See http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm + * See https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Two-pass_algorithm */ double sum = 0.0; for (i = 0; i < gh->nbuckets; i++) { diff --git a/source/blender/blenlib/intern/astar.c b/source/blender/blenlib/intern/astar.c index 21d974de1c4..0020dbe4612 100644 --- a/source/blender/blenlib/intern/astar.c +++ b/source/blender/blenlib/intern/astar.c @@ -35,7 +35,7 @@ * in addition to distance already walked. This heuristic allows more efficiency * in finding optimal path. * - * Implementation based on Wikipedia A* page [http://en.wikipedia.org/wiki/A*_search_algorithm]. + * Implementation based on Wikipedia A* page [https://en.wikipedia.org/wiki/A*_search_algorithm]. * * Note that most memory handling here is done through two different MemArena's. Those should also be used to allocate * custom data needed to a specific use of A*. diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c index abb8ff35a45..01a805a09b6 100644 --- a/source/blender/blenlib/intern/math_color_inline.c +++ b/source/blender/blenlib/intern/math_color_inline.c @@ -269,7 +269,7 @@ MINLINE void cpack_cpy_3ub(unsigned char r_col[3], const unsigned int pack) /** * ITU-R BT.709 primaries - * http://en.wikipedia.org/wiki/Relative_luminance + * https://en.wikipedia.org/wiki/Relative_luminance * * Real values are: * ``Y = 0.2126390059(R) + 0.7151686788(G) + 0.0721923154(B)`` diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index ded10ad7713..f0d0bd00dea 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -430,7 +430,7 @@ void BLI_cleanup_file(const char *relabase, char *path) * \return true if \a fname was changed, false otherwise. * * For now, simply replaces reserved chars (as listed in - * http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words ) + * https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words ) * by underscores ('_'). * * \note Space case ' ' is a bit of an edge case here - in theory it is allowed, but again can be an issue diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c index 0b976e9612e..ccac221d836 100644 --- a/source/blender/blenlib/intern/smallhash.c +++ b/source/blender/blenlib/intern/smallhash.c @@ -34,7 +34,7 @@ * based on a doubling hashing approach (non-chaining) which uses more buckets then entries * stepping over buckets when two keys share the same hash so any key can find a free bucket. * - * See: http://en.wikipedia.org/wiki/Double_hashing + * See: https://en.wikipedia.org/wiki/Double_hashing * * \warning This should _only_ be used for small hashes where allocating a hash every time is unacceptable. * Otherwise #GHash should be used instead. diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp index a681583809c..70e0b2cfb57 100644 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp @@ -186,8 +186,8 @@ struct BufferLineAccumulator { } /* TODO implement proper filtering here, see - * http://en.wikipedia.org/wiki/Lanczos_resampling - * http://en.wikipedia.org/wiki/Sinc_function + * https://en.wikipedia.org/wiki/Lanczos_resampling + * https://en.wikipedia.org/wiki/Sinc_function * * using lanczos with x = distance from the line segment, * normalized to a == 0.5f, could give a good result diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index 76cd81f1b8f..da71db09f3d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -47,7 +47,7 @@ namespace DEG { /* -------------------------------------------------- */ /* Performs a transitive reduction to remove redundant relations. - * http://en.wikipedia.org/wiki/Transitive_reduction + * https://en.wikipedia.org/wiki/Transitive_reduction * * XXX The current implementation is somewhat naive and has O(V*E) worst case * runtime. diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp index d79cf7d8c31..5cc1231e6cb 100644 --- a/source/blender/physics/intern/hair_volume.cpp +++ b/source/blender/physics/intern/hair_volume.cpp @@ -710,7 +710,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target * div(grad(p)) = div(v) * * The finite difference approximation yields the linear equation system described here: - * http://en.wikipedia.org/wiki/Discrete_Poisson_equation + * https://en.wikipedia.org/wiki/Discrete_Poisson_equation */ lMatrix A(num_cellsA, num_cellsA); /* Reserve space for the base equation system (without boundary conditions). @@ -888,7 +888,7 @@ bool BPH_hair_volume_solve_divergence(HairGrid *grid, float /*dt*/, float target #if 0 /* XXX weighting is incorrect, disabled for now */ /* Velocity filter kernel - * See http://en.wikipedia.org/wiki/Filter_%28large_eddy_simulation%29 + * See https://en.wikipedia.org/wiki/Filter_%28large_eddy_simulation%29 */ BLI_INLINE void hair_volume_filter_box_convolute(HairVertexGrid *grid, float invD, const int kernel_size[3], int i, int j, int k) diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 71288871104..4e980e4c0e6 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1394,7 +1394,7 @@ PyDoc_STRVAR(Matrix_invert_doc, " (instead of raising a :exc:`ValueError` exception).\n" " :type fallback: :class:`Matrix`\n" "\n" -" .. seealso:: \n" +" .. seealso:: \n" ); static PyObject *Matrix_invert(MatrixObject *self, PyObject *args) { @@ -1505,7 +1505,7 @@ PyDoc_STRVAR(Matrix_invert_safe_doc, " If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n" " If tweaked matrix is still degenerated, set to the identity matrix instead.\n" "\n" -" .. seealso:: \n" +" .. seealso:: \n" ); static PyObject *Matrix_invert_safe(MatrixObject *self) { @@ -1556,7 +1556,7 @@ PyDoc_STRVAR(Matrix_adjugate_doc, "\n" " .. note:: When the matrix cant be adjugated a :exc:`ValueError` exception is raised.\n" "\n" -" .. seealso:: \n" +" .. seealso:: \n" ); static PyObject *Matrix_adjugate(MatrixObject *self) { @@ -1733,7 +1733,7 @@ PyDoc_STRVAR(Matrix_determinant_doc, " :return: Return the determinant of a matrix.\n" " :rtype: float\n" "\n" -" .. seealso:: \n" +" .. seealso:: \n" ); static PyObject *Matrix_determinant(MatrixObject *self) { @@ -1755,7 +1755,7 @@ PyDoc_STRVAR(Matrix_transpose_doc, "\n" " Set the matrix to its transpose.\n" "\n" -" .. seealso:: \n" +" .. seealso:: \n" ); static PyObject *Matrix_transpose(MatrixObject *self) { @@ -1890,7 +1890,7 @@ PyDoc_STRVAR(Matrix_identity_doc, " .. note:: An object with zero location and rotation, a scale of one,\n" " will have an identity matrix.\n" "\n" -" .. seealso:: \n" +" .. seealso:: \n" ); static PyObject *Matrix_identity(MatrixObject *self) { From a39ab9cfdecd4ab6e9e4e0214d2ca6ab1181dd1b Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 25 Oct 2016 17:59:45 +0200 Subject: [PATCH 040/590] Fix T49815: Blender always reverts to RGBA when using Save As Image. `BKE_imformat_defaults()` was doing some weird black magic based on imbuf's channels, instead of merely copying imbuf's planes here... --- source/blender/blenkernel/intern/image.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index a4eef2f9230..df3a7630bb0 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1580,24 +1580,7 @@ void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const ImBuf *i } /* planes */ - /* TODO(sergey): Channels doesn't correspond actual planes used for image buffer - * For example byte buffer will have 4 channels but it might easily - * be BW or RGB image. - * - * Need to use im_format->planes = imbuf->planes instead? - */ - switch (imbuf->channels) { - case 0: - case 4: im_format->planes = R_IMF_PLANES_RGBA; - break; - case 3: im_format->planes = R_IMF_PLANES_RGB; - break; - case 1: im_format->planes = R_IMF_PLANES_BW; - break; - default: im_format->planes = R_IMF_PLANES_RGB; - break; - } - + im_format->planes = imbuf->planes; } From 5c4113a3e49217f164183591129659eb34d8d577 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 18:05:44 +0200 Subject: [PATCH 041/590] Cycles: Fix typo in previous commit for BVH improvements --- intern/cycles/kernel/geom/geom_object.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index 0e0932512e9..89087ea05c9 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -378,13 +378,13 @@ ccl_device_inline float3 bvh_clamp_direction(float3 dir) /* clamp absolute values by exp2f(-80.0f) to avoid division by zero when calculating inverse direction */ #if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) const ssef oopes(8.271806E-25f,8.271806E-25f,8.271806E-25f,0.0f); - const ssef mask = _mm_cmpgt_ps(fabs(dir),oopes); + const ssef mask = _mm_cmpgt_ps(fabs(dir), oopes); const ssef signdir = signmsk(dir.m128) | oopes; # ifndef __KERNEL_AVX__ - ssef res = mask & dir; + ssef res = mask & signdir; res = _mm_or_ps(res,_mm_andnot_ps(mask, signdir)); # else - ssef res = _mm_blendv_ps(signdir,dir,mask); + ssef res = _mm_blendv_ps(signdir, dir, mask); # endif return float3(res); #else /* __KERNEL_SSE__ && __KERNEL_SSE2__ */ From f523fb43f9b5c8a4a694e0bbd071935a4ed979b5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 25 Oct 2016 18:28:02 +0200 Subject: [PATCH 042/590] Cycles: Fix for fix (tm) Sorry guys, for some reason read the expression back-to-front and did wrong fix :S --- intern/cycles/kernel/geom/geom_object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index 89087ea05c9..cb2de3a7e87 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -381,7 +381,7 @@ ccl_device_inline float3 bvh_clamp_direction(float3 dir) const ssef mask = _mm_cmpgt_ps(fabs(dir), oopes); const ssef signdir = signmsk(dir.m128) | oopes; # ifndef __KERNEL_AVX__ - ssef res = mask & signdir; + ssef res = mask & ssef(dir); res = _mm_or_ps(res,_mm_andnot_ps(mask, signdir)); # else ssef res = _mm_blendv_ps(signdir, dir, mask); From bc71c2bf08d887ded44243ba93447e0bea493745 Mon Sep 17 00:00:00 2001 From: lazydodo Date: Tue, 25 Oct 2016 11:49:08 -0600 Subject: [PATCH 043/590] [msvc] make.bat - create a build.log in the build directory --- make.bat | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/make.bat b/make.bat index 11c1ff00a3b..c7f2dbbf369 100644 --- a/make.bat +++ b/make.bat @@ -225,7 +225,8 @@ msbuild ^ /property:Configuration=%BUILD_TYPE% ^ /maxcpucount ^ /verbosity:minimal ^ - /p:platform=%MSBUILD_PLATFORM% + /p:platform=%MSBUILD_PLATFORM% ^ + /flp:Summary;Verbosity=minimal;LogFile=%BUILD_DIR%\Build.log if %ERRORLEVEL% NEQ 0 ( echo "Build Failed" From a1f137767fe7bf7213543a54e1e73e8cc5f29f07 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 26 Oct 2016 14:15:00 +1100 Subject: [PATCH 044/590] BMesh: edge-net split, edge selection error In practice I couldn't make this cause a bug, however it's a logical regression in fix for T48716. Thanks to Francesc Juhe for finding. --- source/blender/bmesh/intern/bmesh_polygon_edgenet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index 5ee0e904a33..6ce7c100b0d 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -161,7 +161,7 @@ static bool bm_face_split_edgenet_find_loop_pair( e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary); if (edges_boundary_len > 2) { - BLI_SMALLSTACK_SWAP(edges_search, edges_wire); + BLI_SMALLSTACK_SWAP(edges_search, edges_boundary); } } else { From 3e36cbb3deb317c903c32c7361bbcca9535a1aa9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 26 Oct 2016 20:11:09 +1100 Subject: [PATCH 045/590] Cleanup: move bitmap drawing into its own module Bitmap drawing is out-of-scope for a general math API, move to BLI_bitmap_draw_2d. --- source/blender/blenkernel/intern/tracking.c | 1 + source/blender/blenlib/BLI_bitmap_draw_2d.h | 37 ++++ source/blender/blenlib/BLI_math_geom.h | 5 - source/blender/blenlib/CMakeLists.txt | 2 + .../blender/blenlib/intern/bitmap_draw_2d.c | 181 ++++++++++++++++++ source/blender/blenlib/intern/math_geom.c | 136 ------------- source/blender/editors/mesh/editmesh_select.c | 1 + .../blender/editors/sculpt_paint/paint_mask.c | 1 + .../editors/space_view3d/view3d_edit.c | 1 + .../blender/windowmanager/intern/wm_gesture.c | 1 + 10 files changed, 225 insertions(+), 141 deletions(-) create mode 100644 source/blender/blenlib/BLI_bitmap_draw_2d.h create mode 100644 source/blender/blenlib/intern/bitmap_draw_2d.c diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index a86606f1099..29750cf2183 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -44,6 +44,7 @@ #include "DNA_scene_types.h" #include "BLI_utildefines.h" +#include "BLI_bitmap_draw_2d.h" #include "BLI_ghash.h" #include "BLI_math.h" #include "BLI_math_base.h" diff --git a/source/blender/blenlib/BLI_bitmap_draw_2d.h b/source/blender/blenlib/BLI_bitmap_draw_2d.h new file mode 100644 index 00000000000..d447c5823e2 --- /dev/null +++ b/source/blender/blenlib/BLI_bitmap_draw_2d.h @@ -0,0 +1,37 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_BITMAP_DRAW_2D_H__ +#define __BLI_BITMAP_DRAW_2D_H__ + +/** \file BLI_bitmap_draw_2d.h + * \ingroup bli + */ + +void plot_line_v2v2i( + const int p1[2], const int p2[2], + bool (*callback)(int, int, void *), void *userData); + +void fill_poly_v2i_n( + const int xmin, const int ymin, const int xmax, const int ymax, + const int polyXY[][2], const int polyCorners, + void (*callback)(int x, int x_end, int y, void *), void *userData); + +#endif /* __BLI_BITMAP_DRAW_2D_H__ */ diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 84a25f533bf..514b0300274 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -325,11 +325,6 @@ bool clip_segment_v3_plane_n( const float p1[3], const float p2[3], const float plane_array[][4], const int plane_tot, float r_p1[3], float r_p2[3]); -void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData); -void fill_poly_v2i_n( - const int xmin, const int ymin, const int xmax, const int ymax, - const int polyXY[][2], const int polyCorners, - void (*callback)(int x, int x_end, int y, void *), void *userData); /****************************** Interpolation ********************************/ /* tri or quad, d can be NULL */ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 9978d1d19af..6e717a3ae7e 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -56,6 +56,7 @@ set(SRC intern/array_store_utils.c intern/array_utils.c intern/astar.c + intern/bitmap_draw_2d.c intern/boxpack2d.c intern/buffer.c intern/callbacks.c @@ -127,6 +128,7 @@ set(SRC BLI_array_utils.h BLI_astar.h BLI_bitmap.h + BLI_bitmap_draw_2d.h BLI_blenlib.h BLI_boxpack2d.h BLI_buffer.h diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c new file mode 100644 index 00000000000..06d21855197 --- /dev/null +++ b/source/blender/blenlib/intern/bitmap_draw_2d.c @@ -0,0 +1,181 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: some of this file. + * + * ***** END GPL LICENSE BLOCK ***** + * */ + +/** \file blender/blenlib/intern/bitmap_draw_2d.c + * \ingroup bli + * + * Utility functions for primitive drawing operations. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_bitmap_draw_2d.h" + +#include "BLI_utildefines.h" + +#include "BLI_strict_flags.h" + +/** + * Plot a line from \a p1 to \a p2 (inclusive). + */ +void plot_line_v2v2i( + const int p1[2], const int p2[2], + bool (*callback)(int, int, void *), void *userData) +{ + /* Bresenham's line algorithm. */ + int x1 = p1[0]; + int y1 = p1[1]; + int x2 = p2[0]; + int y2 = p2[1]; + + 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; + int delta_y = (y2 > y1 ? ((void)(iy = 1), y2 - y1) : ((void)(iy = -1), y1 - y2)) << 1; + + if (callback(x1, y1, userData) == 0) { + return; + } + + if (delta_x >= delta_y) { + /* error may go below zero */ + int error = delta_y - (delta_x >> 1); + + while (x1 != x2) { + if (error >= 0) { + if (error || (ix > 0)) { + y1 += iy; + error -= delta_x; + } + /* else do nothing */ + } + /* else do nothing */ + + x1 += ix; + error += delta_y; + + if (callback(x1, y1, userData) == 0) { + return; + } + } + } + else { + /* error may go below zero */ + int error = delta_x - (delta_y >> 1); + + while (y1 != y2) { + if (error >= 0) { + if (error || (iy > 0)) { + x1 += ix; + error -= delta_y; + } + /* else do nothing */ + } + /* else do nothing */ + + y1 += iy; + error += delta_x; + + if (callback(x1, y1, userData) == 0) { + return; + } + } + } +} + +/** + * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive), + * note that \a x_end will always be greater than \a x, so we can use: + * + * \code{.c} + * do { + * func(x, y); + * } while (++x != x_end); + * \endcode + */ +void fill_poly_v2i_n( + const int xmin, const int ymin, const int xmax, const int ymax, + const int verts[][2], const int nr, + void (*callback)(int x, int x_end, int y, void *), void *userData) +{ + /* Originally by Darel Rex Finley, 2007. + */ + + int nodes, pixel_y, i, j, swap; + int *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(nr + 1), __func__); + + /* Loop through the rows of the image. */ + for (pixel_y = ymin; pixel_y < ymax; pixel_y++) { + + /* Build a list of nodes. */ + nodes = 0; j = nr - 1; + for (i = 0; i < nr; i++) { + if ((verts[i][1] < pixel_y && verts[j][1] >= pixel_y) || + (verts[j][1] < pixel_y && verts[i][1] >= pixel_y)) + { + node_x[nodes++] = (int)(verts[i][0] + + ((double)(pixel_y - verts[i][1]) / (verts[j][1] - verts[i][1])) * + (verts[j][0] - verts[i][0])); + } + j = i; + } + + /* Sort the nodes, via a simple "Bubble" sort. */ + i = 0; + while (i < nodes - 1) { + if (node_x[i] > node_x[i + 1]) { + SWAP_TVAL(swap, node_x[i], node_x[i + 1]); + if (i) i--; + } + else { + i++; + } + } + + /* Fill the pixels between node pairs. */ + for (i = 0; i < nodes; i += 2) { + if (node_x[i] >= xmax) break; + if (node_x[i + 1] > xmin) { + if (node_x[i ] < xmin) node_x[i ] = xmin; + if (node_x[i + 1] > xmax) node_x[i + 1] = xmax; + +#if 0 + /* for many x/y calls */ + for (j = node_x[i]; j < node_x[i + 1]; j++) { + callback(j - xmin, pixel_y - ymin, userData); + } +#else + /* for single call per x-span */ + if (node_x[i] < node_x[i + 1]) { + callback(node_x[i] - xmin, node_x[i + 1] - xmin, pixel_y - ymin, userData); + } +#endif + } + } + } + MEM_freeN(node_x); +} diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index dd30f267f78..f31d0935b77 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2885,142 +2885,6 @@ bool clip_segment_v3_plane_n( return true; } -void plot_line_v2v2i(const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData) -{ - int x1 = p1[0]; - int y1 = p1[1]; - int x2 = p2[0]; - int y2 = p2[1]; - - 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; - int delta_y = (y2 > y1 ? ((void)(iy = 1), y2 - y1) : ((void)(iy = -1), y1 - y2)) << 1; - - if (callback(x1, y1, userData) == 0) { - return; - } - - if (delta_x >= delta_y) { - /* error may go below zero */ - int error = delta_y - (delta_x >> 1); - - while (x1 != x2) { - if (error >= 0) { - if (error || (ix > 0)) { - y1 += iy; - error -= delta_x; - } - /* else do nothing */ - } - /* else do nothing */ - - x1 += ix; - error += delta_y; - - if (callback(x1, y1, userData) == 0) { - return; - } - } - } - else { - /* error may go below zero */ - int error = delta_x - (delta_y >> 1); - - while (y1 != y2) { - if (error >= 0) { - if (error || (iy > 0)) { - x1 += ix; - error -= delta_y; - } - /* else do nothing */ - } - /* else do nothing */ - - y1 += iy; - error += delta_x; - - if (callback(x1, y1, userData) == 0) { - return; - } - } - } -} - -/** - * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive), - * note that \a x_end will always be greater than \a x, so we can use: - * - * \code{.c} - * do { - * func(x, y); - * } while (++x != x_end); - * \endcode - */ -void fill_poly_v2i_n( - const int xmin, const int ymin, const int xmax, const int ymax, - const int verts[][2], const int nr, - void (*callback)(int x, int x_end, int y, void *), void *userData) -{ - /* originally by Darel Rex Finley, 2007 */ - - int nodes, pixel_y, i, j, swap; - int *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(nr + 1), __func__); - - /* Loop through the rows of the image. */ - for (pixel_y = ymin; pixel_y < ymax; pixel_y++) { - - /* Build a list of nodes. */ - nodes = 0; j = nr - 1; - for (i = 0; i < nr; i++) { - if ((verts[i][1] < pixel_y && verts[j][1] >= pixel_y) || - (verts[j][1] < pixel_y && verts[i][1] >= pixel_y)) - { - node_x[nodes++] = (int)(verts[i][0] + - ((double)(pixel_y - verts[i][1]) / (verts[j][1] - verts[i][1])) * - (verts[j][0] - verts[i][0])); - } - j = i; - } - - /* Sort the nodes, via a simple "Bubble" sort. */ - i = 0; - while (i < nodes - 1) { - if (node_x[i] > node_x[i + 1]) { - SWAP_TVAL(swap, node_x[i], node_x[i + 1]); - if (i) i--; - } - else { - i++; - } - } - - /* Fill the pixels between node pairs. */ - for (i = 0; i < nodes; i += 2) { - if (node_x[i] >= xmax) break; - if (node_x[i + 1] > xmin) { - if (node_x[i ] < xmin) node_x[i ] = xmin; - if (node_x[i + 1] > xmax) node_x[i + 1] = xmax; - -#if 0 - /* for many x/y calls */ - for (j = node_x[i]; j < node_x[i + 1]; j++) { - callback(j - xmin, pixel_y - ymin, userData); - } -#else - /* for single call per x-span */ - if (node_x[i] < node_x[i + 1]) { - callback(node_x[i] - xmin, node_x[i + 1] - xmin, pixel_y - ymin, userData); - } -#endif - } - } - } - MEM_freeN(node_x); -} - /****************************** Axis Utils ********************************/ /** diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 5d5731a7e16..1004b0a54b5 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -32,6 +32,7 @@ #include "MEM_guardedalloc.h" #include "BLI_bitmap.h" +#include "BLI_bitmap_draw_2d.h" #include "BLI_listbase.h" #include "BLI_linklist.h" #include "BLI_linklist_stack.h" diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index a47b9a0b936..5471a39cf82 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -37,6 +37,7 @@ #include "BIF_glutil.h" +#include "BLI_bitmap_draw_2d.h" #include "BLI_math_matrix.h" #include "BLI_math_geom.h" #include "BLI_utildefines.h" diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 9b8ca2d26da..3121a8fd90b 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -41,6 +41,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_bitmap_draw_2d.h" #include "BLI_blenlib.h" #include "BLI_kdopbvh.h" #include "BLI_math.h" diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 1357729e898..1f30aa17f23 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -37,6 +37,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_bitmap_draw_2d.h" #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_utildefines.h" From 8125271ddb29f8e42d00ee7667c24412d67fb2f5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 26 Oct 2016 20:14:48 +1100 Subject: [PATCH 046/590] Cleanup: rename functions in BLI_bitmap_draw_2d --- source/blender/blenkernel/intern/tracking.c | 7 ++++--- source/blender/blenlib/BLI_bitmap_draw_2d.h | 4 ++-- source/blender/blenlib/intern/bitmap_draw_2d.c | 4 ++-- source/blender/editors/mesh/editmesh_select.c | 2 +- source/blender/editors/sculpt_paint/paint_mask.c | 2 +- source/blender/editors/space_view3d/view3d_edit.c | 2 +- source/blender/windowmanager/intern/wm_gesture.c | 2 +- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 29750cf2183..96ab8693122 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -998,9 +998,10 @@ static void track_mask_gpencil_layer_rasterize(int frame_width, int frame_height point[1] = (stroke_points[i].y - marker->search_min[1]) * frame_height; } /* TODO: add an option to control whether AA is enabled or not */ - fill_poly_v2i_n(0, 0, mask_width, mask_height, - (const int (*)[2])mask_points, stroke->totpoints, - track_mask_set_pixel_cb, &data); + BLI_bitmap_draw_2d_poly_v2i_n( + 0, 0, mask_width, mask_height, + (const int (*)[2])mask_points, stroke->totpoints, + track_mask_set_pixel_cb, &data); MEM_freeN(mask_points); } stroke = stroke->next; diff --git a/source/blender/blenlib/BLI_bitmap_draw_2d.h b/source/blender/blenlib/BLI_bitmap_draw_2d.h index d447c5823e2..fe890e94f1b 100644 --- a/source/blender/blenlib/BLI_bitmap_draw_2d.h +++ b/source/blender/blenlib/BLI_bitmap_draw_2d.h @@ -25,11 +25,11 @@ * \ingroup bli */ -void plot_line_v2v2i( +void BLI_bitmap_draw_2d_line_v2v2i( const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData); -void fill_poly_v2i_n( +void BLI_bitmap_draw_2d_poly_v2i_n( const int xmin, const int ymin, const int xmax, const int ymax, const int polyXY[][2], const int polyCorners, void (*callback)(int x, int x_end, int y, void *), void *userData); diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c index 06d21855197..11072f668c8 100644 --- a/source/blender/blenlib/intern/bitmap_draw_2d.c +++ b/source/blender/blenlib/intern/bitmap_draw_2d.c @@ -40,7 +40,7 @@ /** * Plot a line from \a p1 to \a p2 (inclusive). */ -void plot_line_v2v2i( +void BLI_bitmap_draw_2d_line_v2v2i( const int p1[2], const int p2[2], bool (*callback)(int, int, void *), void *userData) { @@ -117,7 +117,7 @@ void plot_line_v2v2i( * } while (++x != x_end); * \endcode */ -void fill_poly_v2i_n( +void BLI_bitmap_draw_2d_poly_v2i_n( const int xmin, const int ymin, const int xmax, const int ymax, const int verts[][2], const int nr, void (*callback)(int x, int x_end, int y, void *), void *userData) diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 1004b0a54b5..a6de1b284b7 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -295,7 +295,7 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short lasso_mask_data.px = dr_mask; lasso_mask_data.width = (xmax - xmin) + 1; - fill_poly_v2i_n( + BLI_bitmap_draw_2d_poly_v2i_n( xmin, ymin, xmax + 1, ymax + 1, mcords, tot, edbm_mask_lasso_px_cb, &lasso_mask_data); diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 5471a39cf82..a4887c579ac 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -440,7 +440,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.width = data.rect.xmax - data.rect.xmin; data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__); - fill_poly_v2i_n( + BLI_bitmap_draw_2d_poly_v2i_n( data.rect.xmin, data.rect.ymin, data.rect.xmax, data.rect.ymax, mcords, mcords_tot, mask_lasso_px_cb, &data); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 3121a8fd90b..9e41ad6a8f6 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -5053,7 +5053,7 @@ bool ED_view3d_autodist_depth_seg(ARegion *ar, const int mval_sta[2], const int copy_v2_v2_int(p1, mval_sta); copy_v2_v2_int(p2, mval_end); - plot_line_v2v2i(p1, p2, depth_segment_cb, &data); + BLI_bitmap_draw_2d_line_v2v2i(p1, p2, depth_segment_cb, &data); *depth = data.depth; diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c index 1f30aa17f23..46203333eb5 100644 --- a/source/blender/windowmanager/intern/wm_gesture.c +++ b/source/blender/windowmanager/intern/wm_gesture.c @@ -273,7 +273,7 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt) unsigned char *pixel_buf = MEM_callocN(sizeof(*pixel_buf) * w * h, __func__); struct LassoFillData lasso_fill_data = {pixel_buf, w}; - fill_poly_v2i_n( + BLI_bitmap_draw_2d_poly_v2i_n( rect.xmin, rect.ymin, rect.xmax, rect.ymax, (const int (*)[2])moves, tot, draw_filled_lasso_px_cb, &lasso_fill_data); From 44522a5b98f908928e93ab32c9d6046de4342d9b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 26 Oct 2016 20:26:32 +1100 Subject: [PATCH 047/590] BLI_bitmap_draw_2d: optimize polygon filling Existing method was fine for basic polygons but didn't scale well because its was checking all coordinates for every y-pixel. Heres an optimized version. Basic logic remains the same this just maintains an ordered list of intersections, tracking in-out points, to avoid re-computing every row, this means sorting is only done once when out of order segments are found, the segments only need to be re-ordered if they cross each other. Speedup isn't linear, test with full-screen complex lasso gave 11x speedup. --- .../blender/blenlib/intern/bitmap_draw_2d.c | 220 +++++++++++++++--- 1 file changed, 185 insertions(+), 35 deletions(-) diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c index 11072f668c8..afc54511d13 100644 --- a/source/blender/blenlib/intern/bitmap_draw_2d.c +++ b/source/blender/blenlib/intern/bitmap_draw_2d.c @@ -29,14 +29,21 @@ * Utility functions for primitive drawing operations. */ +#include + #include "MEM_guardedalloc.h" #include "BLI_bitmap_draw_2d.h" +#include "BLI_math_base.h" +#include "BLI_sort.h" #include "BLI_utildefines.h" #include "BLI_strict_flags.h" +/* -------------------------------------------------------------------- */ +/* Draw Line */ + /** * Plot a line from \a p1 to \a p2 (inclusive). */ @@ -107,7 +114,51 @@ void BLI_bitmap_draw_2d_line_v2v2i( } } + +/* -------------------------------------------------------------------- */ +/* Draw Filled Polygon */ + +/* sort edge-segments on y, then x axis */ +static int draw_poly_v2i_n__span_y_sort(const void *a_p, const void *b_p, void *verts_p) +{ + const int (*verts)[2] = verts_p; + const int *a = a_p; + const int *b = b_p; + const int *co_a = verts[a[0]]; + const int *co_b = verts[b[0]]; + + if (co_a[1] < co_b[1]) { + return -1; + } + else if (co_a[1] > co_b[1]) { + return 1; + } + else if (co_a[0] < co_b[0]) { + return -1; + } + else if (co_a[0] > co_b[0]) { + return 1; + } + else { + /* co_a & co_b are identical, use the line closest to the x-min */ + const int *co = co_a; + co_a = verts[a[1]]; + co_b = verts[b[1]]; + int ord = (((co_b[0] - co[0]) * (co_a[1] - co[1])) - + ((co_a[0] - co[0]) * (co_b[1] - co[1]))); + if (ord > 0) { + return -1; + } + if (ord < 0) { + return 1; + } + } + return 0; +} + /** + * Draws a filled polyon with support for self intersections. + * * \param callback: Takes the x, y coords and x-span (\a x_end is not inclusive), * note that \a x_end will always be greater than \a x, so we can use: * @@ -123,59 +174,158 @@ void BLI_bitmap_draw_2d_poly_v2i_n( void (*callback)(int x, int x_end, int y, void *), void *userData) { /* Originally by Darel Rex Finley, 2007. - */ + * Optimized by Campbell Barton, 2016 to track sorted intersections. */ - int nodes, pixel_y, i, j, swap; - int *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(nr + 1), __func__); + int (*span_y)[2] = MEM_mallocN(sizeof(*span_y) * (size_t)nr, __func__); + int span_y_len = 0; + + for (int i_curr = 0, i_prev = nr - 1; i_curr < nr; i_prev = i_curr++) { + const int *co_prev = verts[i_prev]; + const int *co_curr = verts[i_curr]; + + if (co_prev[1] != co_curr[1]) { + /* Any segments entirely above or below the area of interest can be skipped. */ + if ((min_ii(co_prev[1], co_curr[1]) >= ymax) || + (max_ii(co_prev[1], co_curr[1]) < ymin)) + { + continue; + } + + int *s = span_y[span_y_len++]; + if (co_prev[1] < co_curr[1]) { + s[0] = i_prev; + s[1] = i_curr; + } + else { + s[0] = i_curr; + s[1] = i_prev; + } + } + } + + BLI_qsort_r(span_y, (size_t)span_y_len, sizeof(*span_y), draw_poly_v2i_n__span_y_sort, (void *)verts); + + struct NodeX { + int span_y_index; + int x; + } *node_x = MEM_mallocN(sizeof(*node_x) * (size_t)(nr + 1), __func__); + int node_x_len = 0; + + int span_y_index = 0; + if (span_y_len != 0 && verts[span_y[0][0]][1] < ymin) { + while ((span_y_index < span_y_len) && + (verts[span_y[span_y_index][0]][1] < ymin)) + { + BLI_assert(verts[span_y[span_y_index][0]][1] < + verts[span_y[span_y_index][1]][1]); + if (verts[span_y[span_y_index][1]][1] >= ymin) { + struct NodeX *n = &node_x[node_x_len++]; + n->span_y_index = span_y_index; + } + span_y_index += 1; + } + } /* Loop through the rows of the image. */ - for (pixel_y = ymin; pixel_y < ymax; pixel_y++) { + for (int pixel_y = ymin; pixel_y < ymax; pixel_y++) { + bool is_sorted = true; + bool do_remove = false; - /* Build a list of nodes. */ - nodes = 0; j = nr - 1; - for (i = 0; i < nr; i++) { - if ((verts[i][1] < pixel_y && verts[j][1] >= pixel_y) || - (verts[j][1] < pixel_y && verts[i][1] >= pixel_y)) - { - node_x[nodes++] = (int)(verts[i][0] + - ((double)(pixel_y - verts[i][1]) / (verts[j][1] - verts[i][1])) * - (verts[j][0] - verts[i][0])); + for (int i = 0, x_ix_prev = INT_MIN; i < node_x_len; i++) { + struct NodeX *n = &node_x[i]; + const int *s = span_y[n->span_y_index]; + const int *co_prev = verts[s[0]]; + const int *co_curr = verts[s[1]]; + + BLI_assert(co_prev[1] < pixel_y && co_curr[1] >= pixel_y); + + const double x = (co_prev[0] - co_curr[0]); + const double y = (co_prev[1] - co_curr[1]); + const double y_px = (pixel_y - co_curr[1]); + const int x_ix = (int)((double)co_curr[0] + ((y_px / y) * x)); + n->x = x_ix; + + if (is_sorted && (x_ix_prev > x_ix)) { + is_sorted = false; } - j = i; + if (do_remove == false && co_curr[1] == pixel_y) { + do_remove = true; + } + x_ix_prev = x_ix; } /* Sort the nodes, via a simple "Bubble" sort. */ - i = 0; - while (i < nodes - 1) { - if (node_x[i] > node_x[i + 1]) { - SWAP_TVAL(swap, node_x[i], node_x[i + 1]); - if (i) i--; - } - else { - i++; + if (is_sorted == false) { + int i = 0; + const int node_x_end = node_x_len - 1; + while (i < node_x_end) { + if (node_x[i].x > node_x[i + 1].x) { + SWAP(struct NodeX, node_x[i], node_x[i + 1]); + if (i != 0) { + i -= 1; + } + } + else { + i += 1; + } } } /* Fill the pixels between node pairs. */ - for (i = 0; i < nodes; i += 2) { - if (node_x[i] >= xmax) break; - if (node_x[i + 1] > xmin) { - if (node_x[i ] < xmin) node_x[i ] = xmin; - if (node_x[i + 1] > xmax) node_x[i + 1] = xmax; + for (int i = 0; i < node_x_len; i += 2) { + int x_src = node_x[i].x; + int x_dst = node_x[i + 1].x; -#if 0 - /* for many x/y calls */ - for (j = node_x[i]; j < node_x[i + 1]; j++) { - callback(j - xmin, pixel_y - ymin, userData); + if (x_src >= xmax) { + break; + } + + if (x_dst > xmin) { + if (x_src < xmin) { + x_src = xmin; + } + if (x_dst > xmax) { + x_dst = xmax; } -#else /* for single call per x-span */ - if (node_x[i] < node_x[i + 1]) { - callback(node_x[i] - xmin, node_x[i + 1] - xmin, pixel_y - ymin, userData); + if (x_src < x_dst) { + callback(x_src - xmin, x_dst - xmin, pixel_y - ymin, userData); } -#endif } } + + /* Clear finalized nodes in one pass, only when needed + * (avoids excessive array-resizing). */ + if (do_remove == true) { + int i_dst = 0; + for (int i_src = 0; i_src < node_x_len; i_src += 1) { + const int *s = span_y[node_x[i_src].span_y_index]; + const int *co = verts[s[1]]; + if (co[1] != pixel_y) { + if (i_dst != i_src) { + /* x is initialized for the next pixel_y (no need to adjust here) */ + node_x[i_dst].span_y_index = node_x[i_src].span_y_index; + } + i_dst += 1; + } + } + node_x_len = i_dst; + } + + /* Scan for new x-nodes */ + while ((span_y_index < span_y_len) && + (verts[span_y[span_y_index][0]][1] == pixel_y)) + { + /* note, node_x these are just added at the end, + * not ideal but sorting once will resolve. */ + + /* x is initialized for the next pixel_y */ + struct NodeX *n = &node_x[node_x_len++]; + n->span_y_index = span_y_index; + span_y_index += 1; + } } + + MEM_freeN(span_y); MEM_freeN(node_x); } From 72921a1e43033d7fea998dd607a68250da5d93bd Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 13 Oct 2016 15:51:20 +1100 Subject: [PATCH 048/590] RangeTree API rewrite Rewrite the current range-tree API used by dyn-topo undo to avoid inefficiencies from stdc++'s set use. - every call to `take_any` (called for all verts & faces) removed and added to the set. - further range adjustment also took 2x btree edits. This patch inlines a btree which is modified in-place, so common resizing operations don't need to perform a remove & insert. Ranges are stored in a list so `take_any` can access the first item without a btree lookup. Since range-tree isn't a bottleneck in sculpting, this only gives minor speedups. Measured approx ~15% overall faster calculation for sculpting, although this number time doesn't include GPU updates and depends on how much edits fragment the range-tree. --- extern/rangetree/CMakeLists.txt | 6 +- extern/rangetree/README.blender | 6 +- extern/rangetree/README.org | 13 - extern/rangetree/intern/generic_alloc_impl.h | 215 +++++ extern/rangetree/intern/range_tree.c | 869 +++++++++++++++++++ extern/rangetree/range_tree.h | 48 + extern/rangetree/range_tree.hh | 251 ------ extern/rangetree/range_tree_c_api.cc | 92 -- extern/rangetree/range_tree_c_api.h | 62 -- source/blender/bmesh/intern/bmesh_log.c | 2 +- 10 files changed, 1139 insertions(+), 425 deletions(-) delete mode 100644 extern/rangetree/README.org create mode 100644 extern/rangetree/intern/generic_alloc_impl.h create mode 100644 extern/rangetree/intern/range_tree.c create mode 100644 extern/rangetree/range_tree.h delete mode 100644 extern/rangetree/range_tree.hh delete mode 100644 extern/rangetree/range_tree_c_api.cc delete mode 100644 extern/rangetree/range_tree_c_api.h diff --git a/extern/rangetree/CMakeLists.txt b/extern/rangetree/CMakeLists.txt index ba682233381..e8e9b15f8b1 100644 --- a/extern/rangetree/CMakeLists.txt +++ b/extern/rangetree/CMakeLists.txt @@ -21,10 +21,10 @@ set(INC ) set(SRC - range_tree.hh - range_tree_c_api.h + range_tree.h + intern/generic_alloc_impl.h - range_tree_c_api.cc + intern/range_tree.c ) blender_add_lib(extern_rangetree "${SRC}" "${INC}" "") diff --git a/extern/rangetree/README.blender b/extern/rangetree/README.blender index cb5967137ac..6a940c14d60 100644 --- a/extern/rangetree/README.blender +++ b/extern/rangetree/README.blender @@ -1,5 +1,5 @@ Project: RangeTree -URL: https://github.com/nicholasbishop/RangeTree -License: GPLv2+ -Upstream version: c4ecf6bb7dfd +URL: https://github.com/ideasman42/rangetree-c +License: Apache 2.0 +Upstream version: 40ebed8aa209 Local modifications: None diff --git a/extern/rangetree/README.org b/extern/rangetree/README.org deleted file mode 100644 index 46a4cedaf8f..00000000000 --- a/extern/rangetree/README.org +++ /dev/null @@ -1,13 +0,0 @@ -* Overview - Basic class for storing non-overlapping scalar ranges. Underlying - representation is a C++ STL set for fast lookups. - -* License - GPL version 2 or later (see COPYING) - -* Author Note - This implementation is intended for storing free unique IDs in a new - undo system for BMesh in Blender, but could be useful elsewhere. - -* Website - https://github.com/nicholasbishop/RangeTree diff --git a/extern/rangetree/intern/generic_alloc_impl.h b/extern/rangetree/intern/generic_alloc_impl.h new file mode 100644 index 00000000000..0f9f5184637 --- /dev/null +++ b/extern/rangetree/intern/generic_alloc_impl.h @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2016, Blender Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "Apache License") + * with the following modification; you may not use this file except in + * compliance with the Apache License and the following modification to it: + * Section 6. Trademarks. is deleted and replaced with: + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor + * and its affiliates, except as required to comply with Section 4(c) of + * the License and to reproduce the content of the NOTICE file. + * + * You may obtain a copy of the Apache License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Apache License with the above modification is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the Apache License for the specific + * language governing permissions and limitations under the Apache License. + */ + +/** + * Simple Memory Chunking Allocator + * ================================ + * + * Defines need to be set: + * - #TPOOL_IMPL_PREFIX: Prefix to use for the API. + * - #TPOOL_ALLOC_TYPE: Struct type this pool handles. + * - #TPOOL_STRUCT: Name for pool struct name. + * - #TPOOL_CHUNK_SIZE: Chunk size (optional), use 64kb when not defined. + * + * \note #TPOOL_ALLOC_TYPE must be at least ``sizeof(void *)``. + * + * Defines the API, uses #TPOOL_IMPL_PREFIX to prefix each function. + * + * - *_pool_create() + * - *_pool_destroy() + * - *_pool_clear() + * + * - *_pool_elem_alloc() + * - *_pool_elem_calloc() + * - *_pool_elem_free() + */ + +/* check we're not building directly */ +#if !defined(TPOOL_IMPL_PREFIX) || \ + !defined(TPOOL_ALLOC_TYPE) || \ + !defined(TPOOL_STRUCT) +# error "This file can't be compiled directly, include in another source file" +#endif + +#define _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) MACRO_ARG1 ## MACRO_ARG2 +#define _CONCAT(MACRO_ARG1, MACRO_ARG2) _CONCAT_AUX(MACRO_ARG1, MACRO_ARG2) +#define _TPOOL_PREFIX(id) _CONCAT(TPOOL_IMPL_PREFIX, _##id) + +/* local identifiers */ +#define pool_create _TPOOL_PREFIX(pool_create) +#define pool_destroy _TPOOL_PREFIX(pool_destroy) +#define pool_clear _TPOOL_PREFIX(pool_clear) + +#define pool_elem_alloc _TPOOL_PREFIX(pool_elem_alloc) +#define pool_elem_calloc _TPOOL_PREFIX(pool_elem_calloc) +#define pool_elem_free _TPOOL_PREFIX(pool_elem_free) + +/* private identifiers (only for this file, undefine after) */ +#define pool_alloc_chunk _TPOOL_PREFIX(pool_alloc_chunk) +#define TPoolChunk _TPOOL_PREFIX(TPoolChunk) +#define TPoolChunkElemFree _TPOOL_PREFIX(TPoolChunkElemFree) + +#ifndef TPOOL_CHUNK_SIZE +#define TPOOL_CHUNK_SIZE (1 << 16) /* 64kb */ +#define _TPOOL_CHUNK_SIZE_UNDEF +#endif + +#ifndef UNLIKELY +# ifdef __GNUC__ +# define UNLIKELY(x) __builtin_expect(!!(x), 0) +# else +# define UNLIKELY(x) (x) +# endif +#endif + +#ifdef __GNUC__ +# define MAYBE_UNUSED __attribute__((unused)) +#else +# define MAYBE_UNUSED +#endif + + +struct TPoolChunk { + struct TPoolChunk *prev; + unsigned int size; + unsigned int bufsize; + TPOOL_ALLOC_TYPE buf[0]; +}; + +struct TPoolChunkElemFree { + struct TPoolChunkElemFree *next; +}; + +struct TPOOL_STRUCT { + /* Always keep at least one chunk (never NULL) */ + struct TPoolChunk *chunk; + /* when NULL, allocate a new chunk */ + struct TPoolChunkElemFree *free; +}; + +/** + * Number of elems to include per #TPoolChunk when no reserved size is passed, + * or we allocate past the reserved number. + * + * \note Optimize number for 64kb allocs. + */ +#define _TPOOL_CHUNK_DEFAULT_NUM \ + (((1 << 16) - sizeof(struct TPoolChunk)) / sizeof(TPOOL_ALLOC_TYPE)) + + +/** \name Internal Memory Management + * \{ */ + +static struct TPoolChunk *pool_alloc_chunk( + unsigned int tot_elems, struct TPoolChunk *chunk_prev) +{ + struct TPoolChunk *chunk = malloc( + sizeof(struct TPoolChunk) + (sizeof(TPOOL_ALLOC_TYPE) * tot_elems)); + chunk->prev = chunk_prev; + chunk->bufsize = tot_elems; + chunk->size = 0; + return chunk; +} + +static TPOOL_ALLOC_TYPE *pool_elem_alloc(struct TPOOL_STRUCT *pool) +{ + TPOOL_ALLOC_TYPE *elem; + + if (pool->free) { + elem = (TPOOL_ALLOC_TYPE *)pool->free; + pool->free = pool->free->next; + } + else { + struct TPoolChunk *chunk = pool->chunk; + if (UNLIKELY(chunk->size == chunk->bufsize)) { + chunk = pool->chunk = pool_alloc_chunk(_TPOOL_CHUNK_DEFAULT_NUM, chunk); + } + elem = &chunk->buf[chunk->size++]; + } + + return elem; +} + +MAYBE_UNUSED +static TPOOL_ALLOC_TYPE *pool_elem_calloc(struct TPOOL_STRUCT *pool) +{ + TPOOL_ALLOC_TYPE *elem = pool_elem_alloc(pool); + memset(elem, 0, sizeof(*elem)); + return elem; +} + +static void pool_elem_free(struct TPOOL_STRUCT *pool, TPOOL_ALLOC_TYPE *elem) +{ + struct TPoolChunkElemFree *elem_free = (struct TPoolChunkElemFree *)elem; + elem_free->next = pool->free; + pool->free = elem_free; +} + +static void pool_create(struct TPOOL_STRUCT *pool, unsigned int tot_reserve) +{ + pool->chunk = pool_alloc_chunk((tot_reserve > 1) ? tot_reserve : _TPOOL_CHUNK_DEFAULT_NUM, NULL); + pool->free = NULL; +} + +MAYBE_UNUSED +static void pool_clear(struct TPOOL_STRUCT *pool) +{ + /* Remove all except the last chunk */ + while (pool->chunk->prev) { + struct TPoolChunk *chunk_prev = pool->chunk->prev; + free(pool->chunk); + pool->chunk = chunk_prev; + } + pool->chunk->size = 0; + pool->free = NULL; +} + +static void pool_destroy(struct TPOOL_STRUCT *pool) +{ + struct TPoolChunk *chunk = pool->chunk; + do { + struct TPoolChunk *chunk_prev; + chunk_prev = chunk->prev; + free(chunk); + chunk = chunk_prev; + } while (chunk); + + pool->chunk = NULL; + pool->free = NULL; +} + +/** \} */ + +#undef _TPOOL_CHUNK_DEFAULT_NUM +#undef _CONCAT_AUX +#undef _CONCAT +#undef _TPOOL_PREFIX + +#undef TPoolChunk +#undef TPoolChunkElemFree + +#ifdef _TPOOL_CHUNK_SIZE_UNDEF +# undef TPOOL_CHUNK_SIZE +# undef _TPOOL_CHUNK_SIZE_UNDEF +#endif diff --git a/extern/rangetree/intern/range_tree.c b/extern/rangetree/intern/range_tree.c new file mode 100644 index 00000000000..766dd22234c --- /dev/null +++ b/extern/rangetree/intern/range_tree.c @@ -0,0 +1,869 @@ +/* + * Copyright (c) 2016, Campbell Barton. + * + * Licensed under the Apache License, Version 2.0 (the "Apache License") + * with the following modification; you may not use this file except in + * compliance with the Apache License and the following modification to it: + * Section 6. Trademarks. is deleted and replaced with: + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor + * and its affiliates, except as required to comply with Section 4(c) of + * the License and to reproduce the content of the NOTICE file. + * + * You may obtain a copy of the Apache License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Apache License with the above modification is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the Apache License for the specific + * language governing permissions and limitations under the Apache License. + */ + +#include +#include +#include + +#include + +#include "range_tree.h" + +typedef unsigned int uint; + +/* Use binary-tree for lookups, else fallback to full search */ +#define USE_BTREE +/* Use memory pool for nodes, else do individual allocations */ +#define USE_TPOOL + +/* Node representing a range in the RangeTreeUInt. */ +typedef struct Node { + struct Node *next, *prev; + + /* range (inclusive) */ + uint min, max; + +#ifdef USE_BTREE + /* Left leaning red-black tree, for reference implementation see: + * https://gitlab.com/ideasman42/btree-mini-py */ + struct Node *left, *right; + /* RED/BLACK */ + bool color; +#endif +} Node; + +#ifdef USE_TPOOL +/* rt_pool_* pool allocator */ +#define TPOOL_IMPL_PREFIX rt_node +#define TPOOL_ALLOC_TYPE Node +#define TPOOL_STRUCT ElemPool_Node +#include "generic_alloc_impl.h" +#undef TPOOL_IMPL_PREFIX +#undef TPOOL_ALLOC_TYPE +#undef TPOOL_STRUCT +#endif /* USE_TPOOL */ + +typedef struct LinkedList { + Node *first, *last; +} LinkedList; + +typedef struct RangeTreeUInt { + uint range[2]; + LinkedList list; +#ifdef USE_BTREE + Node *root; +#endif +#ifdef USE_TPOOL + struct ElemPool_Node epool; +#endif +} RangeTreeUInt; + +/* ------------------------------------------------------------------------- */ +/* List API */ + +static void list_push_front(LinkedList *list, Node *node) +{ + if (list->first != NULL) { + node->next = list->first; + node->next->prev = node; + node->prev = NULL; + } + else { + list->last = node; + } + list->first = node; +} + +static void list_push_back(LinkedList *list, Node *node) +{ + if (list->first != NULL) { + node->prev = list->last; + node->prev->next = node; + node->next = NULL; + } + else { + list->first = node; + } + list->last = node; +} + +static void list_push_after(LinkedList *list, Node *node_prev, Node *node_new) +{ + /* node_new before node_next */ + + /* empty list */ + if (list->first == NULL) { + list->first = node_new; + list->last = node_new; + return; + } + + /* insert at head of list */ + if (node_prev == NULL) { + node_new->prev = NULL; + node_new->next = list->first; + node_new->next->prev = node_new; + list->first = node_new; + return; + } + + /* at end of list */ + if (list->last == node_prev) { + list->last = node_new; + } + + node_new->next = node_prev->next; + node_new->prev = node_prev; + node_prev->next = node_new; + if (node_new->next) { + node_new->next->prev = node_new; + } +} + +static void list_push_before(LinkedList *list, Node *node_next, Node *node_new) +{ + /* node_new before node_next */ + + /* empty list */ + if (list->first == NULL) { + list->first = node_new; + list->last = node_new; + return; + } + + /* insert at end of list */ + if (node_next == NULL) { + node_new->prev = list->last; + node_new->next = NULL; + list->last->next = node_new; + list->last = node_new; + return; + } + + /* at beginning of list */ + if (list->first == node_next) { + list->first = node_new; + } + + node_new->next = node_next; + node_new->prev = node_next->prev; + node_next->prev = node_new; + if (node_new->prev) { + node_new->prev->next = node_new; + } +} + +static void list_remove(LinkedList *list, Node *node) +{ + if (node->next != NULL) { + node->next->prev = node->prev; + } + if (node->prev != NULL) { + node->prev->next = node->next; + } + + if (list->last == node) { + list->last = node->prev; + } + if (list->first == node) { + list->first = node->next; + } +} + +static void list_clear(LinkedList *list) +{ + list->first = NULL; + list->last = NULL; +} + +/* end list API */ + + +/* forward declarations */ +static void rt_node_free(RangeTreeUInt *rt, Node *node); + + +#ifdef USE_BTREE + +#ifdef DEBUG +static bool rb_is_balanced_root(const Node *root); +#endif + +/* ------------------------------------------------------------------------- */ +/* Internal BTree API + * + * Left-leaning red-black tree. + */ + +/* use minimum, could use max too since nodes never overlap */ +#define KEY(n) ((n)->min) + +enum { + RED = 0, + BLACK = 1, +}; + + +static bool is_red(const Node *node) +{ + return (node && (node->color == RED)); +} + +static int key_cmp(uint key1, uint key2) +{ + return (key1 == key2) ? 0 : ((key1 < key2) ? -1 : 1); +} + +/* removed from the tree */ +static void rb_node_invalidate(Node *node) +{ +#ifdef DEBUG + node->left = NULL; + node->right = NULL; + node->color = false; +#else + (void)node; +#endif +} + +static void rb_flip_color(Node *node) +{ + node->color ^= 1; + node->left->color ^= 1; + node->right->color ^= 1; +} + +static Node *rb_rotate_left(Node *left) +{ + /* Make a right-leaning 3-node lean to the left. */ + Node *right = left->right; + left->right = right->left; + right->left = left; + right->color = left->color; + left->color = RED; + return right; +} + +static Node *rb_rotate_right(Node *right) +{ + /* Make a left-leaning 3-node lean to the right. */ + Node *left = right->left; + right->left = left->right; + left->right = right; + left->color = right->color; + right->color = RED; + return left; +} + +/* Fixup colors when insert happened */ +static Node *rb_fixup_insert(Node *node) +{ + if (is_red(node->right) && !is_red(node->left)) { + node = rb_rotate_left(node); + } + if (is_red(node->left) && is_red(node->left->left)) { + node = rb_rotate_right(node); + } + + if (is_red(node->left) && is_red(node->right)) { + rb_flip_color(node); + } + + return node; +} + +static Node *rb_insert_recursive(Node *node, Node *node_to_insert) +{ + if (node == NULL) { + return node_to_insert; + } + + const int cmp = key_cmp(KEY(node_to_insert), KEY(node)); + if (cmp == 0) { + /* caller ensures no collisions */ + assert(0); + } + else if (cmp == -1) { + node->left = rb_insert_recursive(node->left, node_to_insert); + } + else { + node->right = rb_insert_recursive(node->right, node_to_insert); + } + + return rb_fixup_insert(node); +} + +static Node *rb_insert_root(Node *root, Node *node_to_insert) +{ + root = rb_insert_recursive(root, node_to_insert); + root->color = BLACK; + return root; +} + +static Node *rb_move_red_to_left(Node *node) +{ + /* Assuming that h is red and both h->left and h->left->left + * are black, make h->left or one of its children red. + */ + rb_flip_color(node); + if (node->right && is_red(node->right->left)) { + node->right = rb_rotate_right(node->right); + node = rb_rotate_left(node); + rb_flip_color(node); + } + return node; +} + +static Node *rb_move_red_to_right(Node *node) +{ + /* Assuming that h is red and both h->right and h->right->left + * are black, make h->right or one of its children red. + */ + rb_flip_color(node); + if (node->left && is_red(node->left->left)) { + node = rb_rotate_right(node); + rb_flip_color(node); + } + return node; +} + +/* Fixup colors when remove happened */ +static Node *rb_fixup_remove(Node *node) +{ + if (is_red(node->right)) { + node = rb_rotate_left(node); + } + if (is_red(node->left) && is_red(node->left->left)) { + node = rb_rotate_right(node); + } + if (is_red(node->left) && is_red(node->right)) { + rb_flip_color(node); + } + return node; +} + +static Node *rb_pop_min_recursive(Node *node, Node **r_node_pop) +{ + if (node == NULL) { + return NULL; + } + if (node->left == NULL) { + rb_node_invalidate(node); + *r_node_pop = node; + return NULL; + } + if ((!is_red(node->left)) && (!is_red(node->left->left))) { + node = rb_move_red_to_left(node); + } + node->left = rb_pop_min_recursive(node->left, r_node_pop); + return rb_fixup_remove(node); +} + +static Node *rb_remove_recursive(Node *node, const Node *node_to_remove) +{ + if (node == NULL) { + return NULL; + } + if (key_cmp(KEY(node_to_remove), KEY(node)) == -1) { + if (node->left != NULL) { + if ((!is_red(node->left)) && (!is_red(node->left->left))) { + node = rb_move_red_to_left(node); + } + } + node->left = rb_remove_recursive(node->left, node_to_remove); + } + else { + if (is_red(node->left)) { + node = rb_rotate_right(node); + } + if ((node == node_to_remove) && (node->right == NULL)) { + rb_node_invalidate(node); + return NULL; + } + assert(node->right != NULL); + if ((!is_red(node->right)) && (!is_red(node->right->left))) { + node = rb_move_red_to_right(node); + } + + if (node == node_to_remove) { + /* minor improvement over original method: + * no need to double lookup min */ + Node *node_free; /* will always be set */ + node->right = rb_pop_min_recursive(node->right, &node_free); + + node_free->left = node->left; + node_free->right = node->right; + node_free->color = node->color; + + rb_node_invalidate(node); + node = node_free; + } + else { + node->right = rb_remove_recursive(node->right, node_to_remove); + } + } + return rb_fixup_remove(node); +} + +static Node *rb_btree_remove(Node *root, const Node *node_to_remove) +{ + root = rb_remove_recursive(root, node_to_remove); + if (root != NULL) { + root->color = BLACK; + } + return root; +} + +/* + * Returns the node closest to and including 'key', + * excluding anything below. + */ +static Node *rb_get_or_upper_recursive(Node *n, const uint key) +{ + if (n == NULL) { + return NULL; + } + const int cmp_upper = key_cmp(KEY(n), key); + if (cmp_upper == 0) { + return n; // exact match + } + else if (cmp_upper == 1) { + assert(KEY(n) >= key); + Node *n_test = rb_get_or_upper_recursive(n->left, key); + return n_test ? n_test : n; + } + else { // cmp_upper == -1 + return rb_get_or_upper_recursive(n->right, key); + } +} + +/* + * Returns the node closest to and including 'key', + * excluding anything above. + */ +static Node *rb_get_or_lower_recursive(Node *n, const uint key) +{ + if (n == NULL) { + return NULL; + } + const int cmp_lower = key_cmp(KEY(n), key); + if (cmp_lower == 0) { + return n; // exact match + } + else if (cmp_lower == -1) { + assert(KEY(n) <= key); + Node *n_test = rb_get_or_lower_recursive(n->right, key); + return n_test ? n_test : n; + } + else { // cmp_lower == 1 + return rb_get_or_lower_recursive(n->left, key); + } +} + +#ifdef DEBUG + +static bool rb_is_balanced_recursive(const Node *node, int black) +{ + // Does every path from the root to a leaf have the given number + // of black links? + if (node == NULL) { + return black == 0; + } + if (!is_red(node)) { + black--; + } + return rb_is_balanced_recursive(node->left, black) && + rb_is_balanced_recursive(node->right, black); +} + +static bool rb_is_balanced_root(const Node *root) +{ + // Do all paths from root to leaf have same number of black edges? + int black = 0; // number of black links on path from root to min + const Node *node = root; + while (node != NULL) { + if (!is_red(node)) { + black++; + } + node = node->left; + } + return rb_is_balanced_recursive(root, black); +} + +#endif // DEBUG + + +/* End BTree API */ +#endif // USE_BTREE + + +/* ------------------------------------------------------------------------- */ +/* Internal RangeTreeUInt API */ + +static inline Node *rt_node_alloc(RangeTreeUInt *rt) +{ +#ifdef USE_TPOOL + return rt_node_pool_elem_alloc(&rt->epool); +#else + (void)rt; + return malloc(sizeof(Node)); +#endif +} + +static Node *rt_node_new(RangeTreeUInt *rt, uint min, uint max) +{ + Node *node = rt_node_alloc(rt); + + assert(min <= max); + node->prev = NULL; + node->next = NULL; + node->min = min; + node->max = max; +#ifdef USE_BTREE + node->left = NULL; + node->right = NULL; +#endif + return node; +} + +static void rt_node_free(RangeTreeUInt *rt, Node *node) +{ +#ifdef USE_TPOOL + rt_node_pool_elem_free(&rt->epool, node); +#else + (void)rt; + free(node); +#endif +} + +#ifdef USE_BTREE +static void rt_btree_insert(RangeTreeUInt *rt, Node *node) +{ + node->color = RED; + node->left = NULL; + node->right = NULL; + rt->root = rb_insert_root(rt->root, node); +} +#endif + +static void rt_node_add_back(RangeTreeUInt *rt, Node *node) +{ + list_push_back(&rt->list, node); +#ifdef USE_BTREE + rt_btree_insert(rt, node); +#endif +} +static void rt_node_add_front(RangeTreeUInt *rt, Node *node) +{ + list_push_front(&rt->list, node); +#ifdef USE_BTREE + rt_btree_insert(rt, node); +#endif +} +static void rt_node_add_before(RangeTreeUInt *rt, Node *node_next, Node *node) +{ + list_push_before(&rt->list, node_next, node); +#ifdef USE_BTREE + rt_btree_insert(rt, node); +#endif +} +static void rt_node_add_after(RangeTreeUInt *rt, Node *node_prev, Node *node) +{ + list_push_after(&rt->list, node_prev, node); +#ifdef USE_BTREE + rt_btree_insert(rt, node); +#endif +} + +static void rt_node_remove(RangeTreeUInt *rt, Node *node) +{ + list_remove(&rt->list, node); +#ifdef USE_BTREE + rt->root = rb_btree_remove(rt->root, node); +#endif + rt_node_free(rt, node); +} + +static Node *rt_find_node_from_value(RangeTreeUInt *rt, const uint value) +{ +#ifdef USE_BTREE + Node *node = rb_get_or_lower_recursive(rt->root, value); + if (node != NULL) { + if ((value >= node->min) && (value <= node->max)) { + return node; + } + } + return NULL; +#else + for (Node *node = rt->list.first; node; node = node->next) { + if ((value >= node->min) && (value <= node->max)) { + return node; + } + } + return NULL; +#endif // USE_BTREE +} + +static void rt_find_node_pair_around_value(RangeTreeUInt *rt, const uint value, + Node **r_node_prev, Node **r_node_next) +{ + if (value < rt->list.first->min) { + *r_node_prev = NULL; + *r_node_next = rt->list.first; + return; + } + else if (value > rt->list.last->max) { + *r_node_prev = rt->list.last; + *r_node_next = NULL; + return; + } + else { +#ifdef USE_BTREE + Node *node_next = rb_get_or_upper_recursive(rt->root, value); + if (node_next != NULL) { + Node *node_prev = node_next->prev; + if ((node_prev->max < value) && (value < node_next->min)) { + *r_node_prev = node_prev; + *r_node_next = node_next; + return; + } + } +#else + Node *node_prev = rt->list.first; + Node *node_next; + while ((node_next = node_prev->next)) { + if ((node_prev->max < value) && (value < node_next->min)) { + *r_node_prev = node_prev; + *r_node_next = node_next; + return; + } + node_prev = node_next; + } +#endif // USE_BTREE + } + *r_node_prev = NULL; + *r_node_next = NULL; +} + + +/* ------------------------------------------------------------------------- */ +/* Public API */ + +static RangeTreeUInt *rt_create_empty(uint min, uint max) +{ + RangeTreeUInt *rt = malloc(sizeof(*rt)); + rt->range[0] = min; + rt->range[1] = max; + + list_clear(&rt->list); + +#ifdef USE_BTREE + rt->root = NULL; +#endif +#ifdef USE_TPOOL + rt_node_pool_create(&rt->epool, 512); +#endif + + return rt; +} + +RangeTreeUInt *range_tree_uint_alloc(uint min, uint max) +{ + RangeTreeUInt *rt = rt_create_empty(min, max); + + Node *node = rt_node_new(rt, min, max); + rt_node_add_front(rt, node); + return rt; +} + +void range_tree_uint_free(RangeTreeUInt *rt) +{ +#ifdef DEBUG +#ifdef USE_BTREE + assert(rb_is_balanced_root(rt->root)); +#endif +#endif + +#ifdef USE_TPOOL + + rt_node_pool_destroy(&rt->epool); +#else + for (Node *node = rt->list.first, *node_next; node; node = node_next) { + node_next = node->next; + rt_node_free(rt, node); + } +#endif + + free(rt); +} + +#ifdef USE_BTREE +static Node *rt_copy_recursive(RangeTreeUInt *rt_dst, const Node *node_src) +{ + if (node_src == NULL) { + return NULL; + } + + Node *node_dst = rt_node_alloc(rt_dst); + + *node_dst = *node_src; + node_dst->left = rt_copy_recursive(rt_dst, node_dst->left); + list_push_back(&rt_dst->list, node_dst); + node_dst->right = rt_copy_recursive(rt_dst, node_dst->right); + + return node_dst; +} +#endif // USE_BTREE + +RangeTreeUInt *range_tree_uint_copy(const RangeTreeUInt *rt_src) +{ + RangeTreeUInt *rt_dst = rt_create_empty(rt_src->range[0], rt_src->range[1]); +#ifdef USE_BTREE + rt_dst->root = rt_copy_recursive(rt_dst, rt_src->root); +#else + for (Node *node_src = rt_src->list.first; node_src; node_src = node_src->next) { + Node *node_dst = rt_node_alloc(rt_dst); + *node_dst = *node_src; + list_push_back(&rt_dst->list, node_dst); + } +#endif + return rt_dst; +} + +/** + * Return true if the tree has the value (not taken). + */ +bool range_tree_uint_has(RangeTreeUInt *rt, const uint value) +{ + assert(value >= rt->range[0] && value <= rt->range[1]); + Node *node = rt_find_node_from_value(rt, value); + return (node != NULL); +} + +static void range_tree_uint_take_impl(RangeTreeUInt *rt, const uint value, Node *node) +{ + assert(node == rt_find_node_from_value(rt, value)); + if (node->min == value) { + if (node->max != value) { + node->min += 1; + } + else { + assert(node->min == node->max); + rt_node_remove(rt, node); + } + } + else if (node->max == value) { + node->max -= 1; + } + else { + Node *node_next = rt_node_new(rt, value + 1, node->max); + node->max = value - 1; + rt_node_add_after(rt, node, node_next); + } +} + +void range_tree_uint_take(RangeTreeUInt *rt, const uint value) +{ + Node *node = rt_find_node_from_value(rt, value); + assert(node != NULL); + range_tree_uint_take_impl(rt, value, node); +} + +bool range_tree_uint_retake(RangeTreeUInt *rt, const uint value) +{ + Node *node = rt_find_node_from_value(rt, value); + if (node != NULL) { + range_tree_uint_take_impl(rt, value, node); + return true; + } + else { + return false; + } +} + +uint range_tree_uint_take_any(RangeTreeUInt *rt) +{ + Node *node = node = rt->list.first; + uint value = node->min; + if (value == node->max) { + rt_node_remove(rt, node); + } + else { + node->min += 1; + } + return value; +} + +void range_tree_uint_release(RangeTreeUInt *rt, const uint value) +{ + bool touch_prev, touch_next; + Node *node_prev, *node_next; + + if (rt->list.first != NULL) { + rt_find_node_pair_around_value(rt, value, &node_prev, &node_next); + /* the value must have been already taken */ + assert(node_prev || node_next); + + /* Cases: + * 1) fill the gap between prev & next (two spans into one span). + * 2) touching prev, (grow node_prev->max up one). + * 3) touching next, (grow node_next->min down one). + * 4) touching neither, add a new segment. */ + touch_prev = (node_prev != NULL && node_prev->max + 1 == value); + touch_next = (node_next != NULL && node_next->min - 1 == value); + } + else { + // we could handle this case (4) inline, + // since its not a common case - use regular logic. + node_prev = node_next = NULL; + touch_prev = false; + touch_next = false; + } + + if (touch_prev && touch_next) { // 1) + node_prev->max = node_next->max; + rt_node_remove(rt, node_next); + } + else if (touch_prev) { // 2) + assert(node_prev->max + 1 == value); + node_prev->max = value; + } + else if (touch_next) { // 3) + assert(node_next->min - 1 == value); + node_next->min = value; + } + else { // 4) + Node *node_new = rt_node_new(rt, value, value); + if (node_prev != NULL) { + rt_node_add_after(rt, node_prev, node_new); + } + else if (node_next != NULL) { + rt_node_add_before(rt, node_next, node_new); + } + else { + assert(rt->list.first == NULL); + rt_node_add_back(rt, node_new); + } + } +} diff --git a/extern/rangetree/range_tree.h b/extern/rangetree/range_tree.h new file mode 100644 index 00000000000..b46832b5cdb --- /dev/null +++ b/extern/rangetree/range_tree.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016, Campbell Barton. + * + * Licensed under the Apache License, Version 2.0 (the "Apache License") + * with the following modification; you may not use this file except in + * compliance with the Apache License and the following modification to it: + * Section 6. Trademarks. is deleted and replaced with: + * + * 6. Trademarks. This License does not grant permission to use the trade + * names, trademarks, service marks, or product names of the Licensor + * and its affiliates, except as required to comply with Section 4(c) of + * the License and to reproduce the content of the NOTICE file. + * + * You may obtain a copy of the Apache License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Apache License with the above modification is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the Apache License for the specific + * language governing permissions and limitations under the Apache License. + */ + +#ifndef __RANGE_TREE_H__ +#define __RANGE_TREE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct RangeTreeUInt RangeTreeUInt; + +struct RangeTreeUInt *range_tree_uint_alloc(unsigned int min, unsigned int max); +void range_tree_uint_free(struct RangeTreeUInt *rt); +struct RangeTreeUInt *range_tree_uint_copy(const struct RangeTreeUInt *rt_src); + +bool range_tree_uint_has(struct RangeTreeUInt *rt, const unsigned int value); +void range_tree_uint_take(struct RangeTreeUInt *rt, const unsigned int value); +bool range_tree_uint_retake(struct RangeTreeUInt *rt, const unsigned int value); +unsigned int range_tree_uint_take_any(struct RangeTreeUInt *rt); +void range_tree_uint_release(struct RangeTreeUInt *rt, const unsigned int value); + +#ifdef __cplusplus +} +#endif + +#endif /* __RANGE_TREE_H__ */ diff --git a/extern/rangetree/range_tree.hh b/extern/rangetree/range_tree.hh deleted file mode 100644 index b247a0c6a1e..00000000000 --- a/extern/rangetree/range_tree.hh +++ /dev/null @@ -1,251 +0,0 @@ -/* This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include -#include -#include -#include - -#ifndef RANGE_TREE_DEBUG_PRINT_FUNCTION -# define RANGE_TREE_DEBUG_PRINT_FUNCTION 0 -#endif - -template -struct RangeTree { - struct Range { - Range(T min_, T max_) - : min(min_), max(max_), single(min_ == max_) { - assert(min_ <= max_); - } - - Range(T t) - : min(t), max(t), single(true) - {} - - Range& operator=(const Range& v) { - *this = v; - return *this; - } - - bool operator<(const Range& v) const { - return max < v.min; - } - - const T min; - const T max; - const bool single; - }; - - typedef std::set Tree; - typedef typename Tree::iterator TreeIter; - typedef typename Tree::reverse_iterator TreeIterReverse; - typedef typename Tree::const_iterator TreeIterConst; - - /* Initialize with a single range from 'min' to 'max', inclusive. */ - RangeTree(T min, T max) { - tree.insert(Range(min, max)); - } - - /* Initialize with a single range from 0 to 'max', inclusive. */ - RangeTree(T max) { - tree.insert(Range(0, max)); - } - - RangeTree(const RangeTree& src) { - tree = src.tree; - } - - /* Remove 't' from the associated range in the tree. Precondition: - a range including 't' must exist in the tree. */ - void take(T t) { - #if RANGE_TREE_DEBUG_PRINT_FUNCTION - std::cout << __func__ << "(" << t << ")\n"; - #endif - - /* Find the range that includes 't' and its neighbors */ - TreeIter iter = tree.find(Range(t)); - assert(iter != tree.end()); - Range cur = *iter; - - /* Remove the original range (note that this does not - invalidate the prev/next iterators) */ - tree.erase(iter); - - /* Construct two new ranges that together cover the original - range, except for 't' */ - if (t > cur.min) - tree.insert(Range(cur.min, t - 1)); - if (t + 1 <= cur.max) - tree.insert(Range(t + 1, cur.max)); - } - - /* clone of 'take' that checks if the item exists */ - bool retake(T t) { - #if RANGE_TREE_DEBUG_PRINT_FUNCTION - std::cout << __func__ << "(" << t << ")\n"; - #endif - - TreeIter iter = tree.find(Range(t)); - if (iter == tree.end()) { - return false; - } - - Range cur = *iter; - tree.erase(iter); - if (t > cur.min) - tree.insert(Range(cur.min, t - 1)); - if (t + 1 <= cur.max) - tree.insert(Range(t + 1, cur.max)); - - return true; - } - - - /* Take the first element out of the first range in the - tree. Precondition: tree must not be empty. */ - T take_any() { - #if RANGE_TREE_DEBUG_PRINT_FUNCTION - std::cout << __func__ << "()\n"; - #endif - - /* Find the first element */ - TreeIter iter = tree.begin(); - assert(iter != tree.end()); - T first = iter->min; - - /* Take the first element */ - take(first); - return first; - } - - /* Return 't' to the tree, either expanding/merging existing - ranges or adding a range to cover it. Precondition: 't' cannot - be in an existing range. */ - void release(T t) { - #if RANGE_TREE_DEBUG_PRINT_FUNCTION - std::cout << __func__ << "(" << t << ")\n"; - #endif - - /* TODO: these cases should be simplified/unified */ - - TreeIter right = tree.upper_bound(t); - if (right != tree.end()) { - TreeIter left = right; - if (left != tree.begin()) - --left; - - if (left == right) { - /* 't' lies before any existing ranges */ - if (t + 1 == left->min) { - /* 't' lies directly before the first range, - resize and replace that range */ - const Range r(t, left->max); - tree.erase(left); - tree.insert(r); - } - else { - /* There's a gap between 't' and the first range, - add a new range */ - tree.insert(Range(t)); - } - } - else if ((left->max + 1 == t) && - (t + 1 == right->min)) { - /* 't' fills a hole. Remove left and right, and insert a - new range that covers both. */ - const Range r(left->min, right->max); - tree.erase(left); - tree.erase(right); - tree.insert(r); - } - else if (left->max + 1 == t) { - /* 't' lies directly after 'left' range, resize and - replace that range */ - const Range r(left->min, t); - tree.erase(left); - tree.insert(r); - } - else if (t + 1 == right->min) { - /* 't' lies directly before 'right' range, resize and - replace that range */ - const Range r(t, right->max); - tree.erase(right); - tree.insert(r); - } - else { - /* There's a gap between 't' and both adjacent ranges, - add a new range */ - tree.insert(Range(t)); - } - } - else { - /* 't' lies after any existing ranges */ - right = tree.end(); - right--; - if (right->max + 1 == t) { - /* 't' lies directly after last range, resize and - replace that range */ - const Range r(right->min, t); - tree.erase(right); - tree.insert(r); - } - else { - /* There's a gap between the last range and 't', add a - new range */ - tree.insert(Range(t)); - } - } - } - - bool has(T t) const { - TreeIterConst iter = tree.find(Range(t)); - return (iter != tree.end()) && (t <= iter->max); - } - - bool has_range(T min, T max) const { - TreeIterConst iter = tree.find(Range(min, max)); - return (iter != tree.end()) && (min == iter->min && max == iter->max); - } - - bool empty() const { - return tree.empty(); - } - - int size() const { - return tree.size(); - } - - void print() const { - std::cout << "RangeTree:\n"; - for (TreeIterConst iter = tree.begin(); iter != tree.end(); ++iter) { - const Range& r = *iter; - if (r.single) - std::cout << " [" << r.min << "]\n"; - else - std::cout << " [" << r.min << ", " << r.max << "]\n"; - } - if (empty()) - std::cout << " "; - std::cout << "\n"; - } - - unsigned int allocation_lower_bound() const { - return tree.size() * sizeof(Range); - } - -private: - Tree tree; -}; diff --git a/extern/rangetree/range_tree_c_api.cc b/extern/rangetree/range_tree_c_api.cc deleted file mode 100644 index f040b5eaeb6..00000000000 --- a/extern/rangetree/range_tree_c_api.cc +++ /dev/null @@ -1,92 +0,0 @@ -/* This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#include "range_tree.hh" - -/* Give RangeTreeUInt a real type rather than the opaque struct type - defined for external use. */ -#define RANGE_TREE_C_API_INTERNAL -typedef RangeTree RangeTreeUInt; - -#include "range_tree_c_api.h" - -RangeTreeUInt *range_tree_uint_alloc(unsigned min, unsigned max) -{ - return new RangeTreeUInt(min, max); -} - -RangeTreeUInt *range_tree_uint_copy(RangeTreeUInt *src) -{ - return new RangeTreeUInt(*src); -} - -void range_tree_uint_free(RangeTreeUInt *rt) -{ - delete rt; -} - -void range_tree_uint_take(RangeTreeUInt *rt, unsigned v) -{ - rt->take(v); -} - -bool range_tree_uint_retake(RangeTreeUInt *rt, unsigned v) -{ - return rt->retake(v); -} - -unsigned range_tree_uint_take_any(RangeTreeUInt *rt) -{ - return rt->take_any(); -} - -void range_tree_uint_release(RangeTreeUInt *rt, unsigned v) -{ - rt->release(v); -} - -bool range_tree_uint_has(const RangeTreeUInt *rt, unsigned v) -{ - return rt->has(v); -} - -bool range_tree_uint_has_range( - const RangeTreeUInt *rt, - unsigned vmin, - unsigned vmax) -{ - return rt->has_range(vmin, vmax); -} - -bool range_tree_uint_empty(const RangeTreeUInt *rt) -{ - return rt->empty(); -} - -unsigned range_tree_uint_size(const RangeTreeUInt *rt) -{ - return rt->size(); -} - -void range_tree_uint_print(const RangeTreeUInt *rt) -{ - rt->print(); -} - -unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt) -{ - return rt->allocation_lower_bound(); -} diff --git a/extern/rangetree/range_tree_c_api.h b/extern/rangetree/range_tree_c_api.h deleted file mode 100644 index 6abfb6bd55e..00000000000 --- a/extern/rangetree/range_tree_c_api.h +++ /dev/null @@ -1,62 +0,0 @@ -/* This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. -*/ - -#ifndef __RANGE_TREE_C_API_H__ -#define __RANGE_TREE_C_API_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Simple C-accessible wrapper for RangeTree */ - -#ifndef RANGE_TREE_C_API_INTERNAL -typedef struct RangeTreeUInt RangeTreeUInt; -#endif - -RangeTreeUInt *range_tree_uint_alloc(unsigned min, unsigned max); - -RangeTreeUInt *range_tree_uint_copy(RangeTreeUInt *src); - -void range_tree_uint_free(RangeTreeUInt *rt); - -void range_tree_uint_take(RangeTreeUInt *rt, unsigned v); - -bool range_tree_uint_retake(RangeTreeUInt *rt, unsigned v); - -unsigned range_tree_uint_take_any(RangeTreeUInt *rt); - -void range_tree_uint_release(RangeTreeUInt *rt, unsigned v); - -bool range_tree_uint_has(const RangeTreeUInt *rt, unsigned v); - -bool range_tree_uint_has_range( - const RangeTreeUInt *rt, - unsigned vmin, unsigned vmax); - -bool range_tree_uint_empty(const RangeTreeUInt *rt); - -unsigned range_tree_uint_size(const RangeTreeUInt *rt); - -void range_tree_uint_print(const RangeTreeUInt *rt); - -unsigned int range_tree_uint_allocation_lower_bound(const RangeTreeUInt *rt); - -#ifdef __cplusplus -} -#endif - -#endif /* __RANGE_TREE_C_API_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c index 1f64f7b74cc..2591c33fc73 100644 --- a/source/blender/bmesh/intern/bmesh_log.c +++ b/source/blender/bmesh/intern/bmesh_log.c @@ -45,7 +45,7 @@ #include "bmesh.h" #include "bmesh_log.h" -#include "range_tree_c_api.h" +#include "range_tree.h" #include "BLI_strict_flags.h" From 7c7d23691fc8583967a17dc501b9fb94f101990b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 26 Oct 2016 14:27:31 +0200 Subject: [PATCH 049/590] Cycles: Fix crashes after recent optimization commits There is some precision issues for big magnitude coordinates which started to give weird behavior of release builds. Some weird memory usage in BVH which is tricky to nail down because only happens in release builds and GDB reports all variables as optimized out when trying to use RelWithDebInfo. There are two things in this commit: - Attempt to make vectorized code closer to original one, hoping that it'll eliminate precision issue. This seems to work for transform_point(). - Similar trick did not work for transform_direction() even tho absolute error here is much smaller. For now disabled that function, need a more careful look here. --- intern/cycles/util/util_transform.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index 771a9442cb3..1bac3c150cb 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -84,9 +84,10 @@ ccl_device_inline float3 transform_point(const Transform *t, const float3 a) _MM_TRANSPOSE4_PS(x, y, z, w); - ssef tmp = madd(x, shuffle<0>(aa), w); - tmp = madd(y, shuffle<1>(aa), tmp); - tmp = madd(z, shuffle<2>(aa), tmp); + ssef tmp = shuffle<0>(aa) * x; + tmp = madd(shuffle<1>(aa), y, tmp); + tmp = madd(shuffle<2>(aa), z, tmp); + tmp += w; return float3(tmp.m128); #else @@ -101,7 +102,8 @@ ccl_device_inline float3 transform_point(const Transform *t, const float3 a) ccl_device_inline float3 transform_direction(const Transform *t, const float3 a) { -#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) + /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) && 0 ssef x, y, z, w, aa; aa = a.m128; x = _mm_loadu_ps(&t->x.x); @@ -111,9 +113,9 @@ ccl_device_inline float3 transform_direction(const Transform *t, const float3 a) _MM_TRANSPOSE4_PS(x, y, z, w); - ssef tmp = x * shuffle<0>(aa); - tmp = madd(y, shuffle<1>(aa), tmp); - tmp = madd(z, shuffle<2>(aa), tmp); + ssef tmp = shuffle<0>(aa) * x; + tmp = madd(shuffle<1>(aa), y, tmp); + tmp = madd(shuffle<2>(aa), z, tmp); return float3(tmp.m128); #else From 35f152358b2af9e0b71be4c78d4381c3f474ffcd Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 26 Oct 2016 15:23:58 +0200 Subject: [PATCH 050/590] Cycles: Completely disable transform SSE for now Was causing issues on another frame. On a tight schedule, disabling for now so artists are happy. Still looking into root of the issue! --- intern/cycles/util/util_transform.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index 1bac3c150cb..ea5eb3b25b0 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -73,7 +73,8 @@ ccl_device_inline float3 transform_perspective(const Transform *t, const float3 ccl_device_inline float3 transform_point(const Transform *t, const float3 a) { -#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) + /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) && 0 ssef x, y, z, w, aa; aa = a.m128; From de22e55291029126d1964de1c616d6b70a62e6bf Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 26 Oct 2016 20:49:33 +0200 Subject: [PATCH 051/590] Cycles: Fix compilation error of AVX2 kernel without SSE math --- intern/cycles/kernel/geom/geom_triangle_intersect.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index 5d76fc3dc58..eb7340583c8 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -120,7 +120,7 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, /* Calculate vertices relative to ray origin. */ const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr); -#if defined(__KERNEL_AVX2__) +#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__) const avxf avxf_P(P.m128, P.m128); const avxf tri_ab = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 0); @@ -282,7 +282,7 @@ ccl_device_inline void triangle_intersect_subsurface( tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); -#if defined(__KERNEL_AVX2__) +#if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__) const avxf avxf_P(P.m128, P.m128); const avxf tri_ab = kernel_tex_fetch_avxf(__prim_tri_verts, tri_vindex + 0); From 7e380ad4c0236e6e572023e85694acec3da28e6e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 26 Oct 2016 22:14:41 +0200 Subject: [PATCH 052/590] Cycles: Another attempt to fix crashes on AVX2 processors Basically don't use rcp() in areas which seems to be critical after second look. Also disabled some multiplication operators, not sure yet why they might be a problem. Tomorrow will be setting up a full test with all cases which were buggy in our farm to see if this fix is complete. --- intern/cycles/kernel/geom/geom_object.h | 3 ++- intern/cycles/util/util_math.h | 22 ++++++++++++---------- intern/cycles/util/util_transform.h | 5 ++--- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index cb2de3a7e87..32900f7f27a 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -397,7 +397,8 @@ ccl_device_inline float3 bvh_clamp_direction(float3 dir) ccl_device_inline float3 bvh_inverse_direction(float3 dir) { -#ifdef __KERNEL_SSE__ + /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */ +#if defined(__KERNEL_SSE__) && 0 return rcp(dir); #else return 1.0f / dir; diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 57cad39d1eb..f0c7492d88a 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -453,8 +453,9 @@ ccl_device_inline float3 operator*(const float3& a, const float f) ccl_device_inline float3 operator*(const float f, const float3& a) { -#ifdef __KERNEL_SSE__ - return float3(_mm_mul_ps(a.m128, _mm_set1_ps(f))); + /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */ +#if defined(__KERNEL_SSE__) && 0 + return float3(_mm_mul_ps(_mm_set1_ps(f), a.m128)); #else return make_float3(a.x*f, a.y*f, a.z*f); #endif @@ -462,13 +463,13 @@ ccl_device_inline float3 operator*(const float f, const float3& a) ccl_device_inline float3 operator/(const float f, const float3& a) { - /* TODO(sergey): Currently disabled, gives speedup but makes intersection tets non-watertight. */ -// #ifdef __KERNEL_SSE__ -// __m128 rc = _mm_rcp_ps(a.m128); -// return float3(_mm_mul_ps(_mm_set1_ps(f),rc)); -// #else + /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */ +#if defined(__KERNEL_SSE__) && 0 + __m128 rc = _mm_rcp_ps(a.m128); + return float3(_mm_mul_ps(_mm_set1_ps(f),rc)); +#else return make_float3(f / a.x, f / a.y, f / a.z); -// #endif +#endif } ccl_device_inline float3 operator/(const float3& a, const float f) @@ -479,7 +480,8 @@ ccl_device_inline float3 operator/(const float3& a, const float f) ccl_device_inline float3 operator/(const float3& a, const float3& b) { -#ifdef __KERNEL_SSE__ + /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */ +#if defined(__KERNEL_SSE__) && 0 __m128 rc = _mm_rcp_ps(b.m128); return float3(_mm_mul_ps(a, rc)); #else @@ -799,7 +801,7 @@ ccl_device_inline float4 operator*(const float4& a, const float4& b) ccl_device_inline float4 operator*(const float4& a, float f) { -#ifdef __KERNEL_SSE__ +#if defined(__KERNEL_SSE__) return a * make_float4(f); #else return make_float4(a.x*f, a.y*f, a.z*f, a.w*f); diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index ea5eb3b25b0..a0695f20488 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -74,7 +74,7 @@ ccl_device_inline float3 transform_perspective(const Transform *t, const float3 ccl_device_inline float3 transform_point(const Transform *t, const float3 a) { /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ -#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) && 0 +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) ssef x, y, z, w, aa; aa = a.m128; @@ -103,8 +103,7 @@ ccl_device_inline float3 transform_point(const Transform *t, const float3 a) ccl_device_inline float3 transform_direction(const Transform *t, const float3 a) { - /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ -#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) && 0 +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) ssef x, y, z, w, aa; aa = a.m128; x = _mm_loadu_ps(&t->x.x); From f11298692b93c79132b77d0795e6bd6080c62480 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 27 Oct 2016 12:51:03 +0200 Subject: [PATCH 053/590] Cycles: More workarounds for weird crashes on AVX2 Oh man, is it a compiler bug? Is it something we do stupid? For now more crap to prevent crashes. During the conference will talk to Maxyn about how can we troubleshoot such weird issues. --- intern/cycles/util/util_math.h | 9 ++++++--- intern/cycles/util/util_transform.h | 5 +++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index f0c7492d88a..bd376e80c64 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -591,7 +591,8 @@ ccl_device_inline float len_squared(const float4& a) ccl_device_inline float3 normalize(const float3& a) { -#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) + /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ +#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) && 0 __m128 norm = _mm_sqrt_ps(_mm_dp_ps(a.m128, a.m128, 0x7F)); return _mm_div_ps(a.m128, norm); #else @@ -792,7 +793,8 @@ ccl_device_inline float4 operator-(const float4& a) ccl_device_inline float4 operator*(const float4& a, const float4& b) { -#ifdef __KERNEL_SSE__ + /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ +#if defined(__KERNEL_SSE__) && 0 return _mm_mul_ps(a.m128, b.m128); #else return make_float4(a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w); @@ -840,7 +842,8 @@ ccl_device_inline float4 operator/(const float4& a, const float4& b) ccl_device_inline float4 operator+(const float4& a, const float4& b) { -#ifdef __KERNEL_SSE__ + /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ +#if defined(__KERNEL_SSE__) && 0 return _mm_add_ps(a.m128, b.m128); #else return make_float4(a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w); diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index a0695f20488..ea5eb3b25b0 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -74,7 +74,7 @@ ccl_device_inline float3 transform_perspective(const Transform *t, const float3 ccl_device_inline float3 transform_point(const Transform *t, const float3 a) { /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ -#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) && 0 ssef x, y, z, w, aa; aa = a.m128; @@ -103,7 +103,8 @@ ccl_device_inline float3 transform_point(const Transform *t, const float3 a) ccl_device_inline float3 transform_direction(const Transform *t, const float3 a) { -#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) + /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) && 0 ssef x, y, z, w, aa; aa = a.m128; x = _mm_loadu_ps(&t->x.x); From 5f0933f07a548719a850d9cac01aae6709b9dc0b Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 27 Oct 2016 09:51:10 +0200 Subject: [PATCH 054/590] Fix T49829: Removal of custom icon previews during add-on unregister crashes Blender. Issue was happening when removal of custom icons was done while they were still being rendered by preview job. Now add a 'deffered deletion' system, to prevent main thread to delete preview image until loading thread is done with them. Note that ideally, calling `ED_preview_kill_jobs()` on custom icon removal would have been simpler, but we don't have easy access to context here... --- source/blender/blenkernel/BKE_icons.h | 1 + source/blender/blenkernel/intern/icons.c | 20 +++++++++--- source/blender/blenloader/intern/readfile.c | 1 + .../editors/interface/interface_icons.c | 2 +- .../blender/editors/render/render_preview.c | 31 ++++++++++++++++--- source/blender/makesdna/DNA_ID.h | 13 ++++++-- 6 files changed, 54 insertions(+), 14 deletions(-) diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index efef8d4be78..6944c5ccd28 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -114,6 +114,7 @@ struct PreviewImage *BKE_previewimg_cached_thumbnail_read( const char *name, const char *path, const int source, bool force_update); void BKE_previewimg_cached_release(const char *name); +void BKE_previewimg_cached_release_pointer(struct PreviewImage *prv); #define ICON_RENDER_DEFAULT_HEIGHT 32 diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index 2d5b15c8f9d..7669c4ba112 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -143,7 +143,7 @@ static PreviewImage *previewimg_create_ex(size_t deferred_data_size) memset(prv_img, 0, sizeof(*prv_img)); /* leave deferred data dirty */ if (deferred_data_size) { - prv_img->use_deferred = true; + prv_img->tag |= PRV_TAG_DEFFERED; } for (i = 0; i < NUM_ICON_SIZES; ++i) { @@ -355,11 +355,14 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read( return prv; } -void BKE_previewimg_cached_release(const char *name) +void BKE_previewimg_cached_release_pointer(PreviewImage *prv) { - PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN); - if (prv) { + if (prv->tag & PRV_TAG_DEFFERED_RENDERING) { + /* We cannot delete the preview while it is being loaded in another thread... */ + prv->tag |= PRV_TAG_DEFFERED_DELETE; + return; + } if (prv->icon_id) { BKE_icon_delete(prv->icon_id); } @@ -367,11 +370,18 @@ void BKE_previewimg_cached_release(const char *name) } } +void BKE_previewimg_cached_release(const char *name) +{ + PreviewImage *prv = BLI_ghash_popkey(gCachedPreviews, name, MEM_freeN); + + BKE_previewimg_cached_release_pointer(prv); +} + /** Handle deferred (lazy) loading/generation of preview image, if needed. * For now, only used with file thumbnails. */ void BKE_previewimg_ensure(PreviewImage *prv, const int size) { - if (prv->use_deferred) { + if ((prv->tag & PRV_TAG_DEFFERED) != 0) { const bool do_icon = ((size == ICON_SIZE_ICON) && !prv->rect[ICON_SIZE_ICON]); const bool do_preview = ((size == ICON_SIZE_PREVIEW) && !prv->rect[ICON_SIZE_PREVIEW]); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index c1da78d3877..41b275751d1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -2147,6 +2147,7 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p prv->gputexture[i] = NULL; } prv->icon_id = 0; + prv->tag = 0; } return prv; diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 22a450d2523..ff9d2840e9c 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1088,7 +1088,7 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi if (prv) { const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON; - if (id || prv->use_deferred) { + if (id || (prv->tag & PRV_TAG_DEFFERED) != 0) { ui_id_preview_image_render_size(C, NULL, id, prv, size, true); } } diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index ddbf59b2cf7..87c08dc6583 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -1080,13 +1080,19 @@ static void icon_preview_add_size(IconPreview *ip, unsigned int *rect, int sizex static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short *do_update, float *progress) { IconPreview *ip = (IconPreview *)customdata; - IconPreviewSize *cur_size = ip->sizes.first; + IconPreviewSize *cur_size; const bool use_new_shading = BKE_scene_use_new_shading_nodes(ip->scene); - while (cur_size) { + for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) { PreviewImage *prv = ip->owner; + + if (prv->tag & PRV_TAG_DEFFERED_DELETE) { + /* Non-thread-protected reading is not an issue here. */ + continue; + } + ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview"); - const bool is_render = !prv->use_deferred; + const bool is_render = !(prv->tag & PRV_TAG_DEFFERED); /* construct shader preview from image size and previewcustomdata */ sp->scene = ip->scene; @@ -1117,8 +1123,6 @@ static void icon_preview_startjob_all_sizes(void *customdata, short *stop, short common_preview_startjob(sp, stop, do_update, progress); shader_preview_free(sp); - - cur_size = cur_size->next; } } @@ -1147,6 +1151,15 @@ static void icon_preview_endjob(void *customdata) } #endif } + + if (ip->owner) { + PreviewImage *prv_img = ip->owner; + prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING; + if (prv_img->tag & PRV_TAG_DEFFERED_DELETE) { + BLI_assert(prv_img->tag & PRV_TAG_DEFFERED); + BKE_previewimg_cached_release_pointer(prv_img); + } + } } static void icon_preview_free(void *customdata) @@ -1205,6 +1218,14 @@ void ED_preview_icon_job(const bContext *C, void *owner, ID *id, unsigned int *r icon_preview_add_size(ip, rect, sizex, sizey); + /* Special threading hack: warn main code that this preview is being rendered and cannot be freed... */ + { + PreviewImage *prv_img = owner; + if (prv_img->tag & PRV_TAG_DEFFERED) { + prv_img->tag |= PRV_TAG_DEFFERED_RENDERING; + } + } + /* setup job */ WM_jobs_customdata_set(wm_job, ip, icon_preview_free); WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 5c1bfc229da..feeb2d5e4d7 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -172,6 +172,13 @@ enum ePreviewImage_Flag { PRV_USER_EDITED = (1 << 1), /* if user-edited, do not auto-update this anymore! */ }; +/* for PreviewImage->tag */ +enum { + PRV_TAG_DEFFERED = (1 << 0), /* Actual loading of preview is deffered. */ + PRV_TAG_DEFFERED_RENDERING = (1 << 1), /* Deffered preview is being loaded. */ + PRV_TAG_DEFFERED_DELETE = (1 << 2), /* Deffered preview should be deleted asap. */ +}; + typedef struct PreviewImage { /* All values of 2 are really NUM_ICON_SIZES */ unsigned int w[2]; @@ -184,12 +191,12 @@ typedef struct PreviewImage { struct GPUTexture *gputexture[2]; int icon_id; /* Used by previews outside of ID context. */ - char pad[3]; - char use_deferred; /* for now a mere bool, if we add more deferred loading methods we can switch to bitflag. */ + short tag; /* Runtime data. */ + char pad[2]; } PreviewImage; #define PRV_DEFERRED_DATA(prv) \ - (CHECK_TYPE_INLINE(prv, PreviewImage *), BLI_assert((prv)->use_deferred), (void *)((prv) + 1)) + (CHECK_TYPE_INLINE(prv, PreviewImage *), BLI_assert((prv)->tag & PRV_TAG_DEFFERED), (void *)((prv) + 1)) /** * Defines for working with IDs. From 216a3a3826214c665c90b8c89715507e8755b1c7 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 27 Oct 2016 13:23:29 +0200 Subject: [PATCH 055/590] Fix T49743: Adding torus in edit mode local mode shows error The 'local' layers were not correctly set when redoing 'add object' addons using object_utils.py helper (we always want to restore layers from view in local view, even if we set 'real' layers from operator afterwards). --- release/scripts/modules/bpy_extras/object_utils.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 87bb84b5844..88cd7398fe0 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -137,12 +137,14 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name= if context.space_data and context.space_data.type == 'VIEW_3D': v3d = context.space_data + if v3d and v3d.local_view: + base.layers_from_view(context.space_data) + if operator is not None and any(operator.layers): base.layers = operator.layers else: if use_active_layer: if v3d and v3d.local_view: - base.layers_from_view(context.space_data) base.layers[scene.active_layer] = True else: if v3d and not v3d.lock_camera_and_layers: From 03b8531cea965818f04520cdd1c488594dd195cb Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Fri, 28 Oct 2016 11:54:01 +0300 Subject: [PATCH 056/590] Compile fix for Windows. __inline instead of inline is needed. --- extern/rangetree/intern/range_tree.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/extern/rangetree/intern/range_tree.c b/extern/rangetree/intern/range_tree.c index 766dd22234c..4c81036dceb 100644 --- a/extern/rangetree/intern/range_tree.c +++ b/extern/rangetree/intern/range_tree.c @@ -521,6 +521,10 @@ static bool rb_is_balanced_root(const Node *root) /* ------------------------------------------------------------------------- */ /* Internal RangeTreeUInt API */ +#ifdef _WIN32 +#define inline __inline +#endif + static inline Node *rt_node_alloc(RangeTreeUInt *rt) { #ifdef USE_TPOOL From 194a33ff001bb240d15268caf6ec0a4738b30225 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 28 Oct 2016 17:56:09 +0200 Subject: [PATCH 057/590] CacheFile: only enable scale property slider if we are editing the cache through a constraint. It doesn't make sense and is a bit confusing to have this property enabled in the modifier context. --- source/blender/editors/interface/interface_templates.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 36f65065fa1..bdad667f206 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -3886,6 +3886,8 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c return; } + SpaceButs *sbuts = CTX_wm_space_buts(C); + uiLayout *row = uiLayoutRow(layout, false); uiBlock *block = uiLayoutGetBlock(row); uiDefBut(block, UI_BTYPE_LABEL, 0, IFACE_("File Path:"), 0, 19, 145, 19, NULL, 0, 0, 0, 0, ""); @@ -3911,6 +3913,7 @@ void uiTemplateCacheFile(uiLayout *layout, bContext *C, PointerRNA *ptr, const c uiItemL(row, IFACE_("Manual Transform:"), ICON_NONE); row = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row, (sbuts->mainb == BCONTEXT_CONSTRAINT)); uiItemR(row, &fileptr, "scale", 0, "Scale", ICON_NONE); /* TODO: unused for now, so no need to expose. */ From 65c481e1457b7daf1ef3d1c41346070d345c1dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 28 Oct 2016 18:01:42 +0200 Subject: [PATCH 058/590] CacheFile: fix missing depsgraph update. --- source/blender/blenkernel/intern/depsgraph.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 5f8332dcf0c..02ae123a71e 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -2997,7 +2997,7 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; if (mcmd->cache_file && (&mcmd->cache_file->id == id)) { - ob->recalc |= OB_RECALC_DATA; + ob->recalc |= OB_RECALC_ALL; continue; } } @@ -3010,7 +3010,7 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag) bTransformCacheConstraint *data = con->data; if (data->cache_file && (&data->cache_file->id == id)) { - ob->recalc |= OB_RECALC_DATA; + ob->recalc |= OB_RECALC_ALL; break; } } From 216dec7eb1ae22ed5c2ab11ce559e7862566026f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 28 Oct 2016 18:21:43 +0200 Subject: [PATCH 059/590] Alembic Export: set start and end frame to that of the scene for convenience. Users will most likely export an entire animation rather than a single frame, so it can save a few clicks. --- source/blender/editors/io/io_alembic.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index 2256bd7f8c5..65af052dc5e 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -231,11 +231,20 @@ static void ui_alembic_export_settings(uiLayout *layout, PointerRNA *imfptr) uiItemR(row, imfptr, "ngon_method", 0, NULL, ICON_NONE); } -static void wm_alembic_export_draw(bContext *UNUSED(C), wmOperator *op) +static void wm_alembic_export_draw(bContext *C, wmOperator *op) { PointerRNA ptr; RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + + /* Conveniently set start and end frame to match the scene's frame range. */ + Scene *scene = CTX_data_scene(C); + + if (scene != NULL) { + RNA_int_set(&ptr, "start", SFRA); + RNA_int_set(&ptr, "end", EFRA); + } + ui_alembic_export_settings(op->layout, &ptr); } From 8a1b38f071dea64567fa9e3dac5ad98d7b2dc6a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 28 Oct 2016 18:26:34 +0200 Subject: [PATCH 060/590] Cleanup: avoid using G.main. --- source/blender/editors/io/io_cache.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index c5eea94f5e1..ebe8898571d 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -59,7 +59,9 @@ static int cachefile_open_invoke(bContext *C, wmOperator *op, const wmEvent *eve { if (!RNA_struct_property_is_set(op->ptr, "filepath")) { char filepath[FILE_MAX]; - BLI_strncpy(filepath, G.main->name, sizeof(filepath)); + Main *bmain = CTX_data_main(C); + + BLI_strncpy(filepath, bmain->name, sizeof(filepath)); BLI_replace_extension(filepath, sizeof(filepath), ".abc"); RNA_string_set(op->ptr, "filepath", filepath); } From 0c13792437b3e501c06605876a0396e187c0f7da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sat, 29 Oct 2016 11:04:51 +0200 Subject: [PATCH 061/590] Alembic export: fix frame range values being reset at every update, draw call. --- source/blender/editors/io/io_alembic.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index 65af052dc5e..a991f59e8e2 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -68,6 +68,8 @@ static int wm_alembic_export_invoke(bContext *C, wmOperator *op, const wmEvent *event) { + RNA_boolean_set(op->ptr, "init_scene_frame_range", true); + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { Main *bmain = CTX_data_main(C); char filepath[FILE_MAX]; @@ -240,9 +242,11 @@ static void wm_alembic_export_draw(bContext *C, wmOperator *op) /* Conveniently set start and end frame to match the scene's frame range. */ Scene *scene = CTX_data_scene(C); - if (scene != NULL) { + if (scene != NULL && RNA_boolean_get(&ptr, "init_scene_frame_range")) { RNA_int_set(&ptr, "start", SFRA); RNA_int_set(&ptr, "end", EFRA); + + RNA_boolean_set(&ptr, "init_scene_frame_range", false); } ui_alembic_export_settings(op->layout, &ptr); @@ -343,6 +347,11 @@ void WM_OT_alembic_export(wmOperatorType *ot) RNA_def_enum(ot->srna, "ngon_method", rna_enum_modifier_triangulate_quad_method_items, MOD_TRIANGULATE_NGON_BEAUTY, "Polygon Method", "Method for splitting the polygons into triangles"); + + /* This dummy prop is used to check whether we need to init the start and + * end frame values to that of the scene's, otherwise they are reset at + * every change, draw update. */ + RNA_def_boolean(ot->srna, "init_scene_frame_range", false, "", ""); } /* ************************************************************************** */ From 753edafcb77d9aaf07fe869372319b841dd80681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sat, 29 Oct 2016 12:23:09 +0200 Subject: [PATCH 062/590] Alembic: store a pointer to the object reader in the cache modifiers and constraints. This avoids traversing the archive everytime object data is needed and gives an overall consistent ~2x speedup here with files containing between 136 and 500 Alembic objects. Also this somewhat nicely de- duplicates code between data creation (upon import) and data streaming (modifiers and constraints). The only worying part is what happens when a CacheFile is deleted and/or has its path changed. For now, we traverse the whole scene and for each object using the CacheFile we free the pointer and NULL-ify it (see BKE_cachefile_clean), but at some point this should be re-considered and make use of the dependency graph. --- source/blender/alembic/ABC_alembic.h | 15 +- source/blender/alembic/intern/abc_curves.cc | 52 +++ source/blender/alembic/intern/abc_curves.h | 3 +- source/blender/alembic/intern/abc_mesh.cc | 309 +++++++++------- source/blender/alembic/intern/abc_mesh.h | 11 +- source/blender/alembic/intern/abc_object.cc | 63 +++- source/blender/alembic/intern/abc_object.h | 22 +- source/blender/alembic/intern/abc_points.cc | 32 +- source/blender/alembic/intern/abc_points.h | 2 + source/blender/alembic/intern/abc_util.cc | 62 ++++ source/blender/alembic/intern/abc_util.h | 7 + source/blender/alembic/intern/alembic_capi.cc | 340 ++++-------------- source/blender/blenkernel/BKE_cachefile.h | 2 + source/blender/blenkernel/intern/cachefile.c | 37 ++ source/blender/blenkernel/intern/constraint.c | 14 +- source/blender/makesdna/DNA_cachefile_types.h | 2 +- .../blender/makesdna/DNA_constraint_types.h | 1 + source/blender/makesdna/DNA_modifier_types.h | 1 + .../blender/makesrna/intern/rna_cachefile.c | 23 ++ .../blender/makesrna/intern/rna_constraint.c | 21 +- source/blender/makesrna/intern/rna_modifier.c | 15 +- .../modifiers/intern/MOD_meshsequencecache.c | 15 +- 22 files changed, 593 insertions(+), 456 deletions(-) diff --git a/source/blender/alembic/ABC_alembic.h b/source/blender/alembic/ABC_alembic.h index e62713f57f5..e92d5f2d9f7 100644 --- a/source/blender/alembic/ABC_alembic.h +++ b/source/blender/alembic/ABC_alembic.h @@ -28,6 +28,7 @@ extern "C" { #endif struct bContext; +struct CacheReader; struct DerivedMesh; struct ListBase; struct Object; @@ -92,21 +93,25 @@ AbcArchiveHandle *ABC_create_handle(const char *filename, struct ListBase *objec void ABC_free_handle(AbcArchiveHandle *handle); -void ABC_get_transform(AbcArchiveHandle *handle, - struct Object *ob, - const char *object_path, +void ABC_get_transform(struct CacheReader *reader, float r_mat[4][4], float time, float scale); -struct DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, +struct DerivedMesh *ABC_read_mesh(struct CacheReader *reader, struct Object *ob, struct DerivedMesh *dm, - const char *object_path, const float time, const char **err_str, int flags); +void CacheReader_free(struct CacheReader *reader); + +struct CacheReader *CacheReader_open_alembic_object(struct AbcArchiveHandle *handle, + struct CacheReader *reader, + struct Object *object, + const char *object_path); + #ifdef __cplusplus } #endif diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc index 2b54741a5c5..7e5ea3b1853 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_curves.cc @@ -37,6 +37,7 @@ extern "C" { #include "BLI_listbase.h" +#include "BKE_cdderivedmesh.h" #include "BKE_curve.h" #include "BKE_object.h" @@ -353,3 +354,54 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time) BLI_addtail(BKE_curve_nurbs_get(cu), nu); } } + +/* NOTE: Alembic only stores data about control points, but the DerivedMesh + * passed from the cache modifier contains the displist, which has more data + * than the control points, so to avoid corrupting the displist we modify the + * object directly and create a new DerivedMesh from that. Also we might need to + * create new or delete existing NURBS in the curve. + */ +DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/) +{ + ISampleSelector sample_sel(time); + const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices(); + + int vertex_idx = 0; + int curve_idx = 0; + Curve *curve = static_cast(m_object->data); + + const int curve_count = BLI_listbase_count(&curve->nurb); + + if (curve_count != num_vertices->size()) { + BKE_nurbList_free(&curve->nurb); + read_curve_sample(curve, m_curves_schema, time); + } + else { + Nurb *nurbs = static_cast(curve->nurb.first); + for (; nurbs; nurbs = nurbs->next, ++curve_idx) { + const int totpoint = (*num_vertices)[curve_idx]; + + if (nurbs->bp) { + BPoint *point = nurbs->bp; + + for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) { + const Imath::V3f &pos = (*positions)[vertex_idx]; + copy_yup_zup(point->vec, pos.getValue()); + } + } + else if (nurbs->bezt) { + BezTriple *bezier = nurbs->bezt; + + for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) { + const Imath::V3f &pos = (*positions)[vertex_idx]; + copy_yup_zup(bezier->vec[1], pos.getValue()); + } + } + } + } + + return CDDM_from_curve(m_object); +} diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h index ee47f1931ea..979ee8af639 100644 --- a/source/blender/alembic/intern/abc_curves.h +++ b/source/blender/alembic/intern/abc_curves.h @@ -56,10 +56,11 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); + DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int); }; /* ************************************************************************** */ void read_curve_sample(Curve *cu, const Alembic::AbcGeom::ICurvesSchema &schema, const float time); -#endif /* __ABC_CURVES_H__ */ \ No newline at end of file +#endif /* __ABC_CURVES_H__ */ diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index bb5d5ce3566..5b282e3c5bb 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -646,75 +646,6 @@ void AbcMeshWriter::getGeoGroups( /* Some helpers for mesh generation */ namespace utils { -void mesh_add_verts(Mesh *mesh, size_t len) -{ - if (len == 0) { - return; - } - - const int totvert = mesh->totvert + len; - CustomData vdata; - CustomData_copy(&mesh->vdata, &vdata, CD_MASK_MESH, CD_DEFAULT, totvert); - CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); - - if (!CustomData_has_layer(&vdata, CD_MVERT)) { - CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, NULL, totvert); - } - - CustomData_free(&mesh->vdata, mesh->totvert); - mesh->vdata = vdata; - BKE_mesh_update_customdata_pointers(mesh, false); - - mesh->totvert = totvert; -} - -static void mesh_add_mloops(Mesh *mesh, size_t len) -{ - if (len == 0) { - return; - } - - /* new face count */ - const int totloops = mesh->totloop + len; - - CustomData ldata; - CustomData_copy(&mesh->ldata, &ldata, CD_MASK_MESH, CD_DEFAULT, totloops); - CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); - - if (!CustomData_has_layer(&ldata, CD_MLOOP)) { - CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, NULL, totloops); - } - - CustomData_free(&mesh->ldata, mesh->totloop); - mesh->ldata = ldata; - BKE_mesh_update_customdata_pointers(mesh, false); - - mesh->totloop = totloops; -} - -static void mesh_add_mpolygons(Mesh *mesh, size_t len) -{ - if (len == 0) { - return; - } - - const int totpolys = mesh->totpoly + len; - - CustomData pdata; - CustomData_copy(&mesh->pdata, &pdata, CD_MASK_MESH, CD_DEFAULT, totpolys); - CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); - - if (!CustomData_has_layer(&pdata, CD_MPOLY)) { - CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, NULL, totpolys); - } - - CustomData_free(&mesh->pdata, mesh->totpoly); - mesh->pdata = pdata; - BKE_mesh_update_customdata_pointers(mesh, false); - - mesh->totpoly = totpolys; -} - static void build_mat_map(const Main *bmain, std::map &mat_map) { Material *material = static_cast(bmain->mat.first); @@ -786,45 +717,6 @@ struct AbcMeshData { UInt32ArraySamplePtr uvs_indices; }; -static void *add_customdata_cb(void *user_data, const char *name, int data_type) -{ - Mesh *mesh = static_cast(user_data); - CustomDataType cd_data_type = static_cast(data_type); - void *cd_ptr = NULL; - - int index = -1; - if (cd_data_type == CD_MLOOPUV) { - index = ED_mesh_uv_texture_add(mesh, name, true); - cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type); - } - else if (cd_data_type == CD_MLOOPCOL) { - index = ED_mesh_color_add(mesh, name, true); - cd_ptr = CustomData_get_layer(&mesh->ldata, cd_data_type); - } - - if (index == -1) { - return NULL; - } - - return cd_ptr; -} - -CDStreamConfig create_config(Mesh *mesh) -{ - CDStreamConfig config; - - config.mvert = mesh->mvert; - config.mpoly = mesh->mpoly; - config.mloop = mesh->mloop; - config.totpoly = mesh->totpoly; - config.totloop = mesh->totloop; - config.user_data = mesh; - config.loopdata = &mesh->ldata; - config.add_customdata_cb = add_customdata_cb; - - return config; -} - static void read_mverts_interp(MVert *mverts, const P3fArraySamplePtr &positions, const P3fArraySamplePtr &ceil_positions, const float weight) { float tmp[3]; @@ -1002,23 +894,15 @@ void AbcMeshReader::readObjectData(Main *bmain, float time) m_object->data = mesh; const ISampleSelector sample_sel(time); - const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel); - const P3fArraySamplePtr &positions = sample.getPositions(); - const Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); - utils::mesh_add_verts(mesh, positions->size()); - utils::mesh_add_mpolygons(mesh, face_counts->size()); - utils::mesh_add_mloops(mesh, face_indices->size()); + if (ndm != dm) { + dm->release(dm); + } - m_mesh_data = create_config(mesh); - - bool has_smooth_normals = false; - read_mesh_sample(m_settings, m_schema, sample_sel, m_mesh_data, has_smooth_normals); - - BKE_mesh_calc_normals(mesh); - BKE_mesh_calc_edges(mesh, false, false); + DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); if (m_settings->validate_meshes) { BKE_mesh_validate(mesh, false, false); @@ -1031,6 +915,120 @@ void AbcMeshReader::readObjectData(Main *bmain, float time) } } +static bool check_smooth_poly_flag(DerivedMesh *dm) +{ + MPoly *mpolys = dm->getPolyArray(dm); + + for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { + MPoly &poly = mpolys[i]; + + if ((poly.flag & ME_SMOOTH) != 0) { + return true; + } + } + + return false; +} + +static void set_smooth_poly_flag(DerivedMesh *dm) +{ + MPoly *mpolys = dm->getPolyArray(dm); + + for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { + MPoly &poly = mpolys[i]; + poly.flag |= ME_SMOOTH; + } +} + +static void *add_customdata_cb(void *user_data, const char *name, int data_type) +{ + DerivedMesh *dm = static_cast(user_data); + CustomDataType cd_data_type = static_cast(data_type); + void *cd_ptr = NULL; + + if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { + cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name); + + if (cd_ptr == NULL) { + cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm), + cd_data_type, + CD_DEFAULT, + NULL, + dm->getNumLoops(dm), + name); + } + } + + return cd_ptr; +} + +CDStreamConfig get_config(DerivedMesh *dm) +{ + CDStreamConfig config; + + config.user_data = dm; + config.mvert = dm->getVertArray(dm); + config.mloop = dm->getLoopArray(dm); + config.mpoly = dm->getPolyArray(dm); + config.totloop = dm->getNumLoops(dm); + config.totpoly = dm->getNumPolys(dm); + config.loopdata = dm->getLoopDataLayout(dm); + config.add_customdata_cb = add_customdata_cb; + + return config; +} + +DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) +{ + ISampleSelector sample_sel(time); + const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); + const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); + + DerivedMesh *new_dm = NULL; + + /* Only read point data when streaming meshes, unless we need to create new ones. */ + ImportSettings settings; + settings.read_flag |= read_flag; + + if (dm->getNumVerts(dm) != positions->size()) { + new_dm = CDDM_from_template(dm, + positions->size(), + 0, + 0, + face_indices->size(), + face_counts->size()); + + settings.read_flag |= MOD_MESHSEQ_READ_ALL; + } + + CDStreamConfig config = get_config(new_dm ? new_dm : dm); + config.time = time; + + bool do_normals = false; + read_mesh_sample(&settings, m_schema, sample_sel, config, do_normals); + + if (new_dm) { + /* Check if we had ME_SMOOTH flag set to restore it. */ + if (!do_normals && check_smooth_poly_flag(dm)) { + set_smooth_poly_flag(new_dm); + } + + CDDM_calc_normals(new_dm); + CDDM_calc_edges(new_dm); + + return new_dm; + } + + if (do_normals) { + CDDM_calc_normals(dm); + } + + return dm; +} + void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, const ISampleSelector &sample_sel) { @@ -1178,21 +1176,17 @@ void AbcSubDReader::readObjectData(Main *bmain, float time) m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); m_object->data = mesh; + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); + + if (ndm != dm) { + dm->release(dm); + } + + DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); + const ISampleSelector sample_sel(time); const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - utils::mesh_add_verts(mesh, positions->size()); - utils::mesh_add_mpolygons(mesh, face_counts->size()); - utils::mesh_add_mloops(mesh, face_indices->size()); - - m_mesh_data = create_config(mesh); - - read_subd_sample(m_settings, m_schema, sample_sel, m_mesh_data); - Int32ArraySamplePtr indices = sample.getCreaseIndices(); Alembic::Abc::FloatArraySamplePtr sharpnesses = sample.getCreaseSharpnesses(); @@ -1262,3 +1256,48 @@ void read_subd_sample(ImportSettings *settings, /* TODO: face sets */ } + +DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) +{ + ISampleSelector sample_sel(time); + const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); + const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); + + DerivedMesh *new_dm = NULL; + + ImportSettings settings; + settings.read_flag |= read_flag; + + if (dm->getNumVerts(dm) != positions->size()) { + new_dm = CDDM_from_template(dm, + positions->size(), + 0, + 0, + face_indices->size(), + face_counts->size()); + + settings.read_flag |= MOD_MESHSEQ_READ_ALL; + } + + /* Only read point data when streaming meshes, unless we need to create new ones. */ + CDStreamConfig config = get_config(new_dm ? new_dm : dm); + config.time = time; + read_subd_sample(&settings, m_schema, sample_sel, config); + + if (new_dm) { + /* Check if we had ME_SMOOTH flag set to restore it. */ + if (check_smooth_poly_flag(dm)) { + set_smooth_poly_flag(new_dm); + } + + CDDM_calc_normals(new_dm); + CDDM_calc_edges(new_dm); + + return new_dm; + } + + return dm; +} diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h index 41abe78f75f..66e6585a3d3 100644 --- a/source/blender/alembic/intern/abc_mesh.h +++ b/source/blender/alembic/intern/abc_mesh.h @@ -102,6 +102,8 @@ public: void readObjectData(Main *bmain, float time); + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); + private: void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, const Alembic::AbcGeom::ISampleSelector &sample_sel); @@ -126,6 +128,7 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); }; void read_subd_sample(ImportSettings *settings, @@ -135,16 +138,10 @@ void read_subd_sample(ImportSettings *settings, /* ************************************************************************** */ -namespace utils { - -void mesh_add_verts(struct Mesh *mesh, size_t len); - -} - void read_mverts(MVert *mverts, const Alembic::AbcGeom::P3fArraySamplePtr &positions, const Alembic::AbcGeom::N3fArraySamplePtr &normals); -CDStreamConfig create_config(Mesh *mesh); +CDStreamConfig get_config(DerivedMesh *dm); #endif /* __ABC_MESH_H__ */ diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc index 32468fdaded..314b2568bed 100644 --- a/source/blender/alembic/intern/abc_object.cc +++ b/source/blender/alembic/intern/abc_object.cc @@ -126,6 +126,7 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings , m_settings(&settings) , m_min_time(std::numeric_limits::max()) , m_max_time(std::numeric_limits::min()) + , m_refcount(0) { m_name = object.getFullName(); std::vector parts; @@ -153,6 +154,11 @@ Object *AbcObjectReader::object() const return m_object; } +void AbcObjectReader::object(Object *ob) +{ + m_object = ob; +} + static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight) { float mat0[4][4], mat1[4][4], ret[4][4]; @@ -209,6 +215,28 @@ Imath::M44d get_matrix(const IXformSchema &schema, const float time) } void AbcObjectReader::readObjectMatrix(const float time) +{ + bool is_constant = false; + + this->read_matrix(m_object->obmat, time, m_settings->scale, is_constant); + invert_m4_m4(m_object->imat, m_object->obmat); + + BKE_object_apply_mat4(m_object, m_object->obmat, false, false); + + if (!is_constant) { + bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE); + bTransformCacheConstraint *data = static_cast(con->data); + BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX); + + data->cache_file = m_settings->cache_file; + id_us_plus(&data->cache_file->id); + + data->reader = reinterpret_cast(this); + this->incref(); + } +} + +void AbcObjectReader::read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant) { IXform ixform; bool has_alembic_parent = false; @@ -250,23 +278,12 @@ void AbcObjectReader::readObjectMatrix(const float time) } const Imath::M44d matrix = get_matrix(schema, time); - convert_matrix(matrix, m_object, m_object->obmat, m_settings->scale, has_alembic_parent); + convert_matrix(matrix, m_object, mat, scale, has_alembic_parent); - invert_m4_m4(m_object->imat, m_object->obmat); - - BKE_object_apply_mat4(m_object, m_object->obmat, false, false); - - if (!schema.isConstant()) { - bConstraint *con = BKE_constraint_add_for_object(m_object, NULL, CONSTRAINT_TYPE_TRANSFORM_CACHE); - bTransformCacheConstraint *data = static_cast(con->data); - BLI_strncpy(data->object_path, m_iobject.getFullName().c_str(), FILE_MAX); - - data->cache_file = m_settings->cache_file; - id_us_plus(&data->cache_file->id); - } + is_constant = schema.isConstant(); } -void AbcObjectReader::addCacheModifier() const +void AbcObjectReader::addCacheModifier() { ModifierData *md = modifier_new(eModifierType_MeshSequenceCache); BLI_addtail(&m_object->modifiers, md); @@ -277,6 +294,9 @@ void AbcObjectReader::addCacheModifier() const id_us_plus(&mcmd->cache_file->id); BLI_strncpy(mcmd->object_path, m_iobject.getFullName().c_str(), FILE_MAX); + + mcmd->reader = reinterpret_cast(this); + this->incref(); } chrono_t AbcObjectReader::minTime() const @@ -288,3 +308,18 @@ chrono_t AbcObjectReader::maxTime() const { return m_max_time; } + +int AbcObjectReader::refcount() const +{ + return m_refcount; +} + +void AbcObjectReader::incref() +{ + ++m_refcount; +} + +void AbcObjectReader::decref() +{ + --m_refcount; +} diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h index a35faa37565..7ff927b4d33 100644 --- a/source/blender/alembic/intern/abc_object.h +++ b/source/blender/alembic/intern/abc_object.h @@ -130,6 +130,8 @@ static bool has_animations(Schema &schema, ImportSettings *settings) /* ************************************************************************** */ +struct DerivedMesh; + using Alembic::AbcCoreAbstract::chrono_t; class AbcObjectReader { @@ -145,6 +147,10 @@ protected: chrono_t m_min_time; chrono_t m_max_time; + /* Use reference counting since the same reader may be used by multiple + * modifiers and/or constraints. */ + int m_refcount; + public: explicit AbcObjectReader(const Alembic::Abc::IObject &object, ImportSettings &settings); @@ -153,17 +159,31 @@ public: const Alembic::Abc::IObject &iobject() const; Object *object() const; + void object(Object *ob); virtual bool valid() const = 0; virtual void readObjectData(Main *bmain, float time) = 0; + virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) + { + (void)time; + (void)read_flag; + return dm; + } + void readObjectMatrix(const float time); - void addCacheModifier() const; + void addCacheModifier(); chrono_t minTime() const; chrono_t maxTime() const; + + int refcount() const; + void incref(); + void decref(); + + void read_matrix(float mat[4][4], const float time, const float scale, bool &is_constant); }; Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time); diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc index 03014547416..c16da621c77 100644 --- a/source/blender/alembic/intern/abc_points.cc +++ b/source/blender/alembic/intern/abc_points.cc @@ -32,6 +32,7 @@ extern "C" { #include "DNA_mesh_types.h" #include "DNA_object_types.h" +#include "BKE_cdderivedmesh.h" #include "BKE_lattice.h" #include "BKE_mesh.h" #include "BKE_object.h" @@ -154,14 +155,14 @@ void AbcPointsReader::readObjectData(Main *bmain, float time) { Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); - const ISampleSelector sample_sel(time); - m_sample = m_schema.getValue(sample_sel); + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0); - const P3fArraySamplePtr &positions = m_sample.getPositions(); - utils::mesh_add_verts(mesh, positions->size()); + if (ndm != dm) { + dm->release(dm); + } - CDStreamConfig config = create_config(mesh); - read_points_sample(m_schema, sample_sel, config, time); + DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); if (m_settings->validate_meshes) { BKE_mesh_validate(mesh, false, false); @@ -197,3 +198,22 @@ void read_points_sample(const IPointsSchema &schema, read_mverts(config.mvert, positions, vnormals); } + +DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/) +{ + ISampleSelector sample_sel(time); + const IPointsSchema::Sample sample = m_schema.getValue(sample_sel); + + const P3fArraySamplePtr &positions = sample.getPositions(); + + DerivedMesh *new_dm = NULL; + + if (dm->getNumVerts(dm) != positions->size()) { + new_dm = CDDM_new(positions->size(), 0, 0, 0, 0); + } + + CDStreamConfig config = get_config(new_dm ? new_dm : dm); + read_points_sample(m_schema, sample_sel, config, time); + + return new_dm ? new_dm : dm; +} diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h index 51f3103bd8b..54873eed346 100644 --- a/source/blender/alembic/intern/abc_points.h +++ b/source/blender/alembic/intern/abc_points.h @@ -60,6 +60,8 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); + + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); }; void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index 60c66bca1c8..f87d18605d4 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -22,6 +22,15 @@ #include "abc_util.h" +#include "abc_camera.h" +#include "abc_curves.h" +#include "abc_mesh.h" +#include "abc_nurbs.h" +#include "abc_points.h" +#include "abc_transform.h" + +#include + #include extern "C" { @@ -462,3 +471,56 @@ float get_weight_and_index(float time, return bias; } + +//#define USE_NURBS + +AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings) +{ + AbcObjectReader *reader = NULL; + + const Alembic::AbcGeom::MetaData &md = object.getMetaData(); + + if (Alembic::AbcGeom::IXform::matches(md)) { + reader = new AbcEmptyReader(object, settings); + } + else if (Alembic::AbcGeom::IPolyMesh::matches(md)) { + reader = new AbcMeshReader(object, settings); + } + else if (Alembic::AbcGeom::ISubD::matches(md)) { + reader = new AbcSubDReader(object, settings); + } + else if (Alembic::AbcGeom::INuPatch::matches(md)) { +#ifdef USE_NURBS + /* TODO(kevin): importing cyclic NURBS from other software crashes + * at the moment. This is due to the fact that NURBS in other + * software have duplicated points which causes buffer overflows in + * Blender. Need to figure out exactly how these points are + * duplicated, in all cases (cyclic U, cyclic V, and cyclic UV). + * Until this is fixed, disabling NURBS reading. */ + reader = new AbcNurbsReader(child, settings); +#endif + } + else if (Alembic::AbcGeom::ICamera::matches(md)) { + reader = new AbcCameraReader(object, settings); + } + else if (Alembic::AbcGeom::IPoints::matches(md)) { + reader = new AbcPointsReader(object, settings); + } + else if (Alembic::AbcMaterial::IMaterial::matches(md)) { + /* Pass for now. */ + } + else if (Alembic::AbcGeom::ILight::matches(md)) { + /* Pass for now. */ + } + else if (Alembic::AbcGeom::IFaceSet::matches(md)) { + /* Pass, those are handled in the mesh reader. */ + } + else if (Alembic::AbcGeom::ICurves::matches(md)) { + reader = new AbcCurveReader(object, settings); + } + else { + assert(false); + } + + return reader; +} diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h index 9e9f0c397ba..2f423a9f8c5 100644 --- a/source/blender/alembic/intern/abc_util.h +++ b/source/blender/alembic/intern/abc_util.h @@ -32,8 +32,13 @@ # define ABC_INLINE static inline #endif +struct CacheReader { + int unused; +}; + using Alembic::Abc::chrono_t; +class AbcObjectReader; class ImportSettings; struct ID; @@ -100,6 +105,8 @@ float get_weight_and_index(float time, Alembic::AbcGeom::index_t &i0, Alembic::AbcGeom::index_t &i1); +AbcObjectReader *create_reader(const Alembic::AbcGeom::IObject &object, ImportSettings &settings); + /* ************************** */ /* TODO(kevin): for now keeping these transformations hardcoded to make sure diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index c6988351db8..e690a255505 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -467,6 +467,7 @@ static void visit_object(const IObject &object, if (reader) { readers.push_back(reader); + reader->incref(); AlembicObjectPath *abc_path = static_cast( MEM_callocN(sizeof(AlembicObjectPath), "AlembicObjectPath")); @@ -710,7 +711,12 @@ static void import_endjob(void *user_data) } for (iter = data->readers.begin(); iter != data->readers.end(); ++iter) { - delete *iter; + AbcObjectReader *reader = *iter; + reader->decref(); + + if (reader->refcount() == 0) { + delete reader; + } } if (data->parent_map) { @@ -771,296 +777,31 @@ void ABC_import(bContext *C, const char *filepath, float scale, bool is_sequence WM_jobs_start(CTX_wm_manager(C), wm_job); } -/* ******************************* */ +/* ************************************************************************** */ -void ABC_get_transform(AbcArchiveHandle *handle, Object *ob, const char *object_path, float r_mat[4][4], float time, float scale) +void ABC_get_transform(CacheReader *reader, float r_mat[4][4], float time, float scale) { - ArchiveReader *archive = archive_from_handle(handle); - - if (!archive || !archive->valid()) { + if (!reader) { return; } - IObject tmp; - find_iobject(archive->getTop(), tmp, object_path); + AbcObjectReader *abc_reader = reinterpret_cast(reader); - IXform ixform; - - if (IXform::matches(tmp.getHeader())) { - ixform = IXform(tmp, kWrapExisting); - } - else { - ixform = IXform(tmp.getParent(), kWrapExisting); - } - - IXformSchema schema = ixform.getSchema(); - - if (!schema.valid()) { - return; - } - - const Imath::M44d matrix = get_matrix(schema, time); - convert_matrix(matrix, ob, r_mat, scale); + bool is_constant = false; + abc_reader->read_matrix(r_mat, time, scale, is_constant); } -/* ***************************************** */ +/* ************************************************************************** */ -static bool check_smooth_poly_flag(DerivedMesh *dm) -{ - MPoly *mpolys = dm->getPolyArray(dm); - - for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { - MPoly &poly = mpolys[i]; - - if ((poly.flag & ME_SMOOTH) != 0) { - return true; - } - } - - return false; -} - -static void set_smooth_poly_flag(DerivedMesh *dm) -{ - MPoly *mpolys = dm->getPolyArray(dm); - - for (int i = 0, e = dm->getNumPolys(dm); i < e; ++i) { - MPoly &poly = mpolys[i]; - poly.flag |= ME_SMOOTH; - } -} - -static void *add_customdata_cb(void *user_data, const char *name, int data_type) -{ - DerivedMesh *dm = static_cast(user_data); - CustomDataType cd_data_type = static_cast(data_type); - void *cd_ptr = NULL; - - if (ELEM(cd_data_type, CD_MLOOPUV, CD_MLOOPCOL)) { - cd_ptr = CustomData_get_layer_named(dm->getLoopDataLayout(dm), cd_data_type, name); - - if (cd_ptr == NULL) { - cd_ptr = CustomData_add_layer_named(dm->getLoopDataLayout(dm), - cd_data_type, - CD_DEFAULT, - NULL, - dm->getNumLoops(dm), - name); - } - } - - return cd_ptr; -} - -ABC_INLINE CDStreamConfig get_config(DerivedMesh *dm) -{ - CDStreamConfig config; - - config.user_data = dm; - config.mvert = dm->getVertArray(dm); - config.mloop = dm->getLoopArray(dm); - config.mpoly = dm->getPolyArray(dm); - config.totloop = dm->getNumLoops(dm); - config.totpoly = dm->getNumPolys(dm); - config.loopdata = dm->getLoopDataLayout(dm); - config.add_customdata_cb = add_customdata_cb; - - return config; -} - -static DerivedMesh *read_mesh_sample(DerivedMesh *dm, const IObject &iobject, const float time, int read_flag) -{ - IPolyMesh mesh(iobject, kWrapExisting); - IPolyMeshSchema schema = mesh.getSchema(); - ISampleSelector sample_sel(time); - const IPolyMeshSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - DerivedMesh *new_dm = NULL; - - /* Only read point data when streaming meshes, unless we need to create new ones. */ - ImportSettings settings; - settings.read_flag |= read_flag; - - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_from_template(dm, - positions->size(), - 0, - 0, - face_indices->size(), - face_counts->size()); - - settings.read_flag |= MOD_MESHSEQ_READ_ALL; - } - - CDStreamConfig config = get_config(new_dm ? new_dm : dm); - config.time = time; - - bool do_normals = false; - read_mesh_sample(&settings, schema, sample_sel, config, do_normals); - - if (new_dm) { - /* Check if we had ME_SMOOTH flag set to restore it. */ - if (!do_normals && check_smooth_poly_flag(dm)) { - set_smooth_poly_flag(new_dm); - } - - CDDM_calc_normals(new_dm); - CDDM_calc_edges(new_dm); - - return new_dm; - } - - if (do_normals) { - CDDM_calc_normals(dm); - } - - return dm; -} - -using Alembic::AbcGeom::ISubDSchema; - -static DerivedMesh *read_subd_sample(DerivedMesh *dm, const IObject &iobject, const float time, int read_flag) -{ - ISubD mesh(iobject, kWrapExisting); - ISubDSchema schema = mesh.getSchema(); - ISampleSelector sample_sel(time); - const ISubDSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Alembic::Abc::Int32ArraySamplePtr &face_indices = sample.getFaceIndices(); - const Alembic::Abc::Int32ArraySamplePtr &face_counts = sample.getFaceCounts(); - - DerivedMesh *new_dm = NULL; - - ImportSettings settings; - settings.read_flag |= read_flag; - - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_from_template(dm, - positions->size(), - 0, - 0, - face_indices->size(), - face_counts->size()); - - settings.read_flag |= MOD_MESHSEQ_READ_ALL; - } - - /* Only read point data when streaming meshes, unless we need to create new ones. */ - CDStreamConfig config = get_config(new_dm ? new_dm : dm); - config.time = time; - read_subd_sample(&settings, schema, sample_sel, config); - - if (new_dm) { - /* Check if we had ME_SMOOTH flag set to restore it. */ - if (check_smooth_poly_flag(dm)) { - set_smooth_poly_flag(new_dm); - } - - CDDM_calc_normals(new_dm); - CDDM_calc_edges(new_dm); - - return new_dm; - } - - return dm; -} - -static DerivedMesh *read_points_sample(DerivedMesh *dm, const IObject &iobject, const float time) -{ - IPoints points(iobject, kWrapExisting); - IPointsSchema schema = points.getSchema(); - ISampleSelector sample_sel(time); - const IPointsSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - - DerivedMesh *new_dm = NULL; - - if (dm->getNumVerts(dm) != positions->size()) { - new_dm = CDDM_new(positions->size(), 0, 0, 0, 0); - } - - CDStreamConfig config = get_config(new_dm ? new_dm : dm); - read_points_sample(schema, sample_sel, config, time); - - return new_dm ? new_dm : dm; -} - -/* NOTE: Alembic only stores data about control points, but the DerivedMesh - * passed from the cache modifier contains the displist, which has more data - * than the control points, so to avoid corrupting the displist we modify the - * object directly and create a new DerivedMesh from that. Also we might need to - * create new or delete existing NURBS in the curve. - */ -static DerivedMesh *read_curves_sample(Object *ob, const IObject &iobject, const float time) -{ - ICurves points(iobject, kWrapExisting); - ICurvesSchema schema = points.getSchema(); - ISampleSelector sample_sel(time); - const ICurvesSchema::Sample sample = schema.getValue(sample_sel); - - const P3fArraySamplePtr &positions = sample.getPositions(); - const Int32ArraySamplePtr num_vertices = sample.getCurvesNumVertices(); - - int vertex_idx = 0; - int curve_idx = 0; - Curve *curve = static_cast(ob->data); - - const int curve_count = BLI_listbase_count(&curve->nurb); - - if (curve_count != num_vertices->size()) { - BKE_nurbList_free(&curve->nurb); - read_curve_sample(curve, schema, time); - } - else { - Nurb *nurbs = static_cast(curve->nurb.first); - for (; nurbs; nurbs = nurbs->next, ++curve_idx) { - const int totpoint = (*num_vertices)[curve_idx]; - - if (nurbs->bp) { - BPoint *point = nurbs->bp; - - for (int i = 0; i < totpoint; ++i, ++point, ++vertex_idx) { - const Imath::V3f &pos = (*positions)[vertex_idx]; - copy_yup_zup(point->vec, pos.getValue()); - } - } - else if (nurbs->bezt) { - BezTriple *bezier = nurbs->bezt; - - for (int i = 0; i < totpoint; ++i, ++bezier, ++vertex_idx) { - const Imath::V3f &pos = (*positions)[vertex_idx]; - copy_yup_zup(bezier->vec[1], pos.getValue()); - } - } - } - } - - return CDDM_from_curve(ob); -} - -DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, +DerivedMesh *ABC_read_mesh(CacheReader *reader, Object *ob, DerivedMesh *dm, - const char *object_path, const float time, const char **err_str, int read_flag) { - ArchiveReader *archive = archive_from_handle(handle); - - if (!archive || !archive->valid()) { - *err_str = "Invalid archive!"; - return NULL; - } - - IObject iobject; - find_iobject(archive->getTop(), iobject, object_path); + AbcObjectReader *abc_reader = reinterpret_cast(reader); + IObject iobject = abc_reader->iobject(); if (!iobject.valid()) { *err_str = "Invalid object: verify object path"; @@ -1075,7 +816,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_mesh_sample(dm, iobject, time, read_flag); + return abc_reader->read_derivedmesh(dm, time, read_flag); } else if (ISubD::matches(header)) { if (ob->type != OB_MESH) { @@ -1083,7 +824,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_subd_sample(dm, iobject, time, read_flag); + return abc_reader->read_derivedmesh(dm, time, read_flag); } else if (IPoints::matches(header)) { if (ob->type != OB_MESH) { @@ -1091,7 +832,7 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_points_sample(dm, iobject, time); + return abc_reader->read_derivedmesh(dm, time, read_flag); } else if (ICurves::matches(header)) { if (ob->type != OB_CURVE) { @@ -1099,9 +840,48 @@ DerivedMesh *ABC_read_mesh(AbcArchiveHandle *handle, return NULL; } - return read_curves_sample(ob, iobject, time); + return abc_reader->read_derivedmesh(dm, time, read_flag); } *err_str = "Unsupported object type: verify object path"; // or poke developer return NULL; } + +/* ************************************************************************** */ + +void CacheReader_free(CacheReader *reader) +{ + AbcObjectReader *abc_reader = reinterpret_cast(reader); + abc_reader->decref(); + + if (abc_reader->refcount() == 0) { + delete abc_reader; + } +} + +CacheReader *CacheReader_open_alembic_object(AbcArchiveHandle *handle, CacheReader *reader, Object *object, const char *object_path) +{ + if (object_path[0] == '\0') { + return reader; + } + + ArchiveReader *archive = archive_from_handle(handle); + + if (!archive || !archive->valid()) { + return reader; + } + + IObject iobject; + find_iobject(archive->getTop(), iobject, object_path); + + if (reader) { + CacheReader_free(reader); + } + + ImportSettings settings; + AbcObjectReader *abc_reader = create_reader(iobject, settings); + abc_reader->object(object); + abc_reader->incref(); + + return reinterpret_cast(abc_reader); +} diff --git a/source/blender/blenkernel/BKE_cachefile.h b/source/blender/blenkernel/BKE_cachefile.h index a55cb51766c..7e1c069df9a 100644 --- a/source/blender/blenkernel/BKE_cachefile.h +++ b/source/blender/blenkernel/BKE_cachefile.h @@ -63,6 +63,8 @@ bool BKE_cachefile_filepath_get( float BKE_cachefile_time_offset(struct CacheFile *cache_file, const float time, const float fps); +void BKE_cachefile_clean(struct Scene *scene, struct CacheFile *cache_file); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index e62e652b4a6..2a2699f3a14 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -29,6 +29,8 @@ #include "DNA_anim_types.h" #include "DNA_cachefile_types.h" +#include "DNA_constraint_types.h" +#include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BLI_fileops.h" @@ -43,6 +45,7 @@ #include "BKE_global.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_modifier.h" #include "BKE_scene.h" #ifdef WITH_ALEMBIC @@ -196,3 +199,37 @@ float BKE_cachefile_time_offset(CacheFile *cache_file, const float time, const f const float frame = (cache_file->override_frame ? cache_file->frame : time); return cache_file->is_sequence ? frame : frame / fps; } + +/* TODO(kevin): replace this with some depsgraph mechanism, or something similar. */ +void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) +{ + for (Base *base = scene->base.first; base; base = base->next) { + Object *ob = base->object; + + ModifierData *md = modifiers_findByType(ob, eModifierType_MeshSequenceCache); + + if (md) { + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; + + if (cache_file == mcmd->cache_file) { + CacheReader_free(mcmd->reader); + mcmd->reader = NULL; + mcmd->object_path[0] = '\0'; + } + } + + for (bConstraint *con = ob->constraints.first; con; con = con->next) { + if (con->type != CONSTRAINT_TYPE_TRANSFORM_CACHE) { + continue; + } + + bTransformCacheConstraint *data = con->data; + + if (cache_file == data->cache_file) { + CacheReader_free(data->reader); + data->reader = NULL; + data->object_path[0] = '\0'; + } + } + } +} diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index c4afa58b7d3..c7750707cc4 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4364,8 +4364,14 @@ static void transformcache_evaluate(bConstraint *con, bConstraintOb *cob, ListBa BKE_cachefile_ensure_handle(G.main, cache_file); - ABC_get_transform(cache_file->handle, cob->ob, data->object_path, - cob->matrix, time, cache_file->scale); + if (!data->reader) { + data->reader = CacheReader_open_alembic_object(cache_file->handle, + data->reader, + cob->ob, + data->object_path); + } + + ABC_get_transform(data->reader, cob->matrix, time, cache_file->scale); #else UNUSED_VARS(con, cob); #endif @@ -4393,6 +4399,10 @@ static void transformcache_free(bConstraint *con) if (data->cache_file) { id_us_min(&data->cache_file->id); } + + if (data->reader) { + CacheReader_free(data->reader); + } } static void transformcache_new_data(void *cdata) diff --git a/source/blender/makesdna/DNA_cachefile_types.h b/source/blender/makesdna/DNA_cachefile_types.h index dd47d63fc19..46b1adf2725 100644 --- a/source/blender/makesdna/DNA_cachefile_types.h +++ b/source/blender/makesdna/DNA_cachefile_types.h @@ -36,10 +36,10 @@ extern "C" { #endif - /* CacheFile::flag */ enum { CACHEFILE_DS_EXPAND = (1 << 0), + CACHEFILE_DIRTY = (1 << 1), }; /* CacheFile::draw_flag */ diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index fc4e7de73f5..ca774864e95 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -461,6 +461,7 @@ typedef struct bObjectSolverConstraint { /* Transform matrix cache constraint */ typedef struct bTransformCacheConstraint { struct CacheFile *cache_file; + struct CacheReader *reader; char object_path[1024]; /* FILE_MAX */ } bTransformCacheConstraint; diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 1398e9de76f..f95533a88f9 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1555,6 +1555,7 @@ typedef struct MeshSeqCacheModifierData { ModifierData modifier; struct CacheFile *cache_file; + struct CacheReader *reader; char object_path[1024]; /* 1024 = FILE_MAX */ char read_flag; diff --git a/source/blender/makesrna/intern/rna_cachefile.c b/source/blender/makesrna/intern/rna_cachefile.c index 7249ebd5feb..09fdeb15b10 100644 --- a/source/blender/makesrna/intern/rna_cachefile.c +++ b/source/blender/makesrna/intern/rna_cachefile.c @@ -37,6 +37,8 @@ #include "BKE_cachefile.h" #include "BKE_depsgraph.h" +#include "BLI_string.h" + #include "DEG_depsgraph.h" #include "WM_api.h" @@ -60,6 +62,12 @@ static void rna_CacheFile_update_handle(Main *bmain, Scene *scene, PointerRNA *p { CacheFile *cache_file = ptr->data; + if ((cache_file->flag & CACHEFILE_DIRTY) != 0) { + BKE_cachefile_clean(scene, cache_file); + BLI_freelistN(&cache_file->object_paths); + cache_file->flag &= ~CACHEFILE_DIRTY; + } + BKE_cachefile_reload(bmain, cache_file); rna_CacheFile_update(bmain, scene, ptr); @@ -71,6 +79,20 @@ static void rna_CacheFile_object_paths_begin(CollectionPropertyIterator *iter, P rna_iterator_listbase_begin(iter, &cache_file->object_paths, NULL); } +static void rna_CacheFile_filename_set(PointerRNA *ptr, const char *value) +{ + CacheFile *cache_file = ptr->data; + + if (STREQ(cache_file->filepath, value)) { + return; + } + + /* Different file is opened, close all readers. */ + cache_file->flag |= CACHEFILE_DIRTY; + + BLI_strncpy(cache_file->filepath, value, sizeof(cache_file->filepath)); +} + #else /* cachefile.object_paths */ @@ -103,6 +125,7 @@ static void rna_def_cachefile(BlenderRNA *brna) RNA_def_struct_ui_icon(srna, ICON_FILE); PropertyRNA *prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH); + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_CacheFile_filename_set"); RNA_def_property_ui_text(prop, "File Path", "Path to external displacements file"); RNA_def_property_update(prop, 0, "rna_CacheFile_update_handle"); diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index db3f76f3cfc..ad037af943d 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -148,12 +148,17 @@ static EnumPropertyItem space_object_items[] = { {0, NULL, 0, NULL, NULL} }; +#include "DNA_cachefile_types.h" + #include "BKE_animsys.h" #include "BKE_action.h" #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_depsgraph.h" +#ifdef WITH_ALEMBIC +# include "ABC_alembic.h" +#endif static StructRNA *rna_ConstraintType_refine(struct PointerRNA *ptr) { @@ -471,6 +476,20 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v } } +static void rna_Constraint_transformCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + bConstraint *con = (bConstraint *)ptr->data; + bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data; + Object *ob = (Object *)ptr->id.data; + + data->reader = CacheReader_open_alembic_object(data->cache_file->handle, + data->reader, + ob, + data->object_path); + + rna_Constraint_update(bmain, scene, ptr); +} + #else static EnumPropertyItem constraint_distance_items[] = { @@ -2593,7 +2612,7 @@ static void rna_def_constraint_transform_cache(BlenderRNA *brna) prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup the transform matrix"); - RNA_def_property_update(prop, 0, "rna_Constraint_update"); + RNA_def_property_update(prop, 0, "rna_Constraint_transformCache_object_path_update"); } /* base struct for constraints */ diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 39f6298ca61..b30c156a88c 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1131,6 +1131,19 @@ static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr) return (csmd->bind_coords != NULL); } +static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)ptr->data; + Object *ob = (Object *)ptr->id.data; + + mcmd->reader = CacheReader_open_alembic_object(mcmd->cache_file->handle, + mcmd->reader, + ob, + mcmd->object_path); + + rna_Modifier_update(bmain, scene, ptr); +} + #else static PropertyRNA *rna_def_property_subdivision_common(StructRNA *srna, const char type[]) @@ -4257,7 +4270,7 @@ static void rna_def_modifier_meshseqcache(BlenderRNA *brna) prop = RNA_def_property(srna, "object_path", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(prop, "Object Path", "Path to the object in the Alembic archive used to lookup geometric data"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); + RNA_def_property_update(prop, 0, "rna_MeshSequenceCache_object_path_update"); static EnumPropertyItem read_flag_items[] = { {MOD_MESHSEQ_READ_VERT, "VERT", 0, "Vertex", ""}, diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 355ac9563dd..cf137784e65 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -65,6 +65,7 @@ static void copyData(ModifierData *md, ModifierData *target) if (tmcmd->cache_file) { id_us_plus(&tmcmd->cache_file->id); + tmcmd->reader = NULL; } } @@ -75,6 +76,10 @@ static void freeData(ModifierData *md) if (mcmd->cache_file) { id_us_min(&mcmd->cache_file->id); } + + if (mcmd->reader) { + CacheReader_free(mcmd->reader); + } } static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams)) @@ -102,10 +107,16 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, BKE_cachefile_ensure_handle(G.main, cache_file); - DerivedMesh *result = ABC_read_mesh(cache_file->handle, + if (!mcmd->reader) { + mcmd->reader = CacheReader_open_alembic_object(cache_file->handle, + mcmd->reader, + ob, + mcmd->object_path); + } + + DerivedMesh *result = ABC_read_mesh(mcmd->reader, ob, dm, - mcmd->object_path, time, &err_str, mcmd->read_flag); From d3b0977a354d91c363d7128f3e0ef2c5eea977e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sat, 29 Oct 2016 16:22:33 +0200 Subject: [PATCH 063/590] Fix T49878: Alembic crash with long object name Crash comes from writing to char array (ID::name) out its bound and thus overriding memory in the ID struct. --- source/blender/alembic/intern/abc_camera.cc | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc index 5c34ec1391f..d5271e3ca31 100644 --- a/source/blender/alembic/intern/abc_camera.cc +++ b/source/blender/alembic/intern/abc_camera.cc @@ -119,7 +119,7 @@ bool AbcCameraReader::valid() const void AbcCameraReader::readObjectData(Main *bmain, float time) { - Camera *bcam = static_cast(BKE_camera_add(bmain, "abc_camera")); + Camera *bcam = static_cast(BKE_camera_add(bmain, m_data_name.c_str())); ISampleSelector sample_sel(time); CameraSample cam_sample; @@ -155,8 +155,6 @@ void AbcCameraReader::readObjectData(Main *bmain, float time) bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance(); bcam->gpu_dof.fstop = cam_sample.getFStop(); - BLI_strncpy(bcam->id.name + 2, m_data_name.c_str(), m_data_name.size() + 1); - m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str()); m_object->data = bcam; } From 1272ee455e7aeed3f6acb0b8a8366af5ad6aec99 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sat, 29 Oct 2016 18:54:42 +0200 Subject: [PATCH 064/590] Cycles: Implement texture coordinates for Point, Spot and Area Lamps When using the Normal output of the Texture Coordinate node on Point and Spot lamps, the coordinates now depend on the rotation of the lamp. On Area lamps, the Parametric output of the Geometry node now returns UV coordinates on the area lamp. Credit for the Area lamp part goes to Stefan Werner (from D1995). --- intern/cycles/blender/blender_object.cpp | 1 + intern/cycles/kernel/geom/geom_object.h | 15 ++++++++++++++ intern/cycles/kernel/kernel_bake.h | 3 ++- intern/cycles/kernel/kernel_emission.h | 2 +- intern/cycles/kernel/kernel_light.h | 21 ++++++++++++++++---- intern/cycles/kernel/kernel_shader.h | 23 ++++++++++++++++------ intern/cycles/kernel/kernel_types.h | 4 +++- intern/cycles/kernel/osl/osl_services.cpp | 24 +++++++++++++++++++++++ intern/cycles/kernel/svm/svm_tex_coord.h | 6 +++--- intern/cycles/render/light.cpp | 12 ++++++++++++ intern/cycles/render/light.h | 2 ++ intern/cycles/util/util_math.h | 12 +++++++++--- 12 files changed, 106 insertions(+), 19 deletions(-) diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index f7f77dfb4cb..0d961c5bf88 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -153,6 +153,7 @@ void BlenderSync::sync_light(BL::Object& b_parent, /* location and (inverted!) direction */ light->co = transform_get_column(&tfm, 3); light->dir = -transform_get_column(&tfm, 2); + light->tfm = tfm; /* shader */ vector used_shaders; diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index 32900f7f27a..6b42f66b0d5 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -55,6 +55,21 @@ ccl_device_inline Transform object_fetch_transform(KernelGlobals *kg, int object return tfm; } +/* Lamp to world space transformation */ + +ccl_device_inline Transform lamp_fetch_transform(KernelGlobals *kg, int lamp, bool inverse) +{ + int offset = lamp*LIGHT_SIZE + (inverse? 8 : 5); + + Transform tfm; + tfm.x = kernel_tex_fetch(__light_data, offset + 0); + tfm.y = kernel_tex_fetch(__light_data, offset + 1); + tfm.z = kernel_tex_fetch(__light_data, offset + 2); + tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f); + + return tfm; +} + /* Object to world space transformation for motion vectors */ ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type) diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index fd9207fd69f..84575d35d7f 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -320,7 +320,8 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, P, Ng, Ng, shader, object, prim, u, v, 1.0f, 0.5f, - !(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED)); + !(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED), + LAMP_NONE); sd.I = sd.N; /* update differentials */ diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index ac498ba3592..9e4a631b998 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -65,7 +65,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg, shader_setup_from_sample(kg, emission_sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, - ls->u, ls->v, t, time, false); + ls->u, ls->v, t, time, false, ls->lamp); ls->Ng = ccl_fetch(emission_sd, Ng); diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index fffa9afb342..d4cc36d1495 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -297,7 +297,7 @@ ccl_device_inline float background_portal_pdf(KernelGlobals *kg, float3 axisu = make_float3(data1.y, data1.z, data1.w); float3 axisv = make_float3(data2.y, data2.z, data2.w); - if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL)) + if(!ray_quad_intersect(P, direction, 1e-4f, FLT_MAX, lightpos, axisu, axisv, dir, NULL, NULL, NULL, NULL)) continue; portal_pdf += area_light_sample(P, &lightpos, axisu, axisv, 0.0f, 0.0f, false); @@ -585,6 +585,10 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg, return false; } } + float2 uv = map_to_sphere(ls->Ng); + ls->u = uv.x; + ls->v = uv.y; + ls->pdf *= lamp_light_pdf(kg, ls->Ng, -ls->D, ls->t); } else { @@ -600,11 +604,16 @@ ccl_device_inline bool lamp_light_sample(KernelGlobals *kg, return false; } + float3 inplane = ls->P; ls->pdf = area_light_sample(P, &ls->P, axisu, axisv, randu, randv, true); + inplane = ls->P - inplane; + ls->u = dot(inplane, axisu) * (1.0f / dot(axisu, axisu)) + 0.5f; + ls->v = dot(inplane, axisv) * (1.0f / dot(axisv, axisv)) + 0.5f; + ls->Ng = D; ls->D = normalize_len(ls->P - P, &ls->t); @@ -706,6 +715,9 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, if(ls->eval_fac == 0.0f) return false; } + float2 uv = map_to_sphere(ls->Ng); + ls->u = uv.x; + ls->v = uv.y; /* compute pdf */ if(ls->t != FLT_MAX) @@ -730,8 +742,10 @@ ccl_device bool lamp_light_eval(KernelGlobals *kg, int lamp, float3 P, float3 D, float3 light_P = make_float3(data0.y, data0.z, data0.w); - if(!ray_quad_intersect(P, D, 0.0f, t, - light_P, axisu, axisv, Ng, &ls->P, &ls->t)) + if(!ray_quad_intersect(P, D, 0.0f, t, light_P, + axisu, axisv, Ng, + &ls->P, &ls->t, + &ls->u, &ls->v)) { return false; } @@ -887,4 +901,3 @@ ccl_device int light_select_num_samples(KernelGlobals *kg, int index) } CCL_NAMESPACE_END - diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 3e098c922dc..6480975a84d 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -242,7 +242,8 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, int shader, int object, int prim, float u, float v, float t, float time, - bool object_space) + bool object_space, + int lamp) { /* vectors */ ccl_fetch(sd, P) = P; @@ -250,7 +251,12 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, ccl_fetch(sd, Ng) = Ng; ccl_fetch(sd, I) = I; ccl_fetch(sd, shader) = shader; - ccl_fetch(sd, type) = (prim == PRIM_NONE)? PRIMITIVE_NONE: PRIMITIVE_TRIANGLE; + if(prim != PRIM_NONE) + ccl_fetch(sd, type) = PRIMITIVE_TRIANGLE; + else if(lamp != LAMP_NONE) + ccl_fetch(sd, type) = PRIMITIVE_LAMP; + else + ccl_fetch(sd, type) = PRIMITIVE_NONE; /* primitive */ #ifdef __INSTANCING__ @@ -270,11 +276,15 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, #ifdef __OBJECT_MOTION__ shader_setup_object_transforms(kg, sd, time); - } - - ccl_fetch(sd, time) = time; #else } + else if(lamp != LAMP_NONE) { + ccl_fetch(sd, ob_tfm) = lamp_fetch_transform(kg, lamp, false); + ccl_fetch(sd, ob_itfm) = lamp_fetch_transform(kg, lamp, true); + } + +#ifdef __OBJECT_MOTION__ + ccl_fetch(sd, time) = time; #endif /* transform into world space */ @@ -357,7 +367,8 @@ ccl_device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd, P, Ng, I, shader, object, prim, u, v, 0.0f, 0.5f, - !(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED)); + !(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED), + LAMP_NONE); } /* ShaderData setup from ray into background */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 734b4462a91..91b86618745 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -37,7 +37,7 @@ CCL_NAMESPACE_BEGIN /* constants */ #define OBJECT_SIZE 12 #define OBJECT_VECTOR_SIZE 6 -#define LIGHT_SIZE 5 +#define LIGHT_SIZE 11 #define FILTER_TABLE_SIZE 1024 #define RAMP_TABLE_SIZE 256 #define SHUTTER_TABLE_SIZE 256 @@ -552,6 +552,8 @@ typedef enum PrimitiveType { PRIMITIVE_MOTION_TRIANGLE = 2, PRIMITIVE_CURVE = 4, PRIMITIVE_MOTION_CURVE = 8, + /* Lamp primitive is not included below on purpose, since it is no real traceable primitive */ + PRIMITIVE_LAMP = 16, PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE|PRIMITIVE_MOTION_TRIANGLE), PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE|PRIMITIVE_MOTION_CURVE), diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 0f3edcb7eaa..26543862b80 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -166,6 +166,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result tfm = transform_transpose(tfm); COPY_MATRIX44(&result, &tfm); + return true; + } + else if(sd->type == PRIMITIVE_LAMP) { + Transform tfm = transform_transpose(sd->ob_tfm); + COPY_MATRIX44(&result, &tfm); + return true; } } @@ -196,6 +202,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 itfm = transform_transpose(itfm); COPY_MATRIX44(&result, &itfm); + return true; + } + else if(sd->type == PRIMITIVE_LAMP) { + Transform tfm = transform_transpose(sd->ob_itfm); + COPY_MATRIX44(&result, &tfm); + return true; } } @@ -285,6 +297,12 @@ bool OSLRenderServices::get_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 &result tfm = transform_transpose(tfm); COPY_MATRIX44(&result, &tfm); + return true; + } + else if(sd->type == PRIMITIVE_LAMP) { + Transform tfm = transform_transpose(sd->ob_tfm); + COPY_MATRIX44(&result, &tfm); + return true; } } @@ -310,6 +328,12 @@ bool OSLRenderServices::get_inverse_matrix(OSL::ShaderGlobals *sg, OSL::Matrix44 tfm = transform_transpose(tfm); COPY_MATRIX44(&result, &tfm); + return true; + } + else if(sd->type == PRIMITIVE_LAMP) { + Transform tfm = transform_transpose(sd->ob_itfm); + COPY_MATRIX44(&result, &tfm); + return true; } } diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index 6ea2539c543..6c3394adbce 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -49,7 +49,7 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg, } case NODE_TEXCO_NORMAL: { data = ccl_fetch(sd, N); - if(ccl_fetch(sd, object) != OBJECT_NONE) + if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP)) object_inverse_normal_transform(kg, sd, &data); break; } @@ -131,7 +131,7 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, } case NODE_TEXCO_NORMAL: { data = ccl_fetch(sd, N); - if(ccl_fetch(sd, object) != OBJECT_NONE) + if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP)) object_inverse_normal_transform(kg, sd, &data); break; } @@ -216,7 +216,7 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, } case NODE_TEXCO_NORMAL: { data = ccl_fetch(sd, N); - if(ccl_fetch(sd, object) != OBJECT_NONE) + if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP)) object_inverse_normal_transform(kg, sd, &data); break; } diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 93f6d7902f0..777f3229ce6 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -126,6 +126,8 @@ NODE_DEFINE(Light) SOCKET_FLOAT(spot_angle, "Spot Angle", M_PI_4_F); SOCKET_FLOAT(spot_smooth, "Spot Smooth", 0.0f); + SOCKET_TRANSFORM(tfm, "Transform", transform_identity()); + SOCKET_BOOLEAN(cast_shadow, "Cast Shadow", true); SOCKET_BOOLEAN(use_mis, "Use Mis", false); SOCKET_BOOLEAN(use_diffuse, "Use Diffuse", true); @@ -762,6 +764,11 @@ void LightManager::device_update_points(Device *device, light_data[light_index*LIGHT_SIZE + 4] = make_float4(max_bounces, 0.0f, 0.0f, 0.0f); + Transform tfm = light->tfm; + Transform itfm = transform_inverse(tfm); + memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3); + memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3); + light_index++; } @@ -788,6 +795,11 @@ void LightManager::device_update_points(Device *device, light_data[light_index*LIGHT_SIZE + 3] = make_float4(-1, dir.x, dir.y, dir.z); light_data[light_index*LIGHT_SIZE + 4] = make_float4(-1, 0.0f, 0.0f, 0.0f); + Transform tfm = light->tfm; + Transform itfm = transform_inverse(tfm); + memcpy(&light_data[light_index*LIGHT_SIZE + 5], &tfm, sizeof(float4)*3); + memcpy(&light_data[light_index*LIGHT_SIZE + 8], &itfm, sizeof(float4)*3); + light_index++; } diff --git a/intern/cycles/render/light.h b/intern/cycles/render/light.h index 040a672937d..f56530b6490 100644 --- a/intern/cycles/render/light.h +++ b/intern/cycles/render/light.h @@ -50,6 +50,8 @@ public: float3 axisv; float sizev; + Transform tfm; + int map_resolution; float spot_angle; diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index bd376e80c64..e2abfcde702 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -1579,7 +1579,7 @@ ccl_device_inline bool ray_triangle_intersect_uv( ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_mint, float ray_maxt, float3 quad_P, float3 quad_u, float3 quad_v, float3 quad_n, - float3 *isect_P, float *isect_t) + float3 *isect_P, float *isect_t, float *isect_u, float *isect_v) { float t = -(dot(ray_P, quad_n) - dot(quad_P, quad_n)) / dot(ray_D, quad_n); if(t < ray_mint || t > ray_maxt) @@ -1587,13 +1587,19 @@ ccl_device bool ray_quad_intersect(float3 ray_P, float3 ray_D, float ray_mint, f float3 hit = ray_P + t*ray_D; float3 inplane = hit - quad_P; - if(fabsf(dot(inplane, quad_u) / dot(quad_u, quad_u)) > 0.5f) + + float u = dot(inplane, quad_u) / dot(quad_u, quad_u) + 0.5f; + if(u < 0.0f || u > 1.0f) return false; - if(fabsf(dot(inplane, quad_v) / dot(quad_v, quad_v)) > 0.5f) + + float v = dot(inplane, quad_v) / dot(quad_v, quad_v) + 0.5f; + if(v < 0.0f || v > 1.0f) return false; if(isect_P) *isect_P = hit; if(isect_t) *isect_t = t; + if(isect_u) *isect_u = u; + if(isect_v) *isect_v = v; return true; } From 5aa6a2ec06bbfa9ddd255c90ee02da5f9be36f30 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sat, 29 Oct 2016 20:06:52 +0200 Subject: [PATCH 065/590] Fix T49846: OpenCL rendering compilation failure --- intern/cycles/kernel/kernel_projection.h | 2 +- intern/cycles/kernel/kernel_shader.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/cycles/kernel/kernel_projection.h b/intern/cycles/kernel/kernel_projection.h index ba714b6c382..9a2b0884a7e 100644 --- a/intern/cycles/kernel/kernel_projection.h +++ b/intern/cycles/kernel/kernel_projection.h @@ -235,7 +235,7 @@ ccl_device_inline void spherical_stereo_transform(KernelGlobals *kg, float3 *P, if(kernel_data.cam.pole_merge_angle_to > 0.0f) { const float pole_merge_angle_from = kernel_data.cam.pole_merge_angle_from, pole_merge_angle_to = kernel_data.cam.pole_merge_angle_to; - float altitude = fabsf(safe_asinf(D->z)); + float altitude = fabsf(safe_asinf((*D).z)); if(altitude > pole_merge_angle_to) { interocular_offset = 0.0f; } diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index 6480975a84d..a8070a133de 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -276,7 +276,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, #ifdef __OBJECT_MOTION__ shader_setup_object_transforms(kg, sd, time); -#else +#endif } else if(lamp != LAMP_NONE) { ccl_fetch(sd, ob_tfm) = lamp_fetch_transform(kg, lamp, false); From b2974d7ab79a257f8628c24c05d43da25791018d Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sun, 30 Oct 2016 01:33:10 +0200 Subject: [PATCH 066/590] Cycles: Add smoothing option to the Brick Texture This option allows to create a smoother transition between Bricks and Mortar - 0 applies no smoothing, and 1 smooths across the whole mortar width. Mainly useful for displacement textures. The new default value for the smoothing option is 0.1 to give some smoothing that helps with antialiasing, but existing nodes are loaded with smoothing 0 to preserve compatibility. Reviewers: sergey, dingto, juicyfruit, brecht Reviewed By: brecht Subscribers: Blendify, nutel Differential Revision: https://developer.blender.org/D2230 --- .../kernel/shaders/node_brick_texture.osl | 21 ++++++++---- intern/cycles/kernel/svm/svm_brick.h | 32 +++++++++++++------ intern/cycles/render/nodes.cpp | 10 +++++- intern/cycles/render/nodes.h | 2 +- .../shader/nodes/node_shader_tex_brick.c | 7 ++++ 5 files changed, 54 insertions(+), 18 deletions(-) diff --git a/intern/cycles/kernel/shaders/node_brick_texture.osl b/intern/cycles/kernel/shaders/node_brick_texture.osl index d5e0a7d4c8c..c303594681c 100644 --- a/intern/cycles/kernel/shaders/node_brick_texture.osl +++ b/intern/cycles/kernel/shaders/node_brick_texture.osl @@ -28,7 +28,7 @@ float brick_noise(int n) /* fast integer noise */ return 0.5 * ((float)nn / 1073741824.0); } -float brick(point p, float mortar_size, float bias, +float brick(point p, float mortar_size, float mortar_smooth, float bias, float BrickWidth, float row_height, float offset_amount, int offset_frequency, float squash_amount, int squash_frequency, float tint) { @@ -51,9 +51,17 @@ float brick(point p, float mortar_size, float bias, tint = clamp((brick_noise((rownum << 16) + (bricknum & 65535)) + bias), 0.0, 1.0); - return (x < mortar_size || y < mortar_size || - x > (brick_width - mortar_size) || - y > (row_height - mortar_size)) ? 1.0 : 0.0; + float min_dist = min(min(x, y), min(brick_width - x, row_height - y)); + if(min_dist >= mortar_size) { + return 0.0; + } + else if(mortar_smooth == 0.0) { + return 1.0; + } + else { + min_dist = 1.0 - min_dist/mortar_size; + return smoothstep(0.0, mortar_smooth, min_dist); + } } shader node_brick_texture( @@ -69,6 +77,7 @@ shader node_brick_texture( color Mortar = 0.0, float Scale = 5.0, float MortarSize = 0.02, + float MortarSmooth = 0.0, float Bias = 0.0, float BrickWidth = 0.5, float RowHeight = 0.25, @@ -83,7 +92,7 @@ shader node_brick_texture( float tint = 0.0; color Col = Color1; - Fac = brick(p * Scale, MortarSize, Bias, BrickWidth, RowHeight, + Fac = brick(p * Scale, MortarSize, MortarSmooth, Bias, BrickWidth, RowHeight, offset, offset_frequency, squash, squash_frequency, tint); if (Fac != 1.0) { @@ -91,6 +100,6 @@ shader node_brick_texture( Col = facm * Color1 + tint * Color2; } - Color = (Fac == 1.0) ? Mortar : Col; + Color = mix(Col, Mortar, Fac); } diff --git a/intern/cycles/kernel/svm/svm_brick.h b/intern/cycles/kernel/svm/svm_brick.h index 9b0cf5ab8c4..47e1ba2ba6b 100644 --- a/intern/cycles/kernel/svm/svm_brick.h +++ b/intern/cycles/kernel/svm/svm_brick.h @@ -27,7 +27,7 @@ ccl_device_noinline float brick_noise(int n) /* fast integer noise */ return 0.5f * ((float)nn / 1073741824.0f); } -ccl_device_noinline float2 svm_brick(float3 p, float mortar_size, float bias, +ccl_device_noinline float2 svm_brick(float3 p, float mortar_size, float mortar_smooth, float bias, float brick_width, float row_height, float offset_amount, int offset_frequency, float squash_amount, int squash_frequency) { @@ -47,30 +47,41 @@ ccl_device_noinline float2 svm_brick(float3 p, float mortar_size, float bias, x = (p.x+offset) - brick_width*bricknum; y = p.y - row_height*rownum; - return make_float2( - saturate((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias)), + float tint = saturate((brick_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias)); + float min_dist = min(min(x, y), min(brick_width - x, row_height - y)); - (x < mortar_size || y < mortar_size || - x > (brick_width - mortar_size) || - y > (row_height - mortar_size)) ? 1.0f : 0.0f); + float mortar; + if(min_dist >= mortar_size) { + mortar = 0.0f; + } + else if(mortar_smooth == 0.0f) { + mortar = 1.0f; + } + else { + min_dist = 1.0f - min_dist/mortar_size; + mortar = (min_dist < mortar_smooth)? smoothstepf(min_dist / mortar_smooth) : 1.0f; + } + + return make_float2(tint, mortar); } ccl_device void svm_node_tex_brick(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset) { uint4 node2 = read_node(kg, offset); uint4 node3 = read_node(kg, offset); + uint4 node4 = read_node(kg, offset); /* Input and Output Sockets */ uint co_offset, color1_offset, color2_offset, mortar_offset, scale_offset; uint mortar_size_offset, bias_offset, brick_width_offset, row_height_offset; - uint color_offset, fac_offset; + uint color_offset, fac_offset, mortar_smooth_offset; /* RNA properties */ uint offset_frequency, squash_frequency; decode_node_uchar4(node.y, &co_offset, &color1_offset, &color2_offset, &mortar_offset); decode_node_uchar4(node.z, &scale_offset, &mortar_size_offset, &bias_offset, &brick_width_offset); - decode_node_uchar4(node.w, &row_height_offset, &color_offset, &fac_offset, NULL); + decode_node_uchar4(node.w, &row_height_offset, &color_offset, &fac_offset, &mortar_smooth_offset); decode_node_uchar4(node2.x, &offset_frequency, &squash_frequency, NULL, NULL); @@ -82,13 +93,14 @@ ccl_device void svm_node_tex_brick(KernelGlobals *kg, ShaderData *sd, float *sta float scale = stack_load_float_default(stack, scale_offset, node2.y); float mortar_size = stack_load_float_default(stack, mortar_size_offset, node2.z); + float mortar_smooth = stack_load_float_default(stack, mortar_smooth_offset, node4.x); float bias = stack_load_float_default(stack, bias_offset, node2.w); float brick_width = stack_load_float_default(stack, brick_width_offset, node3.x); float row_height = stack_load_float_default(stack, row_height_offset, node3.y); float offset_amount = __int_as_float(node3.z); float squash_amount = __int_as_float(node3.w); - float2 f2 = svm_brick(co*scale, mortar_size, bias, brick_width, row_height, + float2 f2 = svm_brick(co*scale, mortar_size, mortar_smooth, bias, brick_width, row_height, offset_amount, offset_frequency, squash_amount, squash_frequency); float tint = f2.x; @@ -100,7 +112,7 @@ ccl_device void svm_node_tex_brick(KernelGlobals *kg, ShaderData *sd, float *sta } if(stack_valid(color_offset)) - stack_store_float3(stack, color_offset, (f == 1.0f)? mortar: color1); + stack_store_float3(stack, color_offset, lerp(color1, mortar, f)); if(stack_valid(fac_offset)) stack_store_float(stack, fac_offset, f); } diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 3b4aa389c13..f293af3c40a 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1257,6 +1257,7 @@ NODE_DEFINE(BrickTextureNode) SOCKET_IN_COLOR(mortar, "Mortar", make_float3(0.0f, 0.0f, 0.0f)); SOCKET_IN_FLOAT(scale, "Scale", 5.0f); SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f); + SOCKET_IN_FLOAT(mortar_smooth, "Mortar Smooth", 0.0f); SOCKET_IN_FLOAT(bias, "Bias", 0.0f); SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f); SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f); @@ -1280,6 +1281,7 @@ void BrickTextureNode::compile(SVMCompiler& compiler) ShaderInput *mortar_in = input("Mortar"); ShaderInput *scale_in = input("Scale"); ShaderInput *mortar_size_in = input("Mortar Size"); + ShaderInput *mortar_smooth_in = input("Mortar Smooth"); ShaderInput *bias_in = input("Bias"); ShaderInput *brick_width_in = input("Brick Width"); ShaderInput *row_height_in = input("Row Height"); @@ -1303,7 +1305,8 @@ void BrickTextureNode::compile(SVMCompiler& compiler) compiler.encode_uchar4( compiler.stack_assign_if_linked(row_height_in), compiler.stack_assign_if_linked(color_out), - compiler.stack_assign_if_linked(fac_out))); + compiler.stack_assign_if_linked(fac_out), + compiler.stack_assign_if_linked(mortar_smooth_in))); compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency), __float_as_int(scale), @@ -1315,6 +1318,11 @@ void BrickTextureNode::compile(SVMCompiler& compiler) __float_as_int(offset), __float_as_int(squash)); + compiler.add_node(__float_as_int(mortar_smooth), + SVM_STACK_INVALID, + SVM_STACK_INVALID, + SVM_STACK_INVALID); + tex_mapping.compile_end(compiler, vector_in, vector_offset); } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 13791c668ed..eb0f7977dd1 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -243,7 +243,7 @@ public: int offset_frequency, squash_frequency; float3 color1, color2, mortar; - float scale, mortar_size, bias, brick_width, row_height; + float scale, mortar_size, mortar_smooth, bias, brick_width, row_height; float3 vector; virtual int get_group() { return NODE_GROUP_LEVEL_2; } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c index bb7f2166a8a..0be47c4f751 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.c @@ -36,6 +36,7 @@ static bNodeSocketTemplate sh_node_tex_brick_in[] = { { SOCK_RGBA, 1, N_("Mortar"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, { SOCK_FLOAT, 1, N_("Scale"), 5.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, { SOCK_FLOAT, 1, N_("Mortar Size"), 0.02f, 0.0f, 0.0f, 0.0f, 0.0f, 0.125f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, + { SOCK_FLOAT, 1, N_("Mortar Smooth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, { SOCK_FLOAT, 1, N_("Bias"), 0.0f, 0.0f, 0.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, { SOCK_FLOAT, 1, N_("Brick Width"), 0.5f, 0.0f, 0.0f, 0.0f, 0.01f, 100.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, { SOCK_FLOAT, 1, N_("Row Height"), 0.25f, 0.0f, 0.0f, 0.0f, 0.01f, 100.0f, PROP_NONE, SOCK_NO_INTERNAL_LINK}, @@ -60,6 +61,12 @@ static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node) tex->squash_freq = 2; node->storage = tex; + + for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) { + if (STREQ(sock->name, "Mortar Smooth")) { + ((bNodeSocketValueFloat*)sock->default_value)->value = 0.1f; + } + } } static int node_shader_gpu_tex_brick(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) From ce785868a56a1446750f5af1779f7623ca462ec2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sun, 30 Oct 2016 03:42:46 +0100 Subject: [PATCH 067/590] Fix compile errors for when WITH_ALEMBIC is OFF. --- source/blender/blenkernel/intern/cachefile.c | 4 ++++ source/blender/blenkernel/intern/constraint.c | 2 ++ source/blender/makesrna/intern/rna_constraint.c | 2 ++ source/blender/makesrna/intern/rna_modifier.c | 2 ++ source/blender/modifiers/intern/MOD_meshsequencecache.c | 2 ++ 5 files changed, 12 insertions(+) diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 2a2699f3a14..6a08673144e 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -212,7 +212,9 @@ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)md; if (cache_file == mcmd->cache_file) { +#ifdef WITH_ALEMBIC CacheReader_free(mcmd->reader); +#endif mcmd->reader = NULL; mcmd->object_path[0] = '\0'; } @@ -226,7 +228,9 @@ void BKE_cachefile_clean(Scene *scene, CacheFile *cache_file) bTransformCacheConstraint *data = con->data; if (cache_file == data->cache_file) { +#ifdef WITH_ALEMBIC CacheReader_free(data->reader); +#endif data->reader = NULL; data->object_path[0] = '\0'; } diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index c7750707cc4..b85f1b838ff 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4401,7 +4401,9 @@ static void transformcache_free(bConstraint *con) } if (data->reader) { +#ifdef WITH_ALEMBIC CacheReader_free(data->reader); +#endif } } diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c index ad037af943d..de1a0f24c31 100644 --- a/source/blender/makesrna/intern/rna_constraint.c +++ b/source/blender/makesrna/intern/rna_constraint.c @@ -478,6 +478,7 @@ static void rna_Constraint_objectSolver_camera_set(PointerRNA *ptr, PointerRNA v static void rna_Constraint_transformCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr) { +#ifdef WITH_ALEMBIC bConstraint *con = (bConstraint *)ptr->data; bTransformCacheConstraint *data = (bTransformCacheConstraint *)con->data; Object *ob = (Object *)ptr->id.data; @@ -486,6 +487,7 @@ static void rna_Constraint_transformCache_object_path_update(Main *bmain, Scene data->reader, ob, data->object_path); +#endif rna_Constraint_update(bmain, scene, ptr); } diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index b30c156a88c..c4f0db38a16 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1133,6 +1133,7 @@ static int rna_CorrectiveSmoothModifier_is_bind_get(PointerRNA *ptr) static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, PointerRNA *ptr) { +#ifdef WITH_ALEMBIC MeshSeqCacheModifierData *mcmd = (MeshSeqCacheModifierData *)ptr->data; Object *ob = (Object *)ptr->id.data; @@ -1140,6 +1141,7 @@ static void rna_MeshSequenceCache_object_path_update(Main *bmain, Scene *scene, mcmd->reader, ob, mcmd->object_path); +#endif rna_Modifier_update(bmain, scene, ptr); } diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index cf137784e65..d25e8e38de3 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -78,7 +78,9 @@ static void freeData(ModifierData *md) } if (mcmd->reader) { +#ifdef WITH_ALEMBIC CacheReader_free(mcmd->reader); +#endif } } From 26bf230920cb9ca0aa9626430169967f9e120482 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sat, 29 Oct 2016 23:47:30 +0200 Subject: [PATCH 068/590] Cycles: Add optional probabilistic termination of light samples based on their expected contribution In scenes with many lights, some of them might have a very small contribution to some pixels, but the shadow rays are traced anyways. To avoid that, this patch adds probabilistic termination to light samples - if the contribution before checking for shadowing is below a user-defined threshold, the sample will be discarded with probability (1 - (contribution / threshold)) and otherwise kept, but weighted more to remain unbiased. This is the same approach that's also used in path termination based on length. Note that the rendering remains unbiased with this option, it just adds a bit of noise - but if the setting is used moderately, the speedup gained easily outweighs the additional noise. Reviewers: #cycles Subscribers: sergey, brecht Differential Revision: https://developer.blender.org/D2217 --- intern/cycles/blender/addon/properties.py | 7 ++++ intern/cycles/blender/addon/ui.py | 1 + intern/cycles/blender/blender_sync.cpp | 1 + intern/cycles/kernel/kernel_accumulate.h | 38 ++++++++++++++++--- intern/cycles/kernel/kernel_emission.h | 15 +++++++- intern/cycles/kernel/kernel_path.h | 1 - intern/cycles/kernel/kernel_path_surface.h | 12 ++++-- intern/cycles/kernel/kernel_path_volume.h | 12 ++++-- intern/cycles/kernel/kernel_random.h | 17 +++++++++ intern/cycles/kernel/kernel_shader.h | 2 +- intern/cycles/kernel/kernel_types.h | 5 ++- .../kernel/split/kernel_direct_lighting.h | 3 +- intern/cycles/render/integrator.cpp | 8 ++++ intern/cycles/render/integrator.h | 2 + intern/cycles/util/util_math.h | 5 +++ 15 files changed, 109 insertions(+), 20 deletions(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 977d7f75bb7..ede3ece5bce 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -266,6 +266,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Sample all lights (for indirect samples), rather than randomly picking one", default=True, ) + cls.light_sampling_threshold = FloatProperty( + name="Light Sampling Threshold", + description="Probabilistically terminate light samples when the light contribution is below this threshold (more noise but faster rendering). " + "Zero disables the test and never ignores lights.", + min=0.0, max=1.0, + default=0.05, + ) cls.caustics_reflective = BoolProperty( name="Reflective Caustics", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 52872d2b83f..4942a71ce4d 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -166,6 +166,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): sub.prop(cscene, "sample_clamp_direct") sub.prop(cscene, "sample_clamp_indirect") + sub.prop(cscene, "light_sampling_threshold") if cscene.progressive == 'PATH' or use_branched_path(context) is False: col = split.column() diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 4ca202ac40d..bc5c3bb8096 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -284,6 +284,7 @@ void BlenderSync::sync_integrator() integrator->sample_all_lights_direct = get_boolean(cscene, "sample_all_lights_direct"); integrator->sample_all_lights_indirect = get_boolean(cscene, "sample_all_lights_indirect"); + integrator->light_sampling_threshold = get_float(cscene, "light_sampling_threshold"); int diffuse_samples = get_int(cscene, "diffuse_samples"); int glossy_samples = get_int(cscene, "glossy_samples"); diff --git a/intern/cycles/kernel/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index 623c1dcaaa1..6c3ee6b8098 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -96,7 +96,7 @@ ccl_device_inline bool bsdf_eval_is_zero(BsdfEval *eval) } } -ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value) +ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float value) { #ifdef __PASSES__ if(eval->use_light_pass) { @@ -115,6 +115,36 @@ ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value) } } +ccl_device_inline void bsdf_eval_mul3(BsdfEval *eval, float3 value) +{ +#ifdef __PASSES__ + if(eval->use_light_pass) { + eval->diffuse *= value; + eval->glossy *= value; + eval->transmission *= value; + eval->subsurface *= value; + eval->scatter *= value; + + /* skipping transparent, this function is used by for eval(), will be zero then */ + } + else + eval->diffuse *= value; +#else + eval->diffuse *= value; +#endif +} + +ccl_device_inline float3 bsdf_eval_sum(BsdfEval *eval) +{ +#ifdef __PASSES__ + if(eval->use_light_pass) { + return eval->diffuse + eval->glossy + eval->transmission + eval->subsurface + eval->scatter; + } + else +#endif + return eval->diffuse; +} + /* Path Radiance * * We accumulate different render passes separately. After summing at the end @@ -193,8 +223,7 @@ ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space } else { /* transparent bounce before first hit, or indirectly visible through BSDF */ - float3 sum = (bsdf_eval->diffuse + bsdf_eval->glossy + bsdf_eval->transmission + bsdf_eval->transparent + - bsdf_eval->subsurface + bsdf_eval->scatter) * inverse_pdf; + float3 sum = (bsdf_eval_sum(bsdf_eval) + bsdf_eval->transparent) * inverse_pdf; *throughput *= sum; } } @@ -264,8 +293,7 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 through } else { /* indirectly visible lighting after BSDF bounce */ - float3 sum = bsdf_eval->diffuse + bsdf_eval->glossy + bsdf_eval->transmission + bsdf_eval->subsurface + bsdf_eval->scatter; - L->indirect += throughput*sum*shadow; + L->indirect += throughput*bsdf_eval_sum(bsdf_eval)*shadow; } } else diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index 9e4a631b998..8c7c651a053 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -94,7 +94,8 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, ccl_addr_space PathState *state, Ray *ray, BsdfEval *eval, - bool *is_lamp) + bool *is_lamp, + float rand_terminate) { if(ls->pdf == 0.0f) return false; @@ -134,7 +135,7 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, shader_bsdf_eval(kg, sd, ls->D, eval, ls->pdf, ls->shader & SHADER_USE_MIS); #endif - bsdf_eval_mul(eval, light_eval/ls->pdf); + bsdf_eval_mul3(eval, light_eval/ls->pdf); #ifdef __PASSES__ /* use visibility flag to skip lights */ @@ -155,6 +156,16 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, if(bsdf_eval_is_zero(eval)) return false; + if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) { + float probability = max3(bsdf_eval_sum(eval)) * kernel_data.integrator.light_inv_rr_threshold; + if(probability < 1.0f) { + if(rand_terminate >= probability) { + return false; + } + bsdf_eval_mul(eval, 1.0f / probability); + } + } + if(ls->shader & SHADER_CAST_SHADOW) { /* setup ray */ bool transmit = (dot(ccl_fetch(sd, Ng), ls->D) < 0.0f); diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 7558fb94478..7ef79815ad5 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -851,7 +851,6 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, } else if(probability != 1.0f) { float terminate = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_TERMINATE); - if(terminate >= probability) break; diff --git a/intern/cycles/kernel/kernel_path_surface.h b/intern/cycles/kernel/kernel_path_surface.h index 45f0f1cbfaa..fea503d06e5 100644 --- a/intern/cycles/kernel/kernel_path_surface.h +++ b/intern/cycles/kernel/kernel_path_surface.h @@ -49,6 +49,7 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal for(int j = 0; j < num_samples; j++) { float light_u, light_v; path_branched_rng_2D(kg, &lamp_rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); + float terminate = path_branched_rng_light_termination(kg, &lamp_rng, state, j, num_samples); LightSample ls; if(lamp_light_sample(kg, i, light_u, light_v, ccl_fetch(sd, P), &ls)) { @@ -57,7 +58,7 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal if(kernel_data.integrator.pdf_triangles != 0.0f) ls.pdf *= 2.0f; - if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) { + if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; @@ -79,6 +80,7 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal float light_t = path_branched_rng_1D(kg, rng, state, j, num_samples, PRNG_LIGHT); float light_u, light_v; path_branched_rng_2D(kg, rng, state, j, num_samples, PRNG_LIGHT_U, &light_u, &light_v); + float terminate = path_branched_rng_light_termination(kg, rng, state, j, num_samples); /* only sample triangle lights */ if(kernel_data.integrator.num_all_lights) @@ -90,7 +92,7 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal if(kernel_data.integrator.num_all_lights) ls.pdf *= 2.0f; - if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) { + if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; @@ -108,11 +110,12 @@ ccl_device_noinline void kernel_branched_path_surface_connect_light(KernelGlobal float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT); float light_u, light_v; path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v); + float terminate = path_state_rng_light_termination(kg, rng, state); LightSample ls; if(light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls)) { /* sample random light */ - if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) { + if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; @@ -210,7 +213,8 @@ ccl_device_inline void kernel_path_surface_connect_light(KernelGlobals *kg, ccl_ LightSample ls; if(light_sample(kg, light_t, light_u, light_v, ccl_fetch(sd, time), ccl_fetch(sd, P), state->bounce, &ls)) { - if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) { + float terminate = path_state_rng_light_termination(kg, rng, state); + if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; diff --git a/intern/cycles/kernel/kernel_path_volume.h b/intern/cycles/kernel/kernel_path_volume.h index 5ee1912c913..3d3b7385d8b 100644 --- a/intern/cycles/kernel/kernel_path_volume.h +++ b/intern/cycles/kernel/kernel_path_volume.h @@ -48,7 +48,8 @@ ccl_device_inline void kernel_path_volume_connect_light( if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { - if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) { + float terminate = path_state_rng_light_termination(kg, rng, state); + if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; @@ -161,7 +162,8 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG if(kernel_data.integrator.pdf_triangles != 0.0f) ls.pdf *= 2.0f; - if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) { + float terminate = path_branched_rng_light_termination(kg, rng, state, j, num_samples); + if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; @@ -209,7 +211,8 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG if(kernel_data.integrator.num_all_lights) ls.pdf *= 2.0f; - if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) { + float terminate = path_branched_rng_light_termination(kg, rng, state, j, num_samples); + if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; @@ -246,7 +249,8 @@ ccl_device void kernel_branched_path_volume_connect_light(KernelGlobals *kg, RNG /* todo: split up light_sample so we don't have to call it again with new position */ if(light_sample(kg, light_t, light_u, light_v, sd->time, sd->P, state->bounce, &ls)) { /* sample random light */ - if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp)) { + float terminate = path_state_rng_light_termination(kg, rng, state); + if(direct_emission(kg, sd, emission_sd, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* trace shadow ray */ float3 shadow; diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index 4a76ffddbe7..2372b07d974 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -300,6 +300,23 @@ ccl_device_inline void path_branched_rng_2D(KernelGlobals *kg, ccl_addr_space RN path_rng_2D(kg, rng, state->sample*num_branches + branch, state->num_samples*num_branches, state->rng_offset + dimension, fx, fy); } +/* Utitility functions to get light termination value, since it might not be needed in many cases. */ +ccl_device_inline float path_state_rng_light_termination(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state) +{ + if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) { + return path_state_rng_1D_for_decision(kg, rng, state, PRNG_LIGHT_TERMINATE); + } + return 0.0f; +} + +ccl_device_inline float path_branched_rng_light_termination(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state, int branch, int num_branches) +{ + if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) { + return path_branched_rng_1D_for_decision(kg, rng, state, branch, num_branches, PRNG_LIGHT_TERMINATE); + } + return 0.0f; +} + ccl_device_inline void path_state_branch(PathState *state, int branch, int num_branches) { /* path is splitting into a branch, adjust so that each branch diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index a8070a133de..b4b980c4e90 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -572,7 +572,7 @@ void shader_bsdf_eval(KernelGlobals *kg, _shader_bsdf_multi_eval(kg, sd, omega_in, &pdf, -1, eval, 0.0f, 0.0f); if(use_mis) { float weight = power_heuristic(light_pdf, pdf); - bsdf_eval_mul(eval, make_float3(weight, weight, weight)); + bsdf_eval_mul(eval, weight); } } } diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 91b86618745..a6c31d4a518 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -250,7 +250,7 @@ enum PathTraceDimension { PRNG_LIGHT = 3, PRNG_LIGHT_U = 4, PRNG_LIGHT_V = 5, - PRNG_UNUSED_3 = 6, + PRNG_LIGHT_TERMINATE = 6, PRNG_TERMINATE = 7, #ifdef __VOLUME__ @@ -1123,8 +1123,9 @@ typedef struct KernelIntegrator { float volume_step_size; int volume_samples; + float light_inv_rr_threshold; + int pad1; - int pad2; } KernelIntegrator; static_assert_align(KernelIntegrator, 16); diff --git a/intern/cycles/kernel/split/kernel_direct_lighting.h b/intern/cycles/kernel/split/kernel_direct_lighting.h index 6ad736fc2c1..82ca18829d3 100644 --- a/intern/cycles/kernel/split/kernel_direct_lighting.h +++ b/intern/cycles/kernel/split/kernel_direct_lighting.h @@ -72,6 +72,7 @@ ccl_device char kernel_direct_lighting( float light_t = path_state_rng_1D(kg, rng, state, PRNG_LIGHT); float light_u, light_v; path_state_rng_2D(kg, rng, state, PRNG_LIGHT_U, &light_u, &light_v); + float terminate = path_state_rng_light_termination(kg, rng, state); LightSample ls; if(light_sample(kg, @@ -88,7 +89,7 @@ ccl_device char kernel_direct_lighting( BsdfEval L_light; bool is_lamp; - if(direct_emission(kg, sd, kg->sd_input, &ls, state, &light_ray, &L_light, &is_lamp)) { + if(direct_emission(kg, sd, kg->sd_input, &ls, state, &light_ray, &L_light, &is_lamp, terminate)) { /* Write intermediate data to global memory to access from * the next kernel. */ diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index 63914e57319..a9a33d2e789 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -65,6 +65,7 @@ NODE_DEFINE(Integrator) SOCKET_BOOLEAN(sample_all_lights_direct, "Sample All Lights Direct", true); SOCKET_BOOLEAN(sample_all_lights_indirect, "Sample All Lights Indirect", true); + SOCKET_FLOAT(light_sampling_threshold, "Light Sampling Threshold", 0.05f); static NodeEnum method_enum; method_enum.insert("path", PATH); @@ -164,6 +165,13 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene kintegrator->sampling_pattern = sampling_pattern; kintegrator->aa_samples = aa_samples; + if(light_sampling_threshold > 0.0f) { + kintegrator->light_inv_rr_threshold = 1.0f / light_sampling_threshold; + } + else { + kintegrator->light_inv_rr_threshold = 0.0f; + } + /* sobol directions table */ int max_samples = 1; diff --git a/intern/cycles/render/integrator.h b/intern/cycles/render/integrator.h index 39eaaf246d4..17fdd0ef1db 100644 --- a/intern/cycles/render/integrator.h +++ b/intern/cycles/render/integrator.h @@ -64,8 +64,10 @@ public: int mesh_light_samples; int subsurface_samples; int volume_samples; + bool sample_all_lights_direct; bool sample_all_lights_indirect; + float light_sampling_threshold; enum Method { BRANCHED_PATH = 0, diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index e2abfcde702..3f4d3e06c0b 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -162,6 +162,11 @@ ccl_device_inline float max4(float a, float b, float c, float d) return max(max(a, b), max(c, d)); } +ccl_device_inline float max3(float3 a) +{ + return max(max(a.x, a.y), a.z); +} + #ifndef __KERNEL_OPENCL__ ccl_device_inline int clamp(int a, int mn, int mx) From 4e68f48227e228fbf75736005ceed4cf1cb55215 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sun, 30 Oct 2016 00:56:39 +0200 Subject: [PATCH 069/590] Cycles: Initialize the RNG state from the kernel instead of the host This allows to save a memory copy, which will be particularly useful for network rendering. Reviewers: sergey, brecht, dingto, juicyfruit, maiself Differential Revision: https://developer.blender.org/D2323 --- intern/cycles/kernel/CMakeLists.txt | 1 + intern/cycles/kernel/kernel_path_common.h | 6 ++++++ intern/cycles/render/buffers.cpp | 8 -------- intern/cycles/util/util_hash.h | 6 ++++-- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 694f19a808a..56bcafbce38 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -177,6 +177,7 @@ set(SRC_UTIL_HEADERS ../util/util_atomic.h ../util/util_color.h ../util/util_half.h + ../util/util_hash.h ../util/util_math.h ../util/util_math_fast.h ../util/util_static_assert.h diff --git a/intern/cycles/kernel/kernel_path_common.h b/intern/cycles/kernel/kernel_path_common.h index 1912dfa16ed..13597eab287 100644 --- a/intern/cycles/kernel/kernel_path_common.h +++ b/intern/cycles/kernel/kernel_path_common.h @@ -14,6 +14,8 @@ * limitations under the License. */ +#include "util_hash.h" + CCL_NAMESPACE_BEGIN ccl_device_inline void kernel_path_trace_setup(KernelGlobals *kg, @@ -28,6 +30,10 @@ ccl_device_inline void kernel_path_trace_setup(KernelGlobals *kg, int num_samples = kernel_data.integrator.aa_samples; + if(sample == 0) { + *rng_state = hash_int_2d(x, y); + } + path_rng_init(kg, rng_state, sample, num_samples, rng, x, y, &filter_u, &filter_v); /* sample camera ray */ diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index 1e170d3a96e..cb20e811708 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -135,15 +135,7 @@ void RenderBuffers::reset(Device *device, BufferParams& params_) /* allocate rng state */ rng_state.resize(params.width, params.height); - uint *init_state = rng_state.resize(params.width, params.height); - int x, y, width = params.width, height = params.height; - - for(y = 0; y < height; y++) - for(x = 0; x < width; x++) - init_state[y*width + x] = hash_int_2d(params.full_x+x, params.full_y+y); - device->mem_alloc(rng_state, MEM_READ_WRITE); - device->mem_copy_to(rng_state); } bool RenderBuffers::copy_from_device() diff --git a/intern/cycles/util/util_hash.h b/intern/cycles/util/util_hash.h index 3ff2802b46d..98c3a681ff2 100644 --- a/intern/cycles/util/util_hash.h +++ b/intern/cycles/util/util_hash.h @@ -21,7 +21,7 @@ CCL_NAMESPACE_BEGIN -static inline uint hash_int_2d(uint kx, uint ky) +ccl_device_inline uint hash_int_2d(uint kx, uint ky) { #define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) @@ -44,11 +44,12 @@ static inline uint hash_int_2d(uint kx, uint ky) #undef rot } -static inline uint hash_int(uint k) +ccl_device_inline uint hash_int(uint k) { return hash_int_2d(k, 0); } +#ifndef __KERNEL_GPU__ static inline uint hash_string(const char *str) { uint i = 0, c; @@ -58,6 +59,7 @@ static inline uint hash_string(const char *str) return i; } +#endif CCL_NAMESPACE_END From b6d35e1fa74076e5072e53dad63dc712f85a7027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Sun, 30 Oct 2016 12:29:05 +0100 Subject: [PATCH 070/590] Viewport smoke: add support to render the volume using a color ramp. This is yet another debug option that allows to render an arbitrary simulation field by using a color ramp to inspect its voxel values. Note that when using this, fire rendering is turned off. Reviewers: plasmasolutions, gottfried Differential Revision: https://developer.blender.org/D1733 --- .../startup/bl_ui/properties_physics_smoke.py | 8 + source/blender/blenkernel/intern/smoke.c | 11 ++ source/blender/blenloader/intern/readfile.c | 1 + source/blender/blenloader/intern/writefile.c | 4 + .../blender/editors/space_view3d/drawobject.c | 4 - .../blender/editors/space_view3d/drawvolume.c | 187 +++++++++++------- .../editors/space_view3d/view3d_intern.h | 6 - source/blender/gpu/GPU_shader.h | 1 + source/blender/gpu/intern/gpu_shader.c | 13 ++ .../gpu/shaders/gpu_shader_smoke_frag.glsl | 12 ++ source/blender/makesdna/DNA_smoke_types.h | 23 ++- source/blender/makesrna/intern/rna_smoke.c | 48 +++++ 12 files changed, 236 insertions(+), 82 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py index df03f23a4b5..0374d032141 100644 --- a/release/scripts/startup/bl_ui/properties_physics_smoke.py +++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py @@ -397,6 +397,14 @@ class PHYSICS_PT_smoke_display_settings(PhysicButtonsPanel, Panel): col.prop(domain, "vector_draw_type") col.prop(domain, "vector_scale") + layout.separator() + layout.label(text="Color Mapping:") + layout.prop(domain, "use_color_ramp") + col = layout.column(); + col.enabled = domain.use_color_ramp + col.prop(domain, "coba_field") + col.template_color_ramp(domain, "color_ramp", expand=True) + if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index 05540f51588..e8970d416e9 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -360,6 +360,10 @@ static void smokeModifier_freeDomain(SmokeModifierData *smd) BKE_ptcache_free_list(&(smd->domain->ptcaches[0])); smd->domain->point_cache[0] = NULL; + if (smd->domain->coba) { + MEM_freeN(smd->domain->coba); + } + MEM_freeN(smd->domain); smd->domain = NULL; } @@ -544,6 +548,9 @@ void smokeModifier_createType(struct SmokeModifierData *smd) smd->domain->slice_depth = 0.5f; smd->domain->slice_axis = 0; smd->domain->vector_scale = 1.0f; + + smd->domain->coba = NULL; + smd->domain->coba_field = FLUID_FIELD_DENSITY; } else if (smd->type & MOD_SMOKE_TYPE_FLOW) { @@ -646,6 +653,10 @@ void smokeModifier_copy(struct SmokeModifierData *smd, struct SmokeModifierData tsmd->domain->draw_velocity = smd->domain->draw_velocity; tsmd->domain->vector_draw_type = smd->domain->vector_draw_type; tsmd->domain->vector_scale = smd->domain->vector_scale; + + if (smd->domain->coba) { + tsmd->domain->coba = MEM_dupallocN(smd->domain->coba); + } } else if (tsmd->flow) { tsmd->flow->psys = smd->flow->psys; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 41b275751d1..98c8a260993 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5091,6 +5091,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) smd->domain->tex = NULL; smd->domain->tex_shadow = NULL; smd->domain->tex_wt = NULL; + smd->domain->coba = newdataadr(fd, smd->domain->coba); smd->domain->effector_weights = newdataadr(fd, smd->domain->effector_weights); if (!smd->domain->effector_weights) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 6678189872c..d104fc85eb7 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1728,6 +1728,10 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) smd->domain->point_cache[1]->step = 1; write_pointcaches(wd, &(smd->domain->ptcaches[1])); + + if (smd->domain->coba) { + writestruct(wd, DATA, ColorBand, 1, smd->domain->coba); + } } writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index ea40d4eb5e1..dd282c427f6 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -7915,10 +7915,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short if (!render_override && sds->draw_velocity) { draw_smoke_velocity(sds, viewnormal); } - -#ifdef SMOKE_DEBUG_HEAT - draw_smoke_heat(smd->domain, ob); -#endif } } diff --git a/source/blender/editors/space_view3d/drawvolume.c b/source/blender/editors/space_view3d/drawvolume.c index b0e21601b9c..27ecbf83db5 100644 --- a/source/blender/editors/space_view3d/drawvolume.c +++ b/source/blender/editors/space_view3d/drawvolume.c @@ -1,4 +1,4 @@ -/* +/* * ***** BEGIN GPL LICENSE BLOCK ***** * * This program is free software; you can redistribute it and/or @@ -41,6 +41,7 @@ #include "BLI_math.h" #include "BKE_DerivedMesh.h" +#include "BKE_texture.h" #include "BKE_particle.h" #include "smoke_API.h" @@ -62,28 +63,33 @@ struct GPUTexture; # include "PIL_time_utildefines.h" #endif -static GPUTexture *create_flame_spectrum_texture(void) +/* *************************** Transfer functions *************************** */ + +enum { + TFUNC_FLAME_SPECTRUM = 0, + TFUNC_COLOR_RAMP = 1, +}; + +#define TFUNC_WIDTH 256 + +static void create_flame_spectrum_texture(float *data) { -#define SPEC_WIDTH 256 #define FIRE_THRESH 7 #define MAX_FIRE_ALPHA 0.06f #define FULL_ON_FIRE 100 - GPUTexture *tex; - int i, j, k; - float *spec_data = MEM_mallocN(SPEC_WIDTH * 4 * sizeof(float), "spec_data"); - float *spec_pixels = MEM_mallocN(SPEC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); + float *spec_pixels = MEM_mallocN(TFUNC_WIDTH * 4 * 16 * 16 * sizeof(float), "spec_pixels"); - blackbody_temperature_to_rgb_table(spec_data, SPEC_WIDTH, 1500, 3000); + blackbody_temperature_to_rgb_table(data, TFUNC_WIDTH, 1500, 3000); - for (i = 0; i < 16; i++) { - for (j = 0; j < 16; j++) { - for (k = 0; k < SPEC_WIDTH; k++) { - int index = (j * SPEC_WIDTH * 16 + i * SPEC_WIDTH + k) * 4; + for (int i = 0; i < 16; i++) { + for (int j = 0; j < 16; j++) { + for (int k = 0; k < TFUNC_WIDTH; k++) { + int index = (j * TFUNC_WIDTH * 16 + i * TFUNC_WIDTH + k) * 4; if (k >= FIRE_THRESH) { - spec_pixels[index] = (spec_data[k * 4]); - spec_pixels[index + 1] = (spec_data[k * 4 + 1]); - spec_pixels[index + 2] = (spec_data[k * 4 + 2]); + spec_pixels[index] = (data[k * 4]); + spec_pixels[index + 1] = (data[k * 4 + 1]); + spec_pixels[index + 2] = (data[k * 4 + 2]); spec_pixels[index + 3] = MAX_FIRE_ALPHA * ( (k > FULL_ON_FIRE) ? 1.0f : (k - FIRE_THRESH) / ((float)FULL_ON_FIRE - FIRE_THRESH)); } @@ -94,19 +100,69 @@ static GPUTexture *create_flame_spectrum_texture(void) } } - tex = GPU_texture_create_1D(SPEC_WIDTH, spec_pixels, NULL); + memcpy(data, spec_pixels, sizeof(float) * 4 * TFUNC_WIDTH); - MEM_freeN(spec_data); MEM_freeN(spec_pixels); -#undef SPEC_WIDTH #undef FIRE_THRESH #undef MAX_FIRE_ALPHA #undef FULL_ON_FIRE +} + +static void create_color_ramp(const ColorBand *coba, float *data) +{ + for (int i = 0; i < TFUNC_WIDTH; i++) { + do_colorband(coba, (float)i / TFUNC_WIDTH, &data[i * 4]); + } +} + +static GPUTexture *create_transfer_function(int type, const ColorBand *coba) +{ + float *data = MEM_mallocN(sizeof(float) * 4 * TFUNC_WIDTH, __func__); + + switch (type) { + case TFUNC_FLAME_SPECTRUM: + create_flame_spectrum_texture(data); + break; + case TFUNC_COLOR_RAMP: + create_color_ramp(coba, data); + break; + } + + GPUTexture *tex = GPU_texture_create_1D(TFUNC_WIDTH, data, NULL); + + MEM_freeN(data); return tex; } +static GPUTexture *create_field_texture(SmokeDomainSettings *sds) +{ + float *field = NULL; + + switch (sds->coba_field) { +#ifdef WITH_SMOKE + case FLUID_FIELD_DENSITY: field = smoke_get_density(sds->fluid); break; + case FLUID_FIELD_HEAT: field = smoke_get_heat(sds->fluid); break; + case FLUID_FIELD_FUEL: field = smoke_get_fuel(sds->fluid); break; + case FLUID_FIELD_REACT: field = smoke_get_react(sds->fluid); break; + case FLUID_FIELD_FLAME: field = smoke_get_flame(sds->fluid); break; + case FLUID_FIELD_VELOCITY_X: field = smoke_get_velocity_x(sds->fluid); break; + case FLUID_FIELD_VELOCITY_Y: field = smoke_get_velocity_y(sds->fluid); break; + case FLUID_FIELD_VELOCITY_Z: field = smoke_get_velocity_z(sds->fluid); break; + case FLUID_FIELD_COLOR_R: field = smoke_get_color_r(sds->fluid); break; + case FLUID_FIELD_COLOR_G: field = smoke_get_color_g(sds->fluid); break; + case FLUID_FIELD_COLOR_B: field = smoke_get_color_b(sds->fluid); break; + case FLUID_FIELD_FORCE_X: field = smoke_get_force_x(sds->fluid); break; + case FLUID_FIELD_FORCE_Y: field = smoke_get_force_y(sds->fluid); break; + case FLUID_FIELD_FORCE_Z: field = smoke_get_force_z(sds->fluid); break; +#endif + default: return NULL; + } + + return GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, field); +} + typedef struct VolumeSlicer { float size[3]; float min[3]; @@ -347,6 +403,7 @@ static int create_view_aligned_slices(VolumeSlicer *slicer, } static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture *tex_spec, + GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire, const float min[3], const float ob_sizei[3], const float invsize[3]) { @@ -359,6 +416,8 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture int densityscale_location; int spec_location, flame_location; int shadow_location, actcol_location; + int tfunc_location = 0; + int coba_location = 0; if (use_fire) { spec_location = GPU_shader_get_uniform(shader, "spectrum_texture"); @@ -370,6 +429,11 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture 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"); + + if (sds->use_coba) { + tfunc_location = GPU_shader_get_uniform(shader, "transfer_texture"); + coba_location = GPU_shader_get_uniform(shader, "color_band_texture"); + } } GPU_shader_bind(shader); @@ -397,6 +461,14 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture 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); + + if (sds->use_coba) { + GPU_texture_bind(tex_tfunc, 4); + GPU_shader_uniform_texture(shader, tfunc_location, tex_tfunc); + + GPU_texture_bind(tex_coba, 5); + GPU_shader_uniform_texture(shader, coba_location, tex_coba); + } } GPU_shader_uniform_vector(shader, min_location, 3, 1, min); @@ -404,7 +476,8 @@ static void bind_shader(SmokeDomainSettings *sds, GPUShader *shader, GPUTexture GPU_shader_uniform_vector(shader, invsize_location, 3, 1, invsize); } -static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool use_fire) +static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, + GPUTexture *tex_tfunc, GPUTexture *tex_coba, bool use_fire) { GPU_shader_unbind(); @@ -417,20 +490,30 @@ static void unbind_shader(SmokeDomainSettings *sds, GPUTexture *tex_spec, bool u } else { GPU_texture_unbind(sds->tex_shadow); + + if (sds->use_coba) { + GPU_texture_unbind(tex_tfunc); + GPU_texture_free(tex_tfunc); + + GPU_texture_unbind(tex_coba); + GPU_texture_free(tex_coba); + } } } 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; + GPUTexture *tex_spec = (do_fire) ? create_transfer_function(TFUNC_FLAME_SPECTRUM, NULL) : NULL; + GPUTexture *tex_tfunc = (sds->use_coba) ? create_transfer_function(TFUNC_COLOR_RAMP, sds->coba) : NULL; + GPUTexture *tex_coba = (sds->use_coba) ? create_field_texture(sds) : 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); + bind_shader(sds, shader, tex_spec, tex_tfunc, tex_coba, do_fire, slicer->min, ob_sizei, invsize); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, 0, NULL); @@ -439,7 +522,7 @@ static void draw_buffer(SmokeDomainSettings *sds, GPUShader *shader, const Volum glDisableClientState(GL_VERTEX_ARRAY); - unbind_shader(sds, tex_spec, do_fire); + unbind_shader(sds, tex_spec, tex_tfunc, tex_coba, do_fire); /* cleanup */ @@ -459,7 +542,16 @@ 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(GPU_SHADER_SMOKE); + GPUBuiltinShader builtin_shader; + + if (sds->use_coba) { + builtin_shader = GPU_SHADER_SMOKE_COBA; + } + else { + builtin_shader = GPU_SHADER_SMOKE; + } + + GPUShader *shader = GPU_shader_get_builtin_shader(builtin_shader); if (!shader) { fprintf(stderr, "Unable to create GLSL smoke shader.\n"); @@ -549,7 +641,7 @@ void draw_smoke_volume(SmokeDomainSettings *sds, Object *ob, draw_buffer(sds, shader, &slicer, ob_sizei, invsize, num_points, false); /* Draw fire separately (T47639). */ - if (use_fire) { + if (use_fire && !sds->use_coba) { glBlendFunc(GL_ONE, GL_ONE); draw_buffer(sds, fire_shader, &slicer, ob_sizei, invsize, num_points, true); } @@ -759,50 +851,3 @@ void draw_smoke_velocity(SmokeDomainSettings *domain, float viewnormal[3]) UNUSED_VARS(domain, viewnormal); #endif } - -#ifdef SMOKE_DEBUG_HEAT -void draw_smoke_heat(SmokeDomainSettings *domain, Object *ob) -{ - float x, y, z; - float x0, y0, z0; - int *base_res = domain->base_res; - int *res = domain->res; - int *res_min = domain->res_min; - int *res_max = domain->res_max; - float *heat = smoke_get_heat(domain->fluid); - - float min[3]; - float *cell_size = domain->cell_size; - float step_size = ((float)max_iii(base_res[0], base_res[1], base_res[2])) / 16.f; - float vf = domain->scale / 16.f * 2.f; /* velocity factor */ - - /* set first position so that it doesn't jump when domain moves */ - x0 = res_min[0] + fmod(-(float)domain->shift[0] + res_min[0], step_size); - y0 = res_min[1] + fmod(-(float)domain->shift[1] + res_min[1], step_size); - z0 = res_min[2] + fmod(-(float)domain->shift[2] + res_min[2], step_size); - if (x0 < res_min[0]) x0 += step_size; - if (y0 < res_min[1]) y0 += step_size; - if (z0 < res_min[2]) z0 += step_size; - add_v3_v3v3(min, domain->p0, domain->obj_shift_f); - - for (x = floor(x0); x < res_max[0]; x += step_size) - for (y = floor(y0); y < res_max[1]; y += step_size) - for (z = floor(z0); z < res_max[2]; z += step_size) { - int index = (floor(x) - res_min[0]) + (floor(y) - res_min[1]) * res[0] + (floor(z) - res_min[2]) * res[0] * res[1]; - - float pos[3] = {min[0] + ((float)x + 0.5f) * cell_size[0], min[1] + ((float)y + 0.5f) * cell_size[1], min[2] + ((float)z + 0.5f) * cell_size[2]}; - - /* draw heat as different sized points */ - if (heat[index] >= 0.01f) { - float col_gb = 1.0f - heat[index]; - CLAMP(col_gb, 0.0f, 1.0f); - glColor3f(1.0f, col_gb, col_gb); - glPointSize(24.0f * heat[index]); - - glBegin(GL_POINTS); - glVertex3f(pos[0], pos[1], pos[2]); - glEnd(); - } - } -} -#endif diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 0e2cb95dd89..b11f42bcfef 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -296,14 +296,8 @@ void draw_smoke_volume(struct SmokeDomainSettings *sds, struct Object *ob, const float min[3], const float max[3], const float viewnormal[3]); -//#define SMOKE_DEBUG_HEAT - void draw_smoke_velocity(struct SmokeDomainSettings *domain, float viewnormal[3]); -#ifdef SMOKE_DEBUG_HEAT -void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob); -#endif - /* workaround for trivial but noticeable camera bug caused by imprecision * between view border calculation in 2D/3D space, workaround for bug [#28037]. * without this define we get the old behavior which is to try and align them diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 762329ee077..5b94db6e120 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -89,6 +89,7 @@ typedef enum GPUBuiltinShader { GPU_SHADER_SEP_GAUSSIAN_BLUR = 1, GPU_SHADER_SMOKE = 2, GPU_SHADER_SMOKE_FIRE = 3, + GPU_SHADER_SMOKE_COBA = 4, } GPUBuiltinShader; GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader); diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index 5cfb323bc4b..14f2764b009 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -68,6 +68,7 @@ static struct GPUShadersGlobal { GPUShader *sep_gaussian_blur; GPUShader *smoke; GPUShader *smoke_fire; + GPUShader *smoke_coba; /* cache for shader fx. Those can exist in combinations so store them here */ GPUShader *fx_shaders[MAX_FX_SHADERS * 2]; } shaders; @@ -623,6 +624,13 @@ GPUShader *GPU_shader_get_builtin_shader(GPUBuiltinShader shader) NULL, NULL, NULL, 0, 0, 0); retval = GG.shaders.smoke_fire; break; + case GPU_SHADER_SMOKE_COBA: + if (!GG.shaders.smoke_coba) + GG.shaders.smoke_coba = GPU_shader_create( + datatoc_gpu_shader_smoke_vert_glsl, datatoc_gpu_shader_smoke_frag_glsl, + NULL, NULL, "#define USE_COBA;\n", 0, 0, 0); + retval = GG.shaders.smoke_coba; + break; } if (retval == NULL) @@ -734,6 +742,11 @@ void GPU_shader_free_builtin_shaders(void) GG.shaders.smoke_fire = NULL; } + if (GG.shaders.smoke_coba) { + GPU_shader_free(GG.shaders.smoke_coba); + GG.shaders.smoke_coba = NULL; + } + for (i = 0; i < 2 * MAX_FX_SHADERS; ++i) { if (GG.shaders.fx_shaders[i]) { GPU_shader_free(GG.shaders.fx_shaders[i]); diff --git a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl index fd790009e02..6ded453225e 100644 --- a/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_smoke_frag.glsl @@ -8,10 +8,17 @@ uniform float density_scale; uniform sampler3D soot_texture; uniform sampler3D shadow_texture; +#ifdef USE_COBA +uniform sampler1D transfer_texture; +uniform sampler3D color_band_texture; +#endif + void main() { /* compute color and density from volume texture */ vec4 soot = texture3D(soot_texture, coords); + +#ifndef USE_COBA vec3 soot_color; if (soot.a != 0) { soot_color = active_color * soot.rgb / soot.a; @@ -31,6 +38,11 @@ void main() /* premultiply alpha */ vec4 color = vec4(soot_alpha * soot_color, soot_alpha); +#else + float color_band = texture3D(color_band_texture, coords).r; + vec4 transfer_function = texture1D(transfer_texture, color_band); + vec4 color = transfer_function * density_scale; +#endif gl_FragColor = color; } diff --git a/source/blender/makesdna/DNA_smoke_types.h b/source/blender/makesdna/DNA_smoke_types.h index ba7f73c2f63..c95e0a1f54a 100644 --- a/source/blender/makesdna/DNA_smoke_types.h +++ b/source/blender/makesdna/DNA_smoke_types.h @@ -77,6 +77,23 @@ enum { VECTOR_DRAW_STREAMLINE = 1, }; +enum { + FLUID_FIELD_DENSITY = 0, + FLUID_FIELD_HEAT = 1, + FLUID_FIELD_FUEL = 2, + FLUID_FIELD_REACT = 3, + FLUID_FIELD_FLAME = 4, + FLUID_FIELD_VELOCITY_X = 5, + FLUID_FIELD_VELOCITY_Y = 6, + FLUID_FIELD_VELOCITY_Z = 7, + FLUID_FIELD_COLOR_R = 8, + FLUID_FIELD_COLOR_G = 9, + FLUID_FIELD_COLOR_B = 10, + FLUID_FIELD_FORCE_X = 11, + FLUID_FIELD_FORCE_Y = 12, + FLUID_FIELD_FORCE_Z = 13, +}; + /* cache compression */ #define SM_CACHE_LIGHT 0 #define SM_CACHE_HEAVY 1 @@ -193,9 +210,13 @@ typedef struct SmokeDomainSettings { float slice_per_voxel; float slice_depth; float display_thickness; + + struct ColorBand *coba; float vector_scale; char vector_draw_type; - char pad2[3]; + char use_coba; + char coba_field; /* simulation field used for the color mapping */ + char pad2; } SmokeDomainSettings; diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index b4ba306df3f..6db370fc152 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -30,6 +30,7 @@ #include #include "RNA_define.h" +#include "RNA_enum_types.h" #include "rna_internal.h" @@ -53,6 +54,7 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_particle.h" +#include "BKE_texture.h" #include "smoke_API.h" @@ -383,6 +385,17 @@ static void rna_SmokeFlow_uvlayer_set(PointerRNA *ptr, const char *value) rna_object_uvlayer_name_set(ptr, value, flow->uvlayer_name, sizeof(flow->uvlayer_name)); } +static void rna_Smoke_use_color_ramp_set(PointerRNA *ptr, int value) +{ + SmokeDomainSettings *sds = (SmokeDomainSettings *)ptr->data; + + sds->use_coba = value; + + if (value && sds->coba == NULL) { + sds->coba = add_colorband(false); + } +} + #else static void rna_def_smoke_domain_settings(BlenderRNA *brna) @@ -805,6 +818,41 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.0, 100.0, 0.1, 3); RNA_def_property_ui_text(prop, "Scale", "Multiplier for scaling the vectors"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + /* --------- Color mapping. --------- */ + + prop = RNA_def_property(srna, "use_color_ramp", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "use_coba", 0); + RNA_def_property_boolean_funcs(prop, NULL, "rna_Smoke_use_color_ramp_set"); + RNA_def_property_ui_text(prop, "Use Color Ramp", + "Render a simulation field while mapping its voxels values to the colors of a ramp"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + static EnumPropertyItem coba_field_items[] = { + {FLUID_FIELD_COLOR_R, "COLOR_R", 0, "Red", "Red component of the color field"}, + {FLUID_FIELD_COLOR_G, "COLOR_G", 0, "Green", "Green component of the color field"}, + {FLUID_FIELD_COLOR_B, "COLOR_B", 0, "Blue", "Blue component of the color field"}, + {FLUID_FIELD_DENSITY, "DENSITY", 0, "Density", "Quantity of soot in the fluid"}, + {FLUID_FIELD_FLAME, "FLAME", 0, "Flame", "Flame field"}, + {FLUID_FIELD_FUEL, "FUEL", 0, "Fuel", "Fuel field"}, + {FLUID_FIELD_HEAT, "HEAT", 0, "Heat", "Temperature of the fluid"}, + {FLUID_FIELD_VELOCITY_X, "VELOCITY_X", 0, "X Velocity", "X component of the velocity field"}, + {FLUID_FIELD_VELOCITY_Y, "VELOCITY_Y", 0, "Y Velocity", "Y component of the velocity field"}, + {FLUID_FIELD_VELOCITY_Z, "VELOCITY_Z", 0, "Z Velocity", "Z component of the velocity field"}, + {0, NULL, 0, NULL, NULL} + }; + + prop = RNA_def_property(srna, "coba_field", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "coba_field"); + RNA_def_property_enum_items(prop, coba_field_items); + RNA_def_property_ui_text(prop, "Field", "Simulation field to color map"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + + prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "coba"); + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Color Ramp", ""); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); } static void rna_def_smoke_flow_settings(BlenderRNA *brna) From 5050572e898993fc0ddcd01be9b728a73c53b3bc Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sun, 30 Oct 2016 13:51:03 +0100 Subject: [PATCH 071/590] Cycles: Style Fix: Light sampling threshold description --- intern/cycles/blender/addon/properties.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index ede3ece5bce..a8ab9100ded 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -269,7 +269,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): cls.light_sampling_threshold = FloatProperty( name="Light Sampling Threshold", description="Probabilistically terminate light samples when the light contribution is below this threshold (more noise but faster rendering). " - "Zero disables the test and never ignores lights.", + "Zero disables the test and never ignores lights", min=0.0, max=1.0, default=0.05, ) From 2e9dd1200f76818ee385e0c16831c5e8607ad186 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sun, 30 Oct 2016 16:25:35 +0100 Subject: [PATCH 072/590] Cycles: Fix OpenCL compilation with the new brick texture --- intern/cycles/kernel/svm/svm_brick.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/kernel/svm/svm_brick.h b/intern/cycles/kernel/svm/svm_brick.h index 47e1ba2ba6b..14245cf0522 100644 --- a/intern/cycles/kernel/svm/svm_brick.h +++ b/intern/cycles/kernel/svm/svm_brick.h @@ -112,7 +112,7 @@ ccl_device void svm_node_tex_brick(KernelGlobals *kg, ShaderData *sd, float *sta } if(stack_valid(color_offset)) - stack_store_float3(stack, color_offset, lerp(color1, mortar, f)); + stack_store_float3(stack, color_offset, color1*(1.0f-f) + mortar*f); if(stack_valid(fac_offset)) stack_store_float(stack, fac_offset, f); } From 2257e6899a738146899f7307b188560fff90644f Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 31 Oct 2016 00:08:13 +0100 Subject: [PATCH 073/590] UI: Don't show empty panel right-click menu --- source/blender/editors/interface/interface_handlers.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 863f5e3852c..0555529599c 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -6617,15 +6617,22 @@ static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2)) void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa) { bScreen *sc = CTX_wm_screen(C); + const bool has_panel_category = UI_panel_category_is_visible(ar); + const bool any_item_visible = has_panel_category; PointerRNA ptr; uiPopupMenu *pup; uiLayout *layout; + if (!any_item_visible) { + return; + } + RNA_pointer_create(&sc->id, &RNA_Panel, pa, &ptr); pup = UI_popup_menu_begin(C, IFACE_("Panel"), ICON_NONE); layout = UI_popup_menu_layout(pup); - if (UI_panel_category_is_visible(ar)) { + + if (has_panel_category) { char tmpstr[80]; BLI_snprintf(tmpstr, sizeof(tmpstr), "%s" UI_SEP_CHAR_S "%s", IFACE_("Pin"), IFACE_("Shift+Left Mouse")); uiItemR(layout, &ptr, "use_pin", 0, tmpstr, ICON_NONE); @@ -6636,7 +6643,6 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa) uiBut *but = block->buttons.last; but->flag |= UI_BUT_HAS_SEP_CHAR; } - } UI_popup_menu_end(C, pup); } From 04aa45407595a75b2f730894fb921c31261a23b1 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Mon, 31 Oct 2016 00:40:05 +0100 Subject: [PATCH 074/590] Cycles: Deduplicate AO calculation No functional changes. --- intern/cycles/kernel/kernel_bake.h | 2 +- intern/cycles/kernel/kernel_path.h | 118 +++++++++++------------------ 2 files changed, 44 insertions(+), 76 deletions(-) diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index 84575d35d7f..c32ac6ccf41 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -63,7 +63,7 @@ ccl_device_inline void compute_light_pass(KernelGlobals *kg, /* sample ambient occlusion */ if(pass_filter & BAKE_FILTER_AO) { - kernel_path_ao(kg, sd, &emission_sd, &L_sample, &state, &rng, throughput); + kernel_path_ao(kg, sd, &emission_sd, &L_sample, &state, &rng, throughput, shader_bsdf_alpha(kg, sd)); } /* sample emission */ diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 7ef79815ad5..4237fdb32ff 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -53,6 +53,47 @@ CCL_NAMESPACE_BEGIN +ccl_device_noinline void kernel_path_ao(KernelGlobals *kg, + ShaderData *sd, + ShaderData *emission_sd, + PathRadiance *L, + PathState *state, + RNG *rng, + float3 throughput, + float3 ao_alpha) +{ + /* todo: solve correlation */ + float bsdf_u, bsdf_v; + + path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); + + float ao_factor = kernel_data.background.ao_factor; + float3 ao_N; + float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N); + float3 ao_D; + float ao_pdf; + + sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf); + + if(dot(ccl_fetch(sd, Ng), ao_D) > 0.0f && ao_pdf != 0.0f) { + Ray light_ray; + float3 ao_shadow; + + light_ray.P = ray_offset(ccl_fetch(sd, P), ccl_fetch(sd, Ng)); + light_ray.D = ao_D; + light_ray.t = kernel_data.background.ao_distance; +#ifdef __OBJECT_MOTION__ + light_ray.time = ccl_fetch(sd, time); +#endif + light_ray.dP = ccl_fetch(sd, dP); + light_ray.dD = differential3_zero(); + + if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { + path_radiance_accum_ao(L, throughput, ao_alpha, ao_bsdf, ao_shadow, state->bounce); + } + } +} + ccl_device void kernel_path_indirect(KernelGlobals *kg, ShaderData *sd, ShaderData *emission_sd, @@ -305,40 +346,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #ifdef __AO__ /* ambient occlusion */ if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) { - float bsdf_u, bsdf_v; - path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); - - float ao_factor = kernel_data.background.ao_factor; - float3 ao_N; - float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N); - float3 ao_D; - float ao_pdf; - float3 ao_alpha = make_float3(0.0f, 0.0f, 0.0f); - - sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf); - - if(dot(sd->Ng, ao_D) > 0.0f && ao_pdf != 0.0f) { - Ray light_ray; - float3 ao_shadow; - - light_ray.P = ray_offset(sd->P, sd->Ng); - light_ray.D = ao_D; - light_ray.t = kernel_data.background.ao_distance; -# ifdef __OBJECT_MOTION__ - light_ray.time = sd->time; -# endif - light_ray.dP = sd->dP; - light_ray.dD = differential3_zero(); - - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) { - path_radiance_accum_ao(L, - throughput, - ao_alpha, - ao_bsdf, - ao_shadow, - state->bounce); - } - } + kernel_path_ao(kg, sd, emission_sd, L, state, rng, throughput, make_float3(0.0f, 0.0f, 0.0f)); } #endif @@ -394,46 +402,6 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, } } -ccl_device_noinline void kernel_path_ao(KernelGlobals *kg, - ShaderData *sd, - ShaderData *emission_sd, - PathRadiance *L, - PathState *state, - RNG *rng, - float3 throughput) -{ - /* todo: solve correlation */ - float bsdf_u, bsdf_v; - - path_state_rng_2D(kg, rng, state, PRNG_BSDF_U, &bsdf_u, &bsdf_v); - - float ao_factor = kernel_data.background.ao_factor; - float3 ao_N; - float3 ao_bsdf = shader_bsdf_ao(kg, sd, ao_factor, &ao_N); - float3 ao_D; - float ao_pdf; - float3 ao_alpha = shader_bsdf_alpha(kg, sd); - - sample_cos_hemisphere(ao_N, bsdf_u, bsdf_v, &ao_D, &ao_pdf); - - if(dot(ccl_fetch(sd, Ng), ao_D) > 0.0f && ao_pdf != 0.0f) { - Ray light_ray; - float3 ao_shadow; - - light_ray.P = ray_offset(ccl_fetch(sd, P), ccl_fetch(sd, Ng)); - light_ray.D = ao_D; - light_ray.t = kernel_data.background.ao_distance; -#ifdef __OBJECT_MOTION__ - light_ray.time = ccl_fetch(sd, time); -#endif - light_ray.dP = ccl_fetch(sd, dP); - light_ray.dD = differential3_zero(); - - if(!shadow_blocked(kg, emission_sd, state, &light_ray, &ao_shadow)) - path_radiance_accum_ao(L, throughput, ao_alpha, ao_bsdf, ao_shadow, state->bounce); - } -} - #ifdef __SUBSURFACE__ # ifndef __KERNEL_CUDA__ ccl_device @@ -860,7 +828,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, #ifdef __AO__ /* ambient occlusion */ if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { - kernel_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput); + kernel_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput, shader_bsdf_alpha(kg, &sd)); } #endif From 60682c37dd64b1b6061271452016fc9dabc854a6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 29 Oct 2016 22:31:01 +1100 Subject: [PATCH 075/590] BMesh: remove redundant walker member & assignment --- source/blender/bmesh/bmesh_class.h | 2 +- source/blender/bmesh/intern/bmesh_core.c | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index 72ea7bd7f5d..104df625ee6 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -245,7 +245,7 @@ typedef struct BMesh { /* ID of the shape key this bmesh came from */ int shapenr; - int walkers, totflags; + int totflags; ListBase selected; BMFace *act_face; diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index e83b752947c..28ac8e24ebb 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -295,8 +295,6 @@ static BMLoop *bm_face_boundary_add( #else f->l_first = l; #endif - - l->f = f; return l; } @@ -458,13 +456,10 @@ BMFace *BM_face_create( f = bm_face_create__internal(bm); startl = lastl = bm_face_boundary_add(bm, f, verts[0], edges[0], create_flag); - - startl->v = verts[0]; - startl->e = edges[0]; + for (i = 1; i < len; i++) { l = bm_loop_create(bm, verts[i], edges[i], f, NULL /* edges[i]->l */, create_flag); - - l->f = f; + bmesh_radial_append(edges[i], l); l->prev = lastl; From 6488ce7f33260dbc376947b194c42639bd111762 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 31 Oct 2016 22:07:23 +1100 Subject: [PATCH 076/590] BMesh: simplify vert & edge removal --- source/blender/bmesh/intern/bmesh_core.c | 30 ++++-------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 28ac8e24ebb..859ef744e2b 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -976,23 +976,8 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f) */ void BM_edge_kill(BMesh *bm, BMEdge *e) { - - if (e->l) { - BMLoop *l = e->l, *lnext, *startl = e->l; - - do { - lnext = l->radial_next; - if (lnext->f == l->f) { - BM_face_kill(bm, l->f); - break; - } - - BM_face_kill(bm, l->f); - - if (l == lnext) - break; - l = lnext; - } while (l != startl); + while (e->l) { + BM_face_kill(bm, e->l->f); } bmesh_disk_edge_remove(e, e->v1); @@ -1006,15 +991,8 @@ void BM_edge_kill(BMesh *bm, BMEdge *e) */ void BM_vert_kill(BMesh *bm, BMVert *v) { - if (v->e) { - BMEdge *e, *e_next; - - e = v->e; - while (v->e) { - e_next = bmesh_disk_edge_next(e, v); - BM_edge_kill(bm, e); - e = e_next; - } + while (v->e) { + BM_edge_kill(bm, v->e); } bm_kill_only_vert(bm, v); From aad46dd175ff1901def6086e3188dda07d6a4667 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 31 Oct 2016 22:52:06 +1100 Subject: [PATCH 077/590] BMesh: radial loop (internal API symmetry) Radial append/remove had swapped args and *slightly* different behavior. - bmesh_radial_append(edge, loop) - bmesh_radial_loop_remove(loop, edge) Match logic for append/remove, Logic for the one case where the edge needs to be left untouched has been moved to: `bmesh_radial_loop_unlink`. --- source/blender/bmesh/intern/bmesh_core.c | 38 ++++----- source/blender/bmesh/intern/bmesh_structure.c | 85 +++++++++++-------- source/blender/bmesh/intern/bmesh_structure.h | 5 +- 3 files changed, 72 insertions(+), 56 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 859ef744e2b..d2f638fa8f8 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -287,7 +287,7 @@ static BMLoop *bm_face_boundary_add( #endif BMLoop *l = bm_loop_create(bm, startv, starte, f, NULL /* starte->l */, create_flag); - bmesh_radial_append(starte, l); + bmesh_radial_loop_append(starte, l); #ifdef USE_BMESH_HOLES lst->first = lst->last = l; @@ -460,7 +460,7 @@ BMFace *BM_face_create( for (i = 1; i < len; i++) { l = bm_loop_create(bm, verts[i], edges[i], f, NULL /* edges[i]->l */, create_flag); - bmesh_radial_append(edges[i], l); + bmesh_radial_loop_append(edges[i], l); l->prev = lastl; lastl->next = l; @@ -899,7 +899,7 @@ void BM_face_kill(BMesh *bm, BMFace *f) do { l_next = l_iter->next; - bmesh_radial_loop_remove(l_iter, l_iter->e); + bmesh_radial_loop_remove(l_iter->e, l_iter); bm_kill_only_loop(bm, l_iter); } while ((l_iter = l_next) != l_first); @@ -944,7 +944,7 @@ void BM_face_kill_loose(BMesh *bm, BMFace *f) l_next = l_iter->next; e = l_iter->e; - bmesh_radial_loop_remove(l_iter, e); + bmesh_radial_loop_remove(e, l_iter); bm_kill_only_loop(bm, l_iter); if (e->l == NULL) { @@ -1050,7 +1050,7 @@ static bool bm_loop_reverse_loop( int i, j, edok; for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { - bmesh_radial_loop_remove(l_iter, (edar[i] = l_iter->e)); + bmesh_radial_loop_remove((edar[i] = l_iter->e), l_iter); } /* actually reverse the loop */ @@ -1086,7 +1086,7 @@ static bool bm_loop_reverse_loop( } /* rebuild radial */ for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) - bmesh_radial_append(l_iter->e, l_iter); + bmesh_radial_loop_append(l_iter->e, l_iter); #ifndef NDEBUG /* validate radial */ @@ -1558,8 +1558,8 @@ BMFace *bmesh_sfme( } while ((l_iter = l_iter->next) != l_first); /* link up the new loops into the new edges radial */ - bmesh_radial_append(e, l_f1); - bmesh_radial_append(e, l_f2); + bmesh_radial_loop_append(e, l_f1); + bmesh_radial_loop_append(e, l_f2); f2->len = f2len; @@ -1673,7 +1673,7 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l = l_next; l->f->len++; l_next = l_next != l_next->radial_next ? l_next->radial_next : NULL; - bmesh_radial_loop_remove(l, NULL); + bmesh_radial_loop_unlink(l); l_new = bm_loop_create(bm, NULL, NULL, l->f, l, 0); l_new->prev = l; @@ -1698,8 +1698,8 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l->radial_next = l->radial_prev = NULL; } - bmesh_radial_append(l_new->e, l_new); - bmesh_radial_append(l->e, l); + bmesh_radial_loop_append(l_new->e, l_new); + bmesh_radial_loop_append(l->e, l); } else if (BM_verts_in_edge(l_new->v, l_new->next->v, e_new)) { l_new->e = e_new; @@ -1716,8 +1716,8 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l->radial_next = l->radial_prev = NULL; } - bmesh_radial_append(l_new->e, l_new); - bmesh_radial_append(l->e, l); + bmesh_radial_loop_append(l_new->e, l_new); + bmesh_radial_loop_append(l->e, l); } } @@ -2592,8 +2592,8 @@ bool BM_edge_splice(BMesh *bm, BMEdge *e_dst, BMEdge *e_src) l = e_src->l; BLI_assert(BM_vert_in_edge(e_dst, l->v)); BLI_assert(BM_vert_in_edge(e_dst, l->next->v)); - bmesh_radial_loop_remove(l, e_src); - bmesh_radial_append(e_dst, l); + bmesh_radial_loop_remove(e_src, l); + bmesh_radial_loop_append(e_dst, l); } BLI_assert(bmesh_radial_length(e_src->l) == 0); @@ -2640,8 +2640,8 @@ void bmesh_edge_separate( } e_new = BM_edge_create(bm, e->v1, e->v2, e, BM_CREATE_NOP); - bmesh_radial_loop_remove(l_sep, e); - bmesh_radial_append(e_new, l_sep); + bmesh_radial_loop_remove(e, l_sep); + bmesh_radial_loop_append(e_new, l_sep); l_sep->e = e_new; if (copy_select) { @@ -2828,8 +2828,8 @@ BMVert *bmesh_urmv_loop_multi( do { l_next = l_iter->radial_next; if (BM_ELEM_API_FLAG_TEST(l_iter, LOOP_VISIT)) { - bmesh_radial_loop_remove(l_iter, e); - bmesh_radial_append(e_new, l_iter); + bmesh_radial_loop_remove(e, l_iter); + bmesh_radial_loop_append(e_new, l_iter); l_iter->e = e_new; } } while ((l_iter = l_next) != l_first); diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c index cb302139a4c..edde8cb5d31 100644 --- a/source/blender/bmesh/intern/bmesh_structure.c +++ b/source/blender/bmesh/intern/bmesh_structure.c @@ -143,7 +143,7 @@ void bmesh_disk_vert_replace(BMEdge *e, BMVert *v_dst, BMVert *v_src) * to store non-manifold conditions since BM does not keep track of region/shell information. * * Functions relating to this cycle: - * - #bmesh_radial_append + * - #bmesh_radial_loop_append * - #bmesh_radial_loop_remove * - #bmesh_radial_facevert_count * - #bmesh_radial_facevert_check @@ -389,6 +389,30 @@ bool bmesh_radial_validate(int radlen, BMLoop *l) return true; } +void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) +{ + if (e->l == NULL) { + e->l = l; + l->radial_next = l->radial_prev = l; + } + else { + l->radial_prev = e->l; + l->radial_next = e->l->radial_next; + + e->l->radial_next->radial_prev = l; + e->l->radial_next = l; + + e->l = l; + } + + if (UNLIKELY(l->e && l->e != e)) { + /* l is already in a radial cycle for a different edge */ + BMESH_ASSERT(0); + } + + l->e = e; +} + /** * \brief BMESH RADIAL REMOVE LOOP * @@ -397,28 +421,27 @@ bool bmesh_radial_validate(int radlen, BMLoop *l) * updated (in the case that the edge's link into the radial * cycle was the loop which is being removed from the cycle). */ -void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) +void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) { /* if e is non-NULL, l must be in the radial cycle of e */ - if (UNLIKELY(e && e != l->e)) { + if (UNLIKELY(e != l->e)) { BMESH_ASSERT(0); } if (l->radial_next != l) { - if (e && l == e->l) + if (l == e->l) { e->l = l->radial_next; + } l->radial_next->radial_prev = l->radial_prev; l->radial_prev->radial_next = l->radial_next; } else { - if (e) { - if (l == e->l) { - e->l = NULL; - } - else { - BMESH_ASSERT(0); - } + if (l == e->l) { + e->l = NULL; + } + else { + BMESH_ASSERT(0); } } @@ -428,6 +451,22 @@ void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) l->e = NULL; } +/** + * A version of #bmesh_radial_loop_remove which only performs the radial unlink, + * leaving the edge untouched. + */ +void bmesh_radial_loop_unlink(BMLoop *l) +{ + if (l->radial_next != l) { + l->radial_next->radial_prev = l->radial_prev; + l->radial_prev->radial_next = l->radial_next; + } + + /* l is no longer in a radial cycle; empty the links + * to the cycle and the link back to an edge */ + l->radial_next = l->radial_prev = NULL; + l->e = NULL; +} /** * \brief BME RADIAL FIND FIRST FACE VERT @@ -484,30 +523,6 @@ int bmesh_radial_length(const BMLoop *l) return i; } -void bmesh_radial_append(BMEdge *e, BMLoop *l) -{ - if (e->l == NULL) { - e->l = l; - l->radial_next = l->radial_prev = l; - } - else { - l->radial_prev = e->l; - l->radial_next = e->l->radial_next; - - e->l->radial_next->radial_prev = l; - e->l->radial_next = l; - - e->l = l; - } - - if (UNLIKELY(l->e && l->e != e)) { - /* l is already in a radial cycle for a different edge */ - BMESH_ASSERT(0); - } - - l->e = e; -} - /** * \brief RADIAL COUNT FACE VERT * diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h index 07f94796bb2..679e7a269b3 100644 --- a/source/blender/bmesh/intern/bmesh_structure.h +++ b/source/blender/bmesh/intern/bmesh_structure.h @@ -55,8 +55,9 @@ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WA BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* RADIAL CYCLE MANAGMENT */ -void bmesh_radial_append(BMEdge *e, BMLoop *l) ATTR_NONNULL(); -void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1); +void bmesh_radial_loop_append(BMEdge *e, BMLoop *l) ATTR_NONNULL(); +void bmesh_radial_loop_remove(BMEdge *e, BMLoop *l) ATTR_NONNULL(); +void bmesh_radial_loop_unlink(BMLoop *l) ATTR_NONNULL(); /* note: * bmesh_radial_loop_next(BMLoop *l) / prev. * just use member access l->radial_next, l->radial_prev now */ From cf8f6d1dbcfc86328d5917298e81070a826aea7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 31 Oct 2016 15:31:47 +0100 Subject: [PATCH 078/590] Added 'delete unlocked vertex groups' option. --- .../startup/bl_ui/properties_data_mesh.py | 1 + source/blender/blenkernel/BKE_object_deform.h | 2 ++ .../blender/blenkernel/intern/object_deform.c | 22 ++++++++++++++----- source/blender/editors/object/object_vgroup.c | 3 +++ 4 files changed, 23 insertions(+), 5 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py index 5416735494b..59907692fe0 100644 --- a/release/scripts/startup/bl_ui/properties_data_mesh.py +++ b/release/scripts/startup/bl_ui/properties_data_mesh.py @@ -38,6 +38,7 @@ class MESH_MT_vertex_group_specials(Menu): layout.operator("object.vertex_group_mirror", text="Mirror Vertex Group (Topology)", icon='ARROW_LEFTRIGHT').use_topology = True layout.operator("object.vertex_group_remove_from", icon='X', text="Remove from All Groups").use_all_groups = True layout.operator("object.vertex_group_remove_from", icon='X', text="Clear Active Group").use_all_verts = True + layout.operator("object.vertex_group_remove", icon='X', text="Delete All Unlocked Groups").all_unlocked = True layout.operator("object.vertex_group_remove", icon='X', text="Delete All Groups").all = True layout.separator() layout.operator("object.vertex_group_lock", icon='LOCKED', text="Lock All").action = 'LOCK' diff --git a/source/blender/blenkernel/BKE_object_deform.h b/source/blender/blenkernel/BKE_object_deform.h index a0a885c2a04..19a2220006a 100644 --- a/source/blender/blenkernel/BKE_object_deform.h +++ b/source/blender/blenkernel/BKE_object_deform.h @@ -51,9 +51,11 @@ bool BKE_object_defgroup_clear(struct Object *ob, struct bDeformGroup *dg, const bool BKE_object_defgroup_clear_all(struct Object *ob, const bool use_selection); void BKE_object_defgroup_remove(struct Object *ob, struct bDeformGroup *defgroup); +void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked); void BKE_object_defgroup_remove_all(struct Object *ob); + /* Select helpers */ enum eVGroupSelect; bool *BKE_object_defgroup_subset_from_select_type( diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index b5f63588423..b5e1ded35bb 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -408,8 +408,9 @@ void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup) /** * Remove all vgroups from object. Work in Object and Edit modes. + * When only_unlocked=true, locked vertex groups are not removed. */ -void BKE_object_defgroup_remove_all(Object *ob) +void BKE_object_defgroup_remove_all_ex(struct Object *ob, bool only_unlocked) { bDeformGroup *dg = (bDeformGroup *)ob->defbase.first; const bool edit_mode = BKE_object_is_in_editmode_vgroup(ob); @@ -418,10 +419,12 @@ void BKE_object_defgroup_remove_all(Object *ob) while (dg) { bDeformGroup *next_dg = dg->next; - if (edit_mode) - object_defgroup_remove_edit_mode(ob, dg); - else - object_defgroup_remove_object_mode(ob, dg); + if (!only_unlocked || (dg->flag & DG_LOCK_WEIGHT) == 0) { + if (edit_mode) + object_defgroup_remove_edit_mode(ob, dg); + else + object_defgroup_remove_object_mode(ob, dg); + } dg = next_dg; } @@ -445,6 +448,15 @@ void BKE_object_defgroup_remove_all(Object *ob) } } +/** + * Remove all vgroups from object. Work in Object and Edit modes. + */ +void BKE_object_defgroup_remove_all(struct Object *ob) +{ + BKE_object_defgroup_remove_all_ex(ob, false); +} + + /** * Get MDeformVert vgroup data from given object. Should only be used in Object mode. * diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index bd016b7fcfb..82da6f58912 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -2604,6 +2604,8 @@ static int vertex_group_remove_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "all")) BKE_object_defgroup_remove_all(ob); + else if (RNA_boolean_get(op->ptr, "all_unlocked")) + BKE_object_defgroup_remove_all_ex(ob, true); else vgroup_delete_active(ob); @@ -2633,6 +2635,7 @@ void OBJECT_OT_vertex_group_remove(wmOperatorType *ot) /* properties */ RNA_def_boolean(ot->srna, "all", 0, "All", "Remove all vertex groups"); + RNA_def_boolean(ot->srna, "all_unlocked", 0, "All Unlocked", "Remove all unlocked vertex groups"); } static int vertex_group_assign_exec(bContext *C, wmOperator *UNUSED(op)) From bf1e9bc613377a4a4d5dcf9f50e757a4feb0928f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 1 Nov 2016 11:29:33 +0100 Subject: [PATCH 079/590] Ceres: Update to the latest actual version Brings all the fixes and improvements done in upstream within the last 13 months. --- extern/ceres/CMakeLists.txt | 5 + extern/ceres/ChangeLog | 1035 ++++++------- extern/ceres/bundle.sh | 21 - extern/ceres/files.txt | 5 + .../include/ceres/cost_function_to_functor.h | 3 +- extern/ceres/include/ceres/covariance.h | 56 + .../dynamic_numeric_diff_cost_function.h | 22 +- extern/ceres/include/ceres/gradient_checker.h | 237 +-- extern/ceres/include/ceres/internal/port.h | 22 +- .../ceres/include/ceres/iteration_callback.h | 6 +- extern/ceres/include/ceres/jet.h | 106 +- .../include/ceres/local_parameterization.h | 22 + .../ceres/numeric_diff_cost_function.h | 23 - extern/ceres/include/ceres/problem.h | 7 + extern/ceres/include/ceres/rotation.h | 3 - extern/ceres/include/ceres/solver.h | 31 +- extern/ceres/include/ceres/version.h | 2 +- .../ceres/compressed_row_jacobian_writer.cc | 22 +- extern/ceres/internal/ceres/covariance.cc | 23 + .../ceres/internal/ceres/covariance_impl.cc | 172 ++- extern/ceres/internal/ceres/covariance_impl.h | 9 + .../ceres/internal/ceres/gradient_checker.cc | 276 ++++ .../ceres/gradient_checking_cost_function.cc | 224 +-- .../ceres/gradient_checking_cost_function.h | 87 +- .../internal/ceres/gradient_problem_solver.cc | 18 +- extern/ceres/internal/ceres/is_close.cc | 59 + extern/ceres/internal/ceres/is_close.h | 51 + .../internal/ceres/line_search_minimizer.cc | 26 +- .../internal/ceres/local_parameterization.cc | 74 +- extern/ceres/internal/ceres/map_util.h | 2 +- extern/ceres/internal/ceres/parameter_block.h | 37 +- extern/ceres/internal/ceres/problem.cc | 4 + extern/ceres/internal/ceres/problem_impl.cc | 19 +- extern/ceres/internal/ceres/problem_impl.h | 2 + .../ceres/internal/ceres/reorder_program.cc | 5 + extern/ceres/internal/ceres/residual_block.h | 2 +- .../internal/ceres/schur_complement_solver.cc | 7 + extern/ceres/internal/ceres/solver.cc | 61 +- .../ceres/sparse_normal_cholesky_solver.cc | 7 + extern/ceres/internal/ceres/stringprintf.cc | 41 +- .../internal/ceres/trust_region_minimizer.cc | 1341 +++++++++-------- .../internal/ceres/trust_region_minimizer.h | 123 +- .../ceres/trust_region_step_evaluator.cc | 107 ++ .../ceres/trust_region_step_evaluator.h | 122 ++ .../internal/ceres/trust_region_strategy.h | 4 +- 45 files changed, 2804 insertions(+), 1727 deletions(-) create mode 100644 extern/ceres/internal/ceres/gradient_checker.cc create mode 100644 extern/ceres/internal/ceres/is_close.cc create mode 100644 extern/ceres/internal/ceres/is_close.h create mode 100644 extern/ceres/internal/ceres/trust_region_step_evaluator.cc create mode 100644 extern/ceres/internal/ceres/trust_region_step_evaluator.h diff --git a/extern/ceres/CMakeLists.txt b/extern/ceres/CMakeLists.txt index 2ad8c543088..a6e9cd9c356 100644 --- a/extern/ceres/CMakeLists.txt +++ b/extern/ceres/CMakeLists.txt @@ -73,10 +73,12 @@ set(SRC internal/ceres/file.cc internal/ceres/generated/partitioned_matrix_view_d_d_d.cc internal/ceres/generated/schur_eliminator_d_d_d.cc + internal/ceres/gradient_checker.cc internal/ceres/gradient_checking_cost_function.cc internal/ceres/gradient_problem.cc internal/ceres/gradient_problem_solver.cc internal/ceres/implicit_schur_complement.cc + internal/ceres/is_close.cc internal/ceres/iterative_schur_complement_solver.cc internal/ceres/lapack.cc internal/ceres/levenberg_marquardt_strategy.cc @@ -116,6 +118,7 @@ set(SRC internal/ceres/triplet_sparse_matrix.cc internal/ceres/trust_region_minimizer.cc internal/ceres/trust_region_preprocessor.cc + internal/ceres/trust_region_step_evaluator.cc internal/ceres/trust_region_strategy.cc internal/ceres/types.cc internal/ceres/wall_time.cc @@ -204,6 +207,7 @@ set(SRC internal/ceres/householder_vector.h internal/ceres/implicit_schur_complement.h internal/ceres/integral_types.h + internal/ceres/is_close.h internal/ceres/iterative_schur_complement_solver.h internal/ceres/lapack.h internal/ceres/levenberg_marquardt_strategy.h @@ -248,6 +252,7 @@ set(SRC internal/ceres/triplet_sparse_matrix.h internal/ceres/trust_region_minimizer.h internal/ceres/trust_region_preprocessor.h + internal/ceres/trust_region_step_evaluator.h internal/ceres/trust_region_strategy.h internal/ceres/visibility_based_preconditioner.h internal/ceres/wall_time.h diff --git a/extern/ceres/ChangeLog b/extern/ceres/ChangeLog index 0e6c195174c..ae8d42a7c95 100644 --- a/extern/ceres/ChangeLog +++ b/extern/ceres/ChangeLog @@ -1,659 +1,588 @@ -commit aef9c9563b08d5f39eee1576af133a84749d1b48 -Author: Alessandro Gentilini -Date: Tue Oct 6 20:43:45 2015 +0200 - - Add test for Bessel functions. - - Change-Id: Ief5881e8027643d7ef627e60a88fdbad17f3d884 - -commit 49c86018e00f196c4aa9bd25daccb9919917efee -Author: Alessandro Gentilini -Date: Wed Sep 23 21:59:44 2015 +0200 - - Add Bessel functions in order to use them in residual code. - - See "How can I use the Bessel function in the residual function?" at - https://groups.google.com/d/msg/ceres-solver/Vh1gpqac8v0/NIK1EiWJCAAJ - - Change-Id: I3e80d9f9d1cadaf7177076e493ff46ace5233b76 - -commit dfb201220c034fde00a242d0533bef3f73b2907d -Author: Simon Rutishauser -Date: Tue Oct 13 07:33:58 2015 +0200 - - Make miniglog threadsafe on non-windows system by using - localtime_r() instead of localtime() for time formatting - - Change-Id: Ib8006c685cd8ed4f374893bef56c4061ca2c9747 - -commit 41455566ac633e55f222bce7c4d2cb4cc33d5c72 -Author: Alex Stewart -Date: Mon Sep 28 22:43:42 2015 +0100 - - Remove link-time optimisation (LTO). - - - On GCC 4.9+ although GCC supports LTO, it requires use of the - non-default gcc-ar & gcc-ranlib. Whilst we can ensure Ceres is - compiled with these, doing so with GCC 4.9 causes multiple definition - linker errors of static ints inside Eigen when compiling the tests - and examples when they are not also built with LTO. - - On OS X (Xcode 6 & 7) after the latest update to gtest, if LTO - is used when compiling the tests (& examples), two tests fail - due to typeinfo::operator== (things are fine if only Ceres itself is - compiled with LTO). - - This patch disables LTO for all compilers. It should be revisited when - the performance is more stable across our supported compilers. - - Change-Id: I17b52957faefbdeff0aa40846dc9b342db1b02e3 - -commit 89c40005bfceadb4163bd16b7464b3c2ce740daf -Author: Alex Stewart -Date: Sun Sep 27 13:37:26 2015 +0100 - - Only use LTO when compiling Ceres itself, not tests or examples. - - - If Ceres is built as a shared library, and LTO is enabled for Ceres - and the tests, then type_info::operator==() incorrectly returns false - in gtests' CheckedDowncastToActualType() in the following tests: - -- levenberg_marquardt_strategy_test. - -- gradient_checking_cost_function_test. - on at least Xcode 6 & 7 as reported here: - https://github.com/google/googletest/issues/595. - - This does not appear to be a gtest issue, but is perhaps an LLVM bug - or an RTTI shared library issue. Either way, disabling the use of - LTO when compiling the test application resolves the issue. - - Allow LTO to be enabled for GCC, if it is supported. - - Add CMake function to allow easy appending to target properties s/t - Ceres library-specific compile flags can be iteratively constructed. - - Change-Id: I923e6aae4f7cefa098cf32b2f8fc19389e7918c9 - -commit 0794f41cca440f7f65d9a44e671f66f6e498ef7c +commit 8590e6e8e057adba4ec0083446d00268565bb444 Author: Sameer Agarwal -Date: Sat Sep 26 14:10:15 2015 -0700 +Date: Thu Oct 27 12:29:37 2016 -0700 - Documentation updates. + Remove two checks from rotation.h - 1. Fix a typo in the Trust Region algorithm. - 2. Add ARL in the list of users. - 3. Update the version history. + This allows rotation.h to remove its dependency on glog. - Change-Id: Ic286e8ef1a71af07f3890b7592dd3aed9c5f87ce + Change-Id: Ia6aede93ee51a4bd4039570dc8edd100a7045329 -commit 90e32a8dc437dfb0e6747ce15a1f3193c13b7d5b -Author: Alex Stewart -Date: Mon Sep 21 21:08:25 2015 +0100 +commit e892499e8d8977b9178a760348bdd201ec5f3489 +Author: Je Hyeong Hong +Date: Tue Oct 18 22:49:11 2016 +0100 - Use old minimum iOS version flags on Xcode < 7.0. + Relax the tolerance in QuaternionParameterizationTestHelper. - - The newer style, which are more specific and match the SDK names - are not available on Xcode < 7.0. + This commit relaxes the tolerance value for comparing between the actual + local matrix and the expected local matrix. Without this fix, + EigenQuaternionParameterization.ZeroTest could fail as the difference + exactly matches the value of std::numeric_limits::epsilon(). - Change-Id: I2f07a0365183d2781157cdb05fd49b30ae001ac5 + Change-Id: Ic4d3f26c0acdf5f16fead80dfdc53df9e7dabbf9 -commit 26cd5326a1fb99ae02c667eab9942e1308046984 -Author: Alex Stewart -Date: Mon Sep 21 10:16:01 2015 +0100 - - Add gtest-specific flags when building/using as a shared library. - - - Currently these flags are only used to define the relevant DLL export - prefix for Windows. - - Change-Id: I0c05207b512cb4a985390aefc779b91febdabb38 - -commit c4c79472112a49bc1340da0074af2d15b1c89749 -Author: Alex Stewart -Date: Sun Sep 20 18:26:59 2015 +0100 - - Clean up iOS.cmake to use xcrun/xcodebuild & libtool. - - - Substantial cleanup of iOS.cmake to use xcrun & xcodebuild to - determine the SDK & tool paths. - - Use libtool -static to link libraries instead of ar + ranlib, which - is not compatible with Xcode 7+, this change should be backwards - compatible to at least Xcode 6. - - Force locations of unordered_map & shared_ptr on iOS to work around - check_cxx_source_compiles() running in a forked CMake instance without - access to the variables (IOS_PLATFORM) defined by the user. - - Minor CMake style updates. - - Change-Id: I5f83a60607db34d461ebe85f9dce861f53d98277 - -commit 155765bbb358f1d19f072a4b54825faf1c059910 +commit 7ed9e2fb7f1dff264c5e4fbaa89ee1c4c99df269 Author: Sameer Agarwal -Date: Wed Sep 16 06:56:08 2015 -0700 +Date: Wed Oct 19 04:45:23 2016 -0700 - Import the latest version of gtest and gmock. + Occured -> Occurred. - Change-Id: I4b686c44bba823cab1dae40efa99e31340d2b52a - -commit 0c4647b8f1496c97c6b9376d9c49ddc204aa08dd -Author: Alex Stewart -Date: Wed Sep 16 20:01:11 2015 +0100 - - Remove FAQ about increasing inlining threshold for Clang. + Thanks to Phillip Huebner for reporting this. - - Changing the inlining threshold for Clang as described has a minimal - effect on user performance. - - The problem that originally prompted the belief that it did was - due to an erroneous CXX flag configuration (in user code). - - Change-Id: I03017241c0f87b8dcefb8c984ec3b192afd97fc2 + Change-Id: I9cddfbb373aeb496961d08e434fe661bff4abd29 -commit f4b768b69afcf282568f9ab3a3f0eb8078607468 +commit b82f97279682962d8c8ae1b6d9e801ba072a0ab1 +Author: Je Hyeong Hong +Date: Tue Oct 18 21:18:32 2016 +0100 + + Fix a test error in autodiff_test.cc. + + Previously, the test for the projective camera model would fail as no + tolerance is set in line 144. To resolve this, this commit changes + assert_equal to assert_near. + + Change-Id: I6cd3379083b1a10c7cd0a9cc83fd6962bb993cc9 + +commit 5690b447de5beed6bdda99b7f30f372283c2fb1a Author: Sameer Agarwal -Date: Mon Sep 14 13:53:24 2015 -0700 +Date: Thu Oct 13 09:52:02 2016 -0700 - Lint changes from William Rucklidge + Fix documentation source for templated functions in rotation.h - Change-Id: I0dac2549a8fa2bfd12f745a8d8a0db623b7ec1ac + Change-Id: Ic1b2e6f0e6eb9914f419fd0bb5af77b66252e57c -commit 5f2f05c726443e35767d677daba6d25dbc2d7ff8 +commit 2f8f98f7e8940e465de126fb51282396f42bea20 Author: Sameer Agarwal -Date: Fri Sep 11 22:19:38 2015 -0700 +Date: Thu Oct 13 09:35:18 2016 -0700 - Refactor system_test + Prepare for 1.12.0RC1 - 1. Move common test infrastructure into test_util. - 2. system_test now only contains powells function. - 3. Add bundle_adjustment_test. - - Instead of a single function which computes everything, - there is now a test for each solver configuration which - uses the reference solution computed by the fixture. - - Change-Id: I16a9a9a83a845a7aaf28762bcecf1a8ff5aee805 + Change-Id: I23eaf0b46117a01440143001b74dacfa5e57cbf0 -commit 1936d47e213142b8bf29d3f548905116092b093d -Author: Alex Stewart -Date: Tue Sep 8 23:27:42 2015 +0100 +commit 55c12d2e9569fe4aeac3ba688ac36810935a37ba +Author: Damon Kohler +Date: Wed Oct 5 16:30:31 2016 +0200 - Revert increased inline threshold (iff Clang) to exported Ceres target. + Adds package.xml to support Catkin. - - Increasing the inline threshold results in very variable performance - improvements, and could potentially confuse users if they are trying - to set the inline threshold themselves. - - As such, we no longer export our inline threshold configuration for - Clang, but instead document how to change it in the FAQs. - - Change-Id: I88e2e0001e4586ba2718535845ed1e4b1a5b72bc + Change-Id: I8ad4d36a8b036417604a54644e0bb70dd1615feb -commit a66d89dcda47cefda83758bfb9e7374bec4ce866 +commit 0bcce6565202f5476e40f12afc0a99eb44bd9dfb Author: Sameer Agarwal -Date: Sat Sep 5 16:50:20 2015 -0700 +Date: Mon Oct 10 23:30:42 2016 -0700 - Get ready for 1.11.0RC1 + Fix tabs in Android.mk - Update version numbers. - Drop CERES_VERSION_ABI macro. - - Change-Id: Ib3eadabb318afe206bb196a5221b195d26cbeaa0 + Change-Id: Ie5ab9a8ba2b727721565e1ded242609b6df5f8f5 -commit 1ac3dd223c179fbadaed568ac532af4139c75d84 +commit e6ffe2667170d2fc435443685c0163396fc52d7b Author: Sameer Agarwal -Date: Sat Sep 5 15:30:01 2015 -0700 - - Fix a bug in CompressedRowSparseMatrix::AppendRows - - The test for CompressedRowSparseMatrix::AppendRows tries to add - a matrix of size zero, which results in an invalid pointer deferencing - even though that pointer is never written to. - - Change-Id: I97dba37082bd5dad242ae1af0447a9178cd92027 - -commit 67622b080c8d37b5e932120a53d4ce76b80543e5 -Author: Sameer Agarwal -Date: Sat Sep 5 13:18:38 2015 -0700 - - Fix a pointer access bug in Ridders' algorithm. - - A pointer to an Eigen matrix was being used as an array. - - Change-Id: Ifaea14fa3416eda5953de49afb78dc5a6ea816eb - -commit 5742b7d0f14d2d170054623ccfee09ea214b8ed9 -Author: Sameer Agarwal -Date: Wed Aug 26 09:24:33 2015 -0700 - - Improve performance of SPARSE_NORMAL_CHOLESKY + dynamic_sparsity - - The outer product computation logic in SparseNormalCholeskySolver - does not work well with dynamic sparsity. The overhead of computing - the sparsity pattern of the normal equations is only amortized if - the sparsity is constant. If the sparsity can change from call to call - SparseNormalCholeskySolver will actually be more expensive. - - For Eigen and for CXSparse we now explicitly compute the normal - equations using their respective matrix-matrix product routines and solve. - Change-Id: Ifbd8ed78987cdf71640e66ed69500442526a23d4 - -commit d0b6cf657d6ef0dd739e958af9a5768f2eecfd35 -Author: Keir Mierle -Date: Fri Sep 4 18:43:41 2015 -0700 - - Fix incorrect detect structure test - - Change-Id: I7062f3639147c40b57947790d3b18331a39a366b - -commit 0e8264cc47661651a11e2dd8570c210082963545 -Author: Alex Stewart -Date: Sat Aug 22 16:23:05 2015 +0100 - - Add increased inline threshold (iff Clang) to exported Ceres target. - - - When compiled with Clang, Ceres and all of the examples are compiled - with an increased inlining-threshold, as the default value can result - in poor Eigen performance. - - Previously, client code using Ceres would typically not use an - increased inlining-threshold (unless the user has specifically added - it themselves). However, increasing the inlining threshold can result - in significant performance improvements in auto-diffed CostFunctions. - - This patch adds the inlining-threshold flags to the interface flags - for the Ceres CMake target s/t any client code using Ceres (via - CMake), and compiled with Clang, will now be compiled with the same - increased inlining threshold as used by Ceres itself. - - Change-Id: I31e8f1abfda140d22e85bb48aa57f028a68a415e - -commit a1b3fce9e0a4141b973f6b4dd9b08c4c13052d52 -Author: Alex Stewart -Date: Mon Aug 31 14:14:56 2015 +0100 - - Add optional export of Ceres build directory to new features list. - - Change-Id: I6f1e42b41957ae9cc98fd9dcd1969ef64c4cd96f - -commit e46777d8df068866ef80902401a03e29348d11ae -Author: Alex Stewart -Date: Mon Aug 31 12:41:54 2015 +0100 - - Credit reporters of buildsystem bugs in version history. - - Change-Id: I16fe7973534cd556d97215e84268ae0b8ec4e11a - -commit 01548282cb620e5e3ac79a63a391cd0afd5433e4 -Author: Sameer Agarwal -Date: Sun Aug 30 22:29:27 2015 -0700 +Date: Mon Oct 10 22:47:08 2016 -0700 Update the version history. - Change-Id: I29873bed31675e0108f1a44f53f7bc68976b7f98 + Change-Id: I9a57b0541d6cebcb695ecb364a1d4ca04ea4e06c -commit 2701429f770fce69ed0c77523fa43d7bc20ac6dc +commit 0a4ccb7ee939ab35b22e26758401e039b033b176 +Author: David Gossow +Date: Wed Sep 7 21:38:12 2016 +0200 + + Relaxing Jacobian matching in Gradient Checker test. + + Any result of an arithmetic operation on floating-point matrices + should never be checked for strict equality with some expected + value, due to limited floating point precision on different machines. + This fixes some occurences of exact checks in the gradient checker + unit test that were causing problems on some platforms. + + Change-Id: I48e804c9c705dc485ce74ddfe51037d4957c8fcb + +commit ee44fc91b59584921c1d1c8db153fda6d633b092 +Author: Je Hyeong Hong +Date: Mon Oct 3 12:19:30 2016 +0100 + + Fix an Intel compiler error in covariance_impl.cc. + + Intel C compiler strictly asks for parallel loops with collapse to be + perfectly nested. Otherwise, compiling Ceres with ICC will throw an + error at line 348 of covariance_impl.cc. + + Change-Id: I1ecb68e89b7faf79e4153dfe6675c390d1780db4 + +commit 9026d69d1ce1e0bcd21debd54a38246d85c7c6e4 Author: Sameer Agarwal -Date: Sun Aug 30 21:33:57 2015 -0700 +Date: Thu Sep 22 17:20:14 2016 -0700 - Use Eigen::Dynamic instead of ceres::DYNAMIC in numeric_diff.h + Allow SubsetParameterization to hold all parameters constant - Change-Id: Iccb0284a8fb4c2160748dfae24bcd595f1d4cb5c + 1. SubsetParameterization can now be constructed such that all + parameters are constant. This is required for it be used as part + of a ProductParameterization to hold a part of parameter block + constant. For example, a parameter block consisting of a rotation + as a quaternion and a translation vector can now have a local + parameterization where the translation part is constant and the + quaternion part has a QuaternionParameterization associated with it. + + 2. The check for the tangent space of a parameterization being + positive dimensional. We were not doing this check up till now + and the user could accidentally create parameterizations like this + and create a problem for themselves. This will ensure that even + though one can construct a SubsetParameterization where all + parameters are constant, you cannot actually use it as a local + parameterization for an entire parameter block. Which is how + it was before, but the check was inside the SubsetParameterization + constructor. + + 3. Added more tests and refactored existing tests to be more + granular. + + Change-Id: Ic0184a1f30e3bd8a416b02341781a9d98e855ff7 -commit 4f049db7c2a3ee8cf9910c6eac96be6a28a5999c -Author: Tal Ben-Nun -Date: Wed May 13 15:43:51 2015 +0300 - - Adaptive numeric differentiation using Ridders' method. - - This method numerically computes function derivatives in different - scales, extrapolating between intermediate results to conserve function - evaluations. Adaptive differentiation is essential to produce accurate - results for functions with noisy derivatives. - - Full changelist: - -Created a new type of NumericDiffMethod (RIDDERS). - -Implemented EvaluateRiddersJacobianColumn in NumericDiff. - -Created unit tests with f(x) = x^2 + [random noise] and - f(x) = exp(x). - - Change-Id: I2d6e924d7ff686650272f29a8c981351e6f72091 - -commit 070bba4b43b4b7449628bf456a10452fd2b34d28 +commit a36693f83da7a3fd19dce473d060231d4cc97499 Author: Sameer Agarwal -Date: Tue Aug 25 13:37:33 2015 -0700 +Date: Sat Sep 17 16:31:41 2016 -0700 - Lint fixes from William Rucklidge + Update version history - Change-Id: I719e8852859c970091df842e59c44e02e2c65827 + Change-Id: Ib2f0138ed7a1879ca3b2173e54092f7ae8dd5c9d -commit 887a20ca7f02a1504e35f7cabbdfb2e0842a0b0b -Author: Alex Stewart -Date: Wed Aug 12 21:41:43 2015 +0100 +commit 01e23e3d33178fdd050973666505c1080cfe04c3 +Author: David Gossow +Date: Thu Sep 8 12:22:28 2016 +0200 - Build position independent code when compiling Ceres statically. + Removing duplicate include directive. - - Previously, when Ceres was built as a static library we did not - compile position independent code. This means that the resulting - static library could not be linked against shared libraries, but - could be used by executables. - - To enable the use of a static Ceres library by other shared libraries - as reported in [1], the static library must be generated from - position independent code (except on Windows, where PIC does not - apply). - - [1] https://github.com/Itseez/opencv_contrib/pull/290#issuecomment-130389471 - - Change-Id: I99388f1784ece688f91b162d009578c5c97ddaf6 + Change-Id: I729ae6501497746d1bb615cb893ad592e16ddf3f -commit 860bba588b981a5718f6b73e7e840e5b8757fe65 +commit 99b8210cee92cb972267537fb44bebf56f812d52 Author: Sameer Agarwal -Date: Tue Aug 25 09:43:21 2015 -0700 +Date: Wed Sep 7 15:31:30 2016 -0700 - Fix a bug in DetectStructure + Update Android.mk to include new files. - The logic for determing static/dynamic f-block size in - DetectStructure was broken in a corner case, where the very first - row block which was used to initialize the f_block_size contained - more than one f blocks of varying sizes. The way the if block - was structured, no iteration was performed on the remaining - f-blocks and the loop failed to detect that the f-block size - was actually changing. - - If in the remaining row blocks, there were no row blocks - with varying f-block sizes, the function will erroneously - return a static f-block size. - - Thanks to Johannes Schonberger for providing a reproduction for this - rather tricky corner case. - - Change-Id: Ib442a041d8b7efd29f9653be6a11a69d0eccd1ec + Change-Id: Id543ee7d2a65b65c868554a17f593c0a4958e873 -commit b0cbc0f0b0a22f01724b7b647a4a94db959cc4e4 -Author: Johannes Schönberger -Date: Thu Aug 20 14:21:30 2015 -0400 - - Reduce memory footprint of SubsetParameterization - - Change-Id: If113cb4696d5aef3e50eed01fba7a3d4143b7ec8 - -commit ad2a99777786101411a971e59576ca533a297013 -Author: Sergey Sharybin -Date: Sat Aug 22 11:18:45 2015 +0200 - - Fix for reoder program unit test when built without suitesparse - - This commit fixes failure of reorder_program_test when Ceres is built without - any suitesparse. - - Change-Id: Ia23ae8dfd20c482cb9cd1301f17edf9a34df3235 - -commit 4bf3868beca9c17615f72ec03730cddb3676acaa +commit 195d8d13a6a3962ac39ef7fcdcc6add0216eb8bc Author: Sameer Agarwal -Date: Sun Aug 9 15:24:45 2015 -0700 +Date: Tue Sep 6 07:12:23 2016 -0700 - Fix a bug in the Schur eliminator + Remove two DCHECKs from CubicHermiteSpline. - The schur eliminator treats rows with e blocks and row with - no e blocks separately. The template specialization logic only - applies to the rows with e blocks. + They were present as debugging checks but were causing problems + with the build on 32bit i386 due to numerical cancellation issues, + where x ~ -epsilon. - So, in cases where the rows with e-blocks have a fixed size f-block - but the rows without e-blocks have f-blocks of varying sizes, - DetectStructure will return a static f-block size, but we need to be - careful that we do not blindly use that static f-block size everywhere. + Removing these checks only changes the behaviour in Debug mode. + We are already handling such small negative numbers in production + if they occur. All that this change does is to remove the crash. - This patch fixes a bug where such care was not being taken, where - it was assumed that the static f-block size could be assumed for all - f-block sizes. + https://github.com/ceres-solver/ceres-solver/issues/212 - A new test is added, which triggers an exception in debug mode. In - release mode this error does not present itself, due to a peculiarity - of the way Eigen works. + Thanks to @NeroBurner and @debalance for reporting this. - Thanks to Werner Trobin for reporting this bug. - - Change-Id: I8ae7aabf8eed8c3f9cf74b6c74d632ba44f82581 + Change-Id: I66480e86d4fa0a4b621204f2ff44cc3ff8d01c04 -commit 1635ce726078f00264b89d7fb6e76fd1c2796e59 +commit 83041ac84f2d67c28559c67515e0e596a3f3aa20 Author: Sameer Agarwal -Date: Wed Aug 19 00:26:02 2015 -0700 +Date: Fri Sep 2 19:10:35 2016 -0700 - Fix a bug in the reordering code. + Fix some compiler warnings. - When the user provides an ordering which starts at a non-zero group id, - or has gaps in the groups, then CAMD, the algorithm used to reorder - the program can crash or return garbage results. + Reported by Richard Trieu. - The solution is to map the ordering into grouping constraints, and then - to re-number the groups to be contiguous using a call to - MapValuesToContiguousRange. This was already done for CAMD based - ordering for Schur type solvers, but was not done for SPARSE_NORMAL_CHOLESKY. - - Thanks to Bernhard Zeisl for not only reporting the bug but also - providing a reproduction. - - Change-Id: I5cfae222d701dfdb8e1bda7f0b4670a30417aa89 + Change-Id: I202b7a7df09cc19c92582d276ccf171edf88a9fb -commit 4c3f8987e7f0c51fd367cf6d43d7eb879e79589f -Author: Simon Rutishauser -Date: Thu Aug 13 11:10:44 2015 +0200 - - Add missing CERES_EXPORT to ComposedLoss - - Change-Id: Id7db388d41bf53e6e5704039040c9d2c6bf4c29c - -commit 1a740cc787b85b883a0703403a99fe49662acb79 +commit 8c4623c63a2676e79e7917bb0561f903760f19b9 Author: Sameer Agarwal -Date: Tue Aug 11 18:08:05 2015 -0700 +Date: Thu Sep 1 00:05:09 2016 -0700 - Add the option to use numeric differentiation to nist and more_garbow_hillstrom + Update ExpectArraysClose to use ExpectClose instead of EXPECT_NEAR - Change-Id: If0a5caef90b524dcf5e2567c5b681987f5459401 - -commit ea667ede5c038d6bf3d1c9ec3dbdc5072d1beec6 -Author: Alex Stewart -Date: Sun Aug 9 16:56:13 2015 +0100 - - Fix EIGENSPARSE option help s/t it displays in CMake ncurses GUI. + The documentation for ExpectArraysClose and its implementation + did not match. - - Shorten description for EIGENSPARSE to a single line, as otherwise - it is not correctly displayed in the ncurses CMake GUI. - - Made explicit in description that this results in an LGPL licensed - version of Ceres (this is also made clear in the CMake log output if - EIGENSPARSE is enabled). + This change makes the polynomial_test not fail on 64bit AMD builds. - Change-Id: I11678a9cbc7a817133c22128da01055a3cb8a26d - -commit a14ec27fb28ab2e8d7f1c9d88e41101dc6c0aab5 -Author: Richard Stebbing -Date: Fri Aug 7 08:42:03 2015 -0700 - - Fix SparseNormalCholeskySolver with dynamic sparsity. + Thanks to Phillip Huebner for reporting this. - The previous implementation incorrectly cached the outer product matrix - pattern even when `dynamic_sparsity = true`. - - Change-Id: I1e58315a9b44f2f457d07c56b203ab2668bfb8a2 + Change-Id: I503f2d3317a28d5885a34f8bdbccd49d20ae9ba2 -commit 3dd7fced44ff00197fa9fcb1f2081d12be728062 -Author: Alex Stewart -Date: Sun Aug 9 16:38:50 2015 +0100 - - Remove legacy dependency detection macros. - - - Before the new CMake buildsystem in 1.8, Ceres used non-standard - HINTS variables for dependencies. For backwards compatibility CMake - macros were added to translate these legacy variables into the new - (standard) variables. - - As it has now been multiple releases since the legacy variables - were used and they no longer appear in any of the documentation - support for them has now expired. - - Change-Id: I2cc72927ed711142ba7943df334ee008181f86a2 - -commit 8b32e258ccce1eed2a50bb002add16cad13aff1e -Author: Alex Stewart -Date: Sun Aug 9 15:42:39 2015 +0100 - - Fix failed if() condition expansion if gflags is not found. - - - If a CMake-ified version of gflags is not detected, then - gflags_LIBRARIES is not set and the TARGET condition within a - multiconditional if() statement prevents configuration. - - Change-Id: Ia92e97523d7a1478ab36539726b9540d7cfee5d0 - -commit cc8d47aabb9d63ba4588ba7295058a6191c2df83 -Author: Alex Stewart -Date: Sun Aug 9 15:18:42 2015 +0100 - - Update all CMake to lowercase function name style. - - - Updated to new CMake style where function names are all lowercase, - this will be backwards compatible as CMake function names are - case insensitive. - - Updated using Emacs' M-x unscreamify-cmake-buffer. - - Change-Id: If7219816f560270e59212813aeb021353a64a0e2 - -commit 1f106904c1f47460c35ac03258d6506bb2d60838 -Author: Alex Stewart -Date: Sun Aug 9 14:55:02 2015 +0100 - - Update minimum iOS version to 7.0 for shared_ptr/unordered_map. - - - In order to correctly detect shared_ptr (& unordered_map) - the iOS version must be >= 7.0 (Xcode 5.0+). This only affects the - SIMULATOR(64) platform builds, as the OS (device) build uses the - latest SDK which is now likely 8.0+. - - Change-Id: Iefec8f03408b8cdc7a495f442ebba081f800adb0 - -commit 16ecd40523a408e7705c9fdb0e159cef2007b8ab -Author: Alex Stewart -Date: Sat Aug 8 17:32:31 2015 +0100 - - Fix bug in gflags' <= 2.1.2 exported CMake configuration. - - - gflags <= 2.1.2 has a bug in its exported gflags-config.cmake: - https://github.com/gflags/gflags/issues/110 whereby it sets - gflags_LIBRARIES to a non-existent 'gflags' target. - - This causes linker errors if gflags is installed in a non-standard - location (as otherwise CMake resolves gflags to -lgflags which - links if gflags is installed somewhere on the current path). - - We now check for this case, and search for the correct gflags imported - target and update gflags_LIBRARIES to reference it if found, otherwise - proceed on to the original manual search to try to find gflags. - - Change-Id: Iceccc3ee53c7c2010e41cc45255f966e7b13d526 - -commit 56be8de007dfd65ed5a31c795eb4a08ad765f411 -Author: Alex Stewart -Date: Thu Jun 25 21:31:00 2015 +0100 - - Add docs for new CXX11 option & mask option for Windows. - - - The CXX11 option has no effect on Windows, as there, any new C++11 - features are enabled by default, as such to avoid confusion we only - present the option for non-Windows. - - Change-Id: I38925ae3bb8c16682d404468ba95c611a519b9b9 - -commit cf863b6415ac4dbf3626e70adeac1ac0f3d87ee5 +commit 2fd39fcecb47eebce727081c9ffb8edf86c33669 Author: Sameer Agarwal -Date: Thu Aug 6 14:52:18 2015 -0700 +Date: Thu Sep 1 16:05:06 2016 -0700 - Remove the spec file needed for generating RPMs. + FindWithDefault returns by value rather than reference. - Now that ceres is part of RawHide, there is no need to carry - this spec file with the ceres distribution. + Returning by reference leads to lifetime issues with the default + value which may go out of scope by the time it is used. - Change-Id: Icc400b9874ba05ba05b353e2658f1de94c72299e + Thanks to @Ardavel for reporting this, as this causes graph_test + to fail on VS2015x64. + + https://github.com/ceres-solver/ceres-solver/issues/216 + + Change-Id: I596481219cfbf7622d49a6511ea29193b82c8ba3 -commit 560940fa277a469c1ab34f1aa303ff1af9c3cacf +commit 716f049a7b91a8f3a4632c367d9534d1d9190a81 +Author: Mike Vitus +Date: Wed Aug 31 13:38:30 2016 -0700 + + Convert pose graph 2D example to glog and gflags. + + Change-Id: I0ed75a60718ef95199bb36f33d9eb99157d11d40 + +commit 46c5ce89dda308088a5fdc238d0c126fdd2c2b58 +Author: David Gossow +Date: Wed Aug 31 18:40:57 2016 +0200 + + Fix compiler errors on some systems + + This fixes some signed-unsigned comparisons and a missing header + include. + + Change-Id: Ieb2bf6e905faa74851bc4ac4658d2f1da24b6ecc + +commit b102d53e1dd7dab132e58411183b6fffc2090590 +Author: David Gossow +Date: Wed Aug 31 10:21:20 2016 +0200 + + Gradient checker multithreading bugfix. + + This is a follow-up on c/7470. GradientCheckingCostFunction calls + callback_->SetGradientErrorDetected() in its Evaluate method, + which will run in multiple threads simultaneously when enabling + this option in the solver. Thus, the string append operation + inside that method has to be protected by a mutex. + + Change-Id: I314ef1df2be52595370d9af05851bf6da39bb45e + +commit 79a28d1e49af53f67af7f3387d07e7c9b7339433 Author: Sameer Agarwal -Date: Sat Jul 11 22:21:31 2015 -0700 +Date: Wed Aug 31 06:47:45 2016 -0700 - A refactor of the cubic interpolation code + Rename a confusingly named member of Solver::Options - 1. Push the boundary handling logic into the underlying array - object. This has two very significant impacts: + Solver::Options::numeric_derivative_relative_step_size to + Solver::Options::gradient_check_numeric_derivative_relative_step_size - a. The interpolation code becomes extremely simple to write - and to test. - - b. The user has more flexibility in implementing how out of bounds - values are handled. We provide one default implementation. - - Change-Id: Ic2f6cf9257ce7110c62e492688e5a6c8be1e7df2 + Change-Id: Ib89ae3f87e588d4aba2a75361770d2cec26f07aa -commit dfdf19e111c2b0e6daeb6007728ec2f784106d49 +commit 358ae741c8c4545b03d95c91fa546d9a36683677 Author: Sameer Agarwal -Date: Wed Aug 5 15:20:57 2015 -0700 +Date: Wed Aug 31 06:58:41 2016 -0700 - Lint cleanup from Jim Roseborough + Note that Problem::Evaluate cannot be called from an IterationCallback - Change-Id: Id6845c85644d40e635ed196ca74fc51a387aade4 + Change-Id: Ieabdc2d40715e6b547ab22156ba32e9c8444b7ed -commit 7444f23ae245476a7ac8421cc2f88d6947fd3e5f +commit 44044e25b14d7e623baae4505a17c913bdde59f8 Author: Sameer Agarwal -Date: Mon Aug 3 12:22:44 2015 -0700 +Date: Wed Aug 31 05:50:58 2016 -0700 - Fix a typo in small_blas.h + Update the NumTraits for Jets - The reason this rather serious looking typo has not - caused any problems uptil now is because NUM_ROW_B is - computed but never actually used. + 1. Use AVX if EIGEN_VECTORIZE_AVX is defined. + 2. Make the cost of division same as the cost of multiplication. - Thanks to Werner Trobin for pointing this out. + These are updates to the original numtraits update needed for eigen 3.3 + that Shaheen Gandhi sent out. - Change-Id: Id2b4d9326ec21baec8a85423e3270aefbafb611e + Change-Id: Ic1e3ed7d05a659c7badc79a894679b2dd61c51b9 -commit 5a48b92123b30a437f031eb24b0deaadc8f60d26 +commit 4b6ad5d88e45ce8638c882d3e8f08161089b6dba +Author: Sameer Agarwal +Date: Sat Aug 27 23:21:55 2016 -0700 + + Use ProductParameterization in bundle_adjuster.cc + + Previously, when using a quaternion to parameterize the camera + orientation, the camera parameter block was split into two + parameter blocks. One for the rotation and another for the + translation and intrinsics. This was to enable the use of the + Quaternion parameterization. + + Now that we have a ProductParameterization which allows us + to compose multiple parameterizations, this is no longer needed + and we use a size 10 parameter block instead. + + This leads to a more than 2x improvements in the linear solver time. + + Change-Id: I78b8f06696f81fee54cfe1a4ae193ee8a5f8e920 + +commit bfc916cf1cf753b85c1e2ac037e2019ee891f6f9 +Author: Shaheen Gandhi +Date: Thu Aug 4 12:10:14 2016 -0700 + + Allow ceres to be used with the latest version of Eigen + + Change-Id: Ief3b0f6b405484ec04ecd9ab6a1e1e5409a594c2 + +commit edbd48ab502aa418ad9700ee5c3ada5f9268b90a Author: Alex Stewart -Date: Sat Jul 4 17:59:52 2015 +0100 +Date: Sun Jul 10 14:13:51 2016 +0100 - Export Ceres build directory into local CMake package registry. + Enable support for OpenMP in Clang if detected. - - Optionally use CMake's export() functionality to export the Ceres - build directory as a package into the local CMake package registry. - - This enables the detection & use of Ceres from CMake *without* - requiring that Ceres be installed. + - Previously we disabled OpenMP if Clang was detected, as it did not + support it. However as of Clang 3.8 (and potentially Xcode 8) OpenMP + is supported. - Change-Id: Ib5a7588446f490e1b405878475b6b1dd13accd1f + Change-Id: Ia39dac9fe746f1fc6310e08553f85f3c37349707 -commit d9790e77894ea99d38137d359d6118315b2d1601 +commit f6df6c05dd83b19fa90044106ebaca40957998ae +Author: Mike Vitus +Date: Thu Aug 18 19:27:43 2016 -0700 + + Add an example for modeling and solving a 3D pose graph SLAM problem. + + Change-Id: I750ca5f20c495edfee5f60ffedccc5bd8ba2bb37 + +commit ac3b8e82175122e38bafaaa9cd419ba3cee11087 +Author: David Gossow +Date: Fri Apr 29 16:07:11 2016 +0200 + + Gradient checking cleanup and local parameterization bugfix + + Change the Ceres gradient checking API to make is useful for + unit testing, clean up code duplication and fix interaction between + gradient checking and local parameterizations. + + There were two gradient checking implementations, one being used + when using the check_gradients flag in the Solver, the other + being a standalone class. The standalone version was restricted + to cost functions with fixed parameter sizes at compile time, which + is being lifted here. This enables it to be used inside the + GradientCheckingCostFunction as well. + + In addition, this installs new hooks in the Solver to ensure + that Solve will fail if any incorrect gradients are detected. This + way, you can set the check_gradient flags to true and detect + errors in an automated way, instead of just printing error information + to the log. The error log is now also returned in the Solver summary + instead of being printed directly. The user can then decide what to + do with it. The existing hooks for user callbacks are used for + this purpose to keep the internal API changes minimal and non-invasive. + + The last and biggest change is the way the the interaction between + local parameterizations and the gradient checker works. Before, + local parameterizations would be ignored by the checker. However, + if a cost function does not compute its Jacobian along the null + space of the local parameterization, this wil not have any effect + on the solver, but would result in a gradient checker error. + With this change, the Jacobians are multiplied by the Jacobians + of the respective local parameterization and thus being compared + in the tangent space only. + + The typical use case for this are quaternion parameters, where + a cost function will typically assume that the quaternion is + always normalized, skipping the correct computation of the Jacobian + along the normal to save computation cost. + + Change-Id: I5e1bb97b8a899436cea25101efe5011b0bb13282 + +commit d4264ec10d9a270b53b5db86c0245ae8cbd2cf18 +Author: Mike Vitus +Date: Wed Aug 17 13:39:05 2016 -0700 + + Add a quaternion local parameterization for Eigen's quaternion element convention. + + Change-Id: I7046e8b24805313c5fb6a767de581d0054fcdb83 + +commit fd7cab65ef30fbc33612220abed52dd5073413c4 +Author: Mike Vitus +Date: Wed Aug 10 09:29:12 2016 -0700 + + Fix typos in the pose graph 2D example. + + Change-Id: Ie024ff6b6cab9f2e8011d21121a91931bd987bd1 + +commit 375dc348745081f89693607142d8b6744a7fb6b4 +Author: Mike Vitus +Date: Wed Aug 3 18:51:16 2016 -0700 + + Remove duplicate entry for the NIST example in the docs. + + Change-Id: Ic4e8f9b68b77b5235b5c96fe588cc56866dab759 + +commit f554681bf22d769abc12dd6d346ef65f9bb22431 +Author: Mike Vitus +Date: Mon Jul 25 18:30:48 2016 -0700 + + Add an example for modeling and solving a 2D pose graph SLAM problem. + + Change-Id: Ia89b12af7afa33e7b1b9a68d69cf2a0b53416737 + +commit e1bcc6e0f51512f43aa7bfb7b0d62f7ac1d0cd4b Author: Sameer Agarwal -Date: Sun Jul 12 19:39:47 2015 -0700 +Date: Wed May 18 07:52:48 2016 -0700 - Add ProductParameterization + Add additional logging for analyzing orderings - Often a parameter block is the Cartesian product of a number of - manifolds. For example, a rigid transformation SE(3) = SO(3) x R^3 - In such cases, where you have the local parameterization - of the individual manifolds available, - ProductParameterization can be used to construct a local - parameterization of the cartesian product. - - Change-Id: I4b5bcbd2407a38739c7725b129789db5c3d65a20 + Change-Id: Ic68d2959db35254e2895f11294fb25de4d4b8a81 -commit 7b4fb69dad49eaefb5d2d47ef0d76f48ad7fef73 +commit 16980b4fec846f86910c18772b8145bcb55f4728 +Author: Mike Vitus +Date: Fri Jul 15 13:37:49 2016 -0700 + + Delete the remove_definitons command from sampled_functions + CMakeLists.txt because it will be inherited from the top level examples + CMakeLists.txt. + + Change-Id: I25593587df0ae84fd8ddddc589bc2a13f3777427 + +commit a04490be97800e78e59db5eb67fa46226738ffba +Author: Mike Vitus +Date: Thu Jul 14 10:10:13 2016 -0700 + + Add readme for the sampled_function example. + + Change-Id: I9468b6a7b9f2ffdd2bf9f0dd1f4e1d5f894e540c + +commit ff11d0e63d4678188e8cabd40a532ba06912fe5a Author: Alex Stewart -Date: Sun Jun 28 21:43:46 2015 +0100 +Date: Wed Jun 29 09:31:45 2016 +0100 - Cleanup FindGflags & use installed gflags CMake config if present. + Use _j[0,1,n]() Bessel functions on MSVC to avoid deprecation errors. - - Split out gflags namespace detection methods: - check_cxx_source_compiles() & regex, into separate functions. - - Use installed/exported gflags CMake configuration (present for - versions >= 2.1) if available, unless user expresses a preference not - to, or specifies search directories, in which case fall back to manual - search for components. - -- Prefer installed gflags CMake configurations over exported gflags - build directories on all OSs. - - Remove custom version of check_cxx_source_compiles() that attempted - to force the build type of the test project. This only worked for - NMake on Windows, not MSVC as msbuild ignored our attempts to force - the build type. Now we always use the regex method on Windows if - we cannot find an installed gflags CMake configuration which works - even on MSVC by bypassing msbuild. - - Add default search paths for gflags on Windows. + - Microsoft deprecated the POSIX Bessel functions: j[0,1,n]() in favour + of _j[0,1,n](), it appears since at least MSVC 2005: + https://msdn.microsoft.com/en-us/library/ms235384(v=vs.100).aspx. + - As this occurs in jet.h (templated public header), although Ceres + suppresses the warning when it itself is built (to suppress a warning + about the insecurity of using std::copy), it will crop up again in + client code (without this fix) unless it is explicitly suppressed + there also. + - Raised as Issue #190: + https://github.com/ceres-solver/ceres-solver/issues/190. - Change-Id: I083b267d97a7a5838a1314f3d41a61ae48d5a2d7 + Change-Id: If7ac5dbb856748f9900be93ec0452a40c0b00524 -commit b3063c047906d4a44503dc0187fdcbbfcdda5f38 +commit 8ea86e1614cf77644ce782e43cde6565a54444f5 +Author: Nicolai Wojke +Date: Mon Apr 25 14:24:41 2016 +0200 + + Fix: Copy minimizer option 'is_silent' to LinSearchDirection::Options + + Change-Id: I23b4c3383cad30033c539ac93883d77c8dd4ba1a + +commit 080ca4c5f2ac42620971a07f06d2d13deb7befa8 +Author: Sameer Agarwal +Date: Sun Apr 24 22:46:54 2016 -0700 + + Fix typos in users.rst + + Change-Id: Ifdc67638a39403354bc9589f42a1b42cb9984dd2 + +commit 21ab397dc55335c147fdd795899b1f8981037b09 +Author: Sameer Agarwal +Date: Sun Apr 24 21:13:00 2016 -0700 + + Make some Jet comparisons exact. + + Change-Id: Ia08c72f3b8779df96f5c0d5a954b2c0a1dd3a061 + +commit ee40f954cf464087eb8943abf4d9db8917a33fbe +Author: Sameer Agarwal +Date: Sun Apr 24 07:49:55 2016 -0700 + + Add colmap to users.rst + + Change-Id: I452a8c1dc6a3bc55734b2fc3a4002ff7939ba863 + +commit 9665e099022bd06e53b0779550e9aebded7f274d +Author: Sameer Agarwal +Date: Mon Apr 18 06:00:58 2016 -0700 + + Fix step norm evaluation in LineSearchMinimizer + + TrustRegionMinimizer evaluates the size of the step + taken in the ambient space, where as the LineSearchMinimizer + was using the norm in the tangent space. This change fixes + this discrepancy. + + Change-Id: I9fef64cbb5622c9769c0413003cfb1dc6e89cfa3 + +commit 620ca9d0668cd4a00402264fddca3cf6bd2e7265 Author: Alex Stewart -Date: Wed Jul 15 20:56:56 2015 +0100 +Date: Mon Apr 18 15:14:11 2016 +0100 - Add default glog install location on Windows to search paths. + Remove use of -Werror when compiling Ceres. - Change-Id: I083d368be48986e6780c11460f5a07b2f3b6c900 + - As noted in Issue #193 (in that case for GCC 6), Ceres' use of -Werror + when compiling on *nix can prevent compilation on new compilers that + add new warnings and there is an inevitable delay between new compiler + versions and Ceres versions. + - Removing the explicit use of -Werror, and relying on indirect + verification by maintainers should fix build issues for Ceres releases + on newer compilers. + + Change-Id: I38e9ade28d4a90e53dcd918a7d470f1a1debd7b4 + +commit 0c63bd3efbf1d41151c9fab41d4b77dc64c572c8 +Author: Mike Vitus +Date: Thu Apr 14 10:25:52 2016 -0700 + + Add floor and ceil functions to the Jet implementation. + + Change-Id: I72ebfb0e9ade2964dbf3a014225ead345d5ae352 + +commit 9843f3280356c158d23c06a16085c6c5ba35e053 +Author: Alex Stewart +Date: Mon Mar 7 21:24:32 2016 +0000 + + Report Ceres compile options as components in find_package(). + + - Users can now specify particular components from Ceres, such as + SuiteSparse support) that must be present in a detected version of + Ceres in order for it to be reported as found by find_package(). + - This allows users to specify for example that they require a version + of Ceres with SuiteSparse support at configure time, rather than + finding out only at run time that Ceres was not compiled with the + options they require. + - The list of available components are built directly from the Ceres + compile options. + - The meta-module SparseLinearAlgebraLibrary is present if at least + one sparse linear algebra backend is available. + + Change-Id: I65f1ddfd7697e6dd25bb4ac7e54f5097d3ca6266 + +commit e4d4d88bbe51b9cc0f7450171511abbea0779790 +Author: Timer +Date: Fri Apr 8 15:42:18 2016 +0800 + + Fix a spelling error in nnls_modeling.rst + + Change-Id: I341d901d3df993bc5397ed15e6cb330b0c38fd72 + +commit 5512f58536e1be0d92010d8325b606e7b4733a08 +Author: Keir Mierle +Date: Thu Apr 7 12:03:16 2016 -0700 + + Only use collapse() directive with OpenMP 3.0 or higher + + Change-Id: Icba544c0494763c57eb6dc61e98379312ca15972 + +commit d61e94da5225217cab7b4f93b72f97055094681f +Author: Thomas Schneider +Date: Wed Apr 6 10:40:29 2016 +0200 + + Add IsParameterBlockConstant to the ceres::Problem class. + + Change-Id: I7d0e828e81324443209c17fa54dd1d37605e5bfe + +commit 77d94b34741574e958a417561702d6093fba87fb +Author: Alex Stewart +Date: Sun Feb 14 16:54:03 2016 +0000 + + Fix install path for CeresConfig.cmake to be architecture-aware. + + - Previously we were auto-detecting a "64" suffix for the install path + for the Ceres library on non-Debian/Arch Linux distributions, but + we were installing CeresConfig.cmake to an architecture independent + location. + - We now install CeresConfig.cmake to lib${LIB_SUFFIX}/cmake/Ceres. + - Also make LIB_SUFFIX visible to the user in the CMake GUI s/t they can + easily override the auto-detected value if desired. + - Reported by jpgr87@gmail.com as Issue #194. + + Change-Id: If126260d7af685779487c01220ae178ac31f7aea diff --git a/extern/ceres/bundle.sh b/extern/ceres/bundle.sh index 0eaf00f3989..a4f703ac33d 100755 --- a/extern/ceres/bundle.sh +++ b/extern/ceres/bundle.sh @@ -173,26 +173,5 @@ if(WITH_OPENMP) ) endif() -TEST_UNORDERED_MAP_SUPPORT() -if(HAVE_STD_UNORDERED_MAP_HEADER) - if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE) - add_definitions(-DCERES_STD_UNORDERED_MAP) - else() - if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE) - add_definitions(-DCERES_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) - else() - add_definitions(-DCERES_NO_UNORDERED_MAP) - message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)") - endif() - endif() -else() - if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE) - add_definitions(-DCERES_TR1_UNORDERED_MAP) - else() - add_definitions(-DCERES_NO_UNORDERED_MAP) - message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)") - endif() -endif() - blender_add_lib(extern_ceres "\${SRC}" "\${INC}" "\${INC_SYS}") EOF diff --git a/extern/ceres/files.txt b/extern/ceres/files.txt index f49f1fb0ded..4d973bbcdc2 100644 --- a/extern/ceres/files.txt +++ b/extern/ceres/files.txt @@ -149,6 +149,7 @@ internal/ceres/generated/schur_eliminator_4_4_d.cc internal/ceres/generated/schur_eliminator_d_d_d.cc internal/ceres/generate_eliminator_specialization.py internal/ceres/generate_partitioned_matrix_view_specializations.py +internal/ceres/gradient_checker.cc internal/ceres/gradient_checking_cost_function.cc internal/ceres/gradient_checking_cost_function.h internal/ceres/gradient_problem.cc @@ -160,6 +161,8 @@ internal/ceres/householder_vector.h internal/ceres/implicit_schur_complement.cc internal/ceres/implicit_schur_complement.h internal/ceres/integral_types.h +internal/ceres/is_close.cc +internal/ceres/is_close.h internal/ceres/iterative_schur_complement_solver.cc internal/ceres/iterative_schur_complement_solver.h internal/ceres/lapack.cc @@ -243,6 +246,8 @@ internal/ceres/trust_region_minimizer.cc internal/ceres/trust_region_minimizer.h internal/ceres/trust_region_preprocessor.cc internal/ceres/trust_region_preprocessor.h +internal/ceres/trust_region_step_evaluator.cc +internal/ceres/trust_region_step_evaluator.h internal/ceres/trust_region_strategy.cc internal/ceres/trust_region_strategy.h internal/ceres/types.cc diff --git a/extern/ceres/include/ceres/cost_function_to_functor.h b/extern/ceres/include/ceres/cost_function_to_functor.h index 6c67ac0f937..d2dc94725e4 100644 --- a/extern/ceres/include/ceres/cost_function_to_functor.h +++ b/extern/ceres/include/ceres/cost_function_to_functor.h @@ -130,7 +130,8 @@ class CostFunctionToFunctor { const int num_parameter_blocks = (N0 > 0) + (N1 > 0) + (N2 > 0) + (N3 > 0) + (N4 > 0) + (N5 > 0) + (N6 > 0) + (N7 > 0) + (N8 > 0) + (N9 > 0); - CHECK_EQ(parameter_block_sizes.size(), num_parameter_blocks); + CHECK_EQ(static_cast(parameter_block_sizes.size()), + num_parameter_blocks); CHECK_EQ(N0, parameter_block_sizes[0]); if (parameter_block_sizes.size() > 1) CHECK_EQ(N1, parameter_block_sizes[1]); // NOLINT diff --git a/extern/ceres/include/ceres/covariance.h b/extern/ceres/include/ceres/covariance.h index dd20dc36ba1..930f96cf3ae 100644 --- a/extern/ceres/include/ceres/covariance.h +++ b/extern/ceres/include/ceres/covariance.h @@ -357,6 +357,28 @@ class CERES_EXPORT Covariance { const double*> >& covariance_blocks, Problem* problem); + // Compute a part of the covariance matrix. + // + // The vector parameter_blocks contains the parameter blocks that + // are used for computing the covariance matrix. From this vector + // all covariance pairs are generated. This allows the covariance + // estimation algorithm to only compute and store these blocks. + // + // parameter_blocks cannot contain duplicates. Bad things will + // happen if they do. + // + // Note that the list of covariance_blocks is only used to determine + // what parts of the covariance matrix are computed. The full + // Jacobian is used to do the computation, i.e. they do not have an + // impact on what part of the Jacobian is used for computation. + // + // The return value indicates the success or failure of the + // covariance computation. Please see the documentation for + // Covariance::Options for more on the conditions under which this + // function returns false. + bool Compute(const std::vector& parameter_blocks, + Problem* problem); + // Return the block of the cross-covariance matrix corresponding to // parameter_block1 and parameter_block2. // @@ -394,6 +416,40 @@ class CERES_EXPORT Covariance { const double* parameter_block2, double* covariance_block) const; + // Return the covariance matrix corresponding to all parameter_blocks. + // + // Compute must be called before calling GetCovarianceMatrix and all + // parameter_blocks must have been present in the vector + // parameter_blocks when Compute was called. Otherwise + // GetCovarianceMatrix returns false. + // + // covariance_matrix must point to a memory location that can store + // the size of the covariance matrix. The covariance matrix will be + // a square matrix whose row and column count is equal to the sum of + // the sizes of the individual parameter blocks. The covariance + // matrix will be a row-major matrix. + bool GetCovarianceMatrix(const std::vector ¶meter_blocks, + double *covariance_matrix); + + // Return the covariance matrix corresponding to parameter_blocks + // in the tangent space if a local parameterization is associated + // with one of the parameter blocks else returns the covariance + // matrix in the ambient space. + // + // Compute must be called before calling GetCovarianceMatrix and all + // parameter_blocks must have been present in the vector + // parameters_blocks when Compute was called. Otherwise + // GetCovarianceMatrix returns false. + // + // covariance_matrix must point to a memory location that can store + // the size of the covariance matrix. The covariance matrix will be + // a square matrix whose row and column count is equal to the sum of + // the sizes of the tangent spaces of the individual parameter + // blocks. The covariance matrix will be a row-major matrix. + bool GetCovarianceMatrixInTangentSpace( + const std::vector& parameter_blocks, + double* covariance_matrix); + private: internal::scoped_ptr impl_; }; diff --git a/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h b/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h index c852d57a3fc..5770946a115 100644 --- a/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h +++ b/extern/ceres/include/ceres/dynamic_numeric_diff_cost_function.h @@ -85,22 +85,6 @@ class DynamicNumericDiffCostFunction : public CostFunction { options_(options) { } - // Deprecated. New users should avoid using this constructor. Instead, use the - // constructor with NumericDiffOptions. - DynamicNumericDiffCostFunction( - const CostFunctor* functor, - Ownership ownership, - double relative_step_size) - : functor_(functor), - ownership_(ownership), - options_() { - LOG(WARNING) << "This constructor is deprecated and will be removed in " - "a future version. Please use the NumericDiffOptions " - "constructor instead."; - - options_.relative_step_size = relative_step_size; - } - virtual ~DynamicNumericDiffCostFunction() { if (ownership_ != TAKE_OWNERSHIP) { functor_.release(); @@ -138,19 +122,19 @@ class DynamicNumericDiffCostFunction : public CostFunction { std::vector parameters_copy(parameters_size); std::vector parameters_references_copy(block_sizes.size()); parameters_references_copy[0] = ¶meters_copy[0]; - for (int block = 1; block < block_sizes.size(); ++block) { + for (size_t block = 1; block < block_sizes.size(); ++block) { parameters_references_copy[block] = parameters_references_copy[block - 1] + block_sizes[block - 1]; } // Copy the parameters into the local temp space. - for (int block = 0; block < block_sizes.size(); ++block) { + for (size_t block = 0; block < block_sizes.size(); ++block) { memcpy(parameters_references_copy[block], parameters[block], block_sizes[block] * sizeof(*parameters[block])); } - for (int block = 0; block < block_sizes.size(); ++block) { + for (size_t block = 0; block < block_sizes.size(); ++block) { if (jacobians[block] != NULL && !NumericDiff -#include #include +#include +#include "ceres/cost_function.h" +#include "ceres/dynamic_numeric_diff_cost_function.h" #include "ceres/internal/eigen.h" #include "ceres/internal/fixed_array.h" #include "ceres/internal/macros.h" #include "ceres/internal/scoped_ptr.h" -#include "ceres/numeric_diff_cost_function.h" +#include "ceres/local_parameterization.h" #include "glog/logging.h" namespace ceres { -// An object that exercises a cost function, to compare the answers that it -// gives with derivatives estimated using finite differencing. +// GradientChecker compares the Jacobians returned by a cost function against +// derivatives estimated using finite differencing. // -// The only likely usage of this is for testing. +// The condition enforced is that +// +// (J_actual(i, j) - J_numeric(i, j)) +// ------------------------------------ < relative_precision +// max(J_actual(i, j), J_numeric(i, j)) +// +// where J_actual(i, j) is the jacobian as computed by the supplied cost +// function (by the user) multiplied by the local parameterization Jacobian +// and J_numeric is the jacobian as computed by finite differences, multiplied +// by the local parameterization Jacobian as well. // // How to use: Fill in an array of pointers to parameter blocks for your -// CostFunction, and then call Probe(). Check that the return value is -// 'true'. See prober_test.cc for an example. -// -// This is templated similarly to NumericDiffCostFunction, as it internally -// uses that. -template +// CostFunction, and then call Probe(). Check that the return value is 'true'. class GradientChecker { public: - // Here we stash some results from the probe, for later - // inspection. - struct GradientCheckResults { - // Computed cost. - Vector cost; + // This will not take ownership of the cost function or local + // parameterizations. + // + // function: The cost function to probe. + // local_parameterization: A vector of local parameterizations for each + // parameter. May be NULL or contain NULL pointers to indicate that the + // respective parameter does not have a local parameterization. + // options: Options to use for numerical differentiation. + GradientChecker( + const CostFunction* function, + const std::vector* local_parameterizations, + const NumericDiffOptions& options); - // The sizes of these matrices are dictated by the cost function's - // parameter and residual block sizes. Each vector's length will - // term->parameter_block_sizes().size(), and each matrix is the - // Jacobian of the residual with respect to the corresponding parameter - // block. + // Contains results from a call to Probe for later inspection. + struct ProbeResults { + // The return value of the cost function. + bool return_value; + + // Computed residual vector. + Vector residuals; + + // The sizes of the Jacobians below are dictated by the cost function's + // parameter block size and residual block sizes. If a parameter block + // has a local parameterization associated with it, the size of the "local" + // Jacobian will be determined by the local parameterization dimension and + // residual block size, otherwise it will be identical to the regular + // Jacobian. // Derivatives as computed by the cost function. - std::vector term_jacobians; + std::vector jacobians; - // Derivatives as computed by finite differencing. - std::vector finite_difference_jacobians; + // Derivatives as computed by the cost function in local space. + std::vector local_jacobians; - // Infinity-norm of term_jacobians - finite_difference_jacobians. - double error_jacobians; + // Derivatives as computed by nuerical differentiation in local space. + std::vector numeric_jacobians; + + // Derivatives as computed by nuerical differentiation in local space. + std::vector local_numeric_jacobians; + + // Contains the maximum relative error found in the local Jacobians. + double maximum_relative_error; + + // If an error was detected, this will contain a detailed description of + // that error. + std::string error_log; }; - // Checks the Jacobian computed by a cost function. + // Call the cost function, compute alternative Jacobians using finite + // differencing and compare results. If local parameterizations are given, + // the Jacobians will be multiplied by the local parameterization Jacobians + // before performing the check, which effectively means that all errors along + // the null space of the local parameterization will be ignored. + // Returns false if the Jacobians don't match, the cost function return false, + // or if the cost function returns different residual when called with a + // Jacobian output argument vs. calling it without. Otherwise returns true. // - // probe_point: The parameter values at which to probe. - // error_tolerance: A threshold for the infinity-norm difference - // between the Jacobians. If the Jacobians differ by more than - // this amount, then the probe fails. - // - // term: The cost function to test. Not retained after this call returns. - // - // results: On return, the two Jacobians (and other information) - // will be stored here. May be NULL. + // parameters: The parameter values at which to probe. + // relative_precision: A threshold for the relative difference between the + // Jacobians. If the Jacobians differ by more than this amount, then the + // probe fails. + // results: On return, the Jacobians (and other information) will be stored + // here. May be NULL. // // Returns true if no problems are detected and the difference between the // Jacobians is less than error_tolerance. - static bool Probe(double const* const* probe_point, - double error_tolerance, - CostFunctionToProbe *term, - GradientCheckResults* results) { - CHECK_NOTNULL(probe_point); - CHECK_NOTNULL(term); - LOG(INFO) << "-------------------- Starting Probe() --------------------"; - - // We need a GradientCheckeresults, whether or not they supplied one. - internal::scoped_ptr owned_results; - if (results == NULL) { - owned_results.reset(new GradientCheckResults); - results = owned_results.get(); - } - - // Do a consistency check between the term and the template parameters. - CHECK_EQ(M, term->num_residuals()); - const int num_residuals = M; - const std::vector& block_sizes = term->parameter_block_sizes(); - const int num_blocks = block_sizes.size(); - - CHECK_LE(num_blocks, 5) << "Unable to test functions that take more " - << "than 5 parameter blocks"; - if (N0) { - CHECK_EQ(N0, block_sizes[0]); - CHECK_GE(num_blocks, 1); - } else { - CHECK_LT(num_blocks, 1); - } - if (N1) { - CHECK_EQ(N1, block_sizes[1]); - CHECK_GE(num_blocks, 2); - } else { - CHECK_LT(num_blocks, 2); - } - if (N2) { - CHECK_EQ(N2, block_sizes[2]); - CHECK_GE(num_blocks, 3); - } else { - CHECK_LT(num_blocks, 3); - } - if (N3) { - CHECK_EQ(N3, block_sizes[3]); - CHECK_GE(num_blocks, 4); - } else { - CHECK_LT(num_blocks, 4); - } - if (N4) { - CHECK_EQ(N4, block_sizes[4]); - CHECK_GE(num_blocks, 5); - } else { - CHECK_LT(num_blocks, 5); - } - - results->term_jacobians.clear(); - results->term_jacobians.resize(num_blocks); - results->finite_difference_jacobians.clear(); - results->finite_difference_jacobians.resize(num_blocks); - - internal::FixedArray term_jacobian_pointers(num_blocks); - internal::FixedArray - finite_difference_jacobian_pointers(num_blocks); - for (int i = 0; i < num_blocks; i++) { - results->term_jacobians[i].resize(num_residuals, block_sizes[i]); - term_jacobian_pointers[i] = results->term_jacobians[i].data(); - results->finite_difference_jacobians[i].resize( - num_residuals, block_sizes[i]); - finite_difference_jacobian_pointers[i] = - results->finite_difference_jacobians[i].data(); - } - results->cost.resize(num_residuals, 1); - - CHECK(term->Evaluate(probe_point, results->cost.data(), - term_jacobian_pointers.get())); - NumericDiffCostFunction - numeric_term(term, DO_NOT_TAKE_OWNERSHIP); - CHECK(numeric_term.Evaluate(probe_point, results->cost.data(), - finite_difference_jacobian_pointers.get())); - - results->error_jacobians = 0; - for (int i = 0; i < num_blocks; i++) { - Matrix jacobian_difference = results->term_jacobians[i] - - results->finite_difference_jacobians[i]; - results->error_jacobians = - std::max(results->error_jacobians, - jacobian_difference.lpNorm()); - } - - LOG(INFO) << "========== term-computed derivatives =========="; - for (int i = 0; i < num_blocks; i++) { - LOG(INFO) << "term_computed block " << i; - LOG(INFO) << "\n" << results->term_jacobians[i]; - } - - LOG(INFO) << "========== finite-difference derivatives =========="; - for (int i = 0; i < num_blocks; i++) { - LOG(INFO) << "finite_difference block " << i; - LOG(INFO) << "\n" << results->finite_difference_jacobians[i]; - } - - LOG(INFO) << "========== difference =========="; - for (int i = 0; i < num_blocks; i++) { - LOG(INFO) << "difference block " << i; - LOG(INFO) << (results->term_jacobians[i] - - results->finite_difference_jacobians[i]); - } - - LOG(INFO) << "||difference|| = " << results->error_jacobians; - - return results->error_jacobians < error_tolerance; - } + bool Probe(double const* const* parameters, + double relative_precision, + ProbeResults* results) const; private: CERES_DISALLOW_IMPLICIT_CONSTRUCTORS(GradientChecker); + + std::vector local_parameterizations_; + const CostFunction* function_; + internal::scoped_ptr finite_diff_cost_function_; }; } // namespace ceres diff --git a/extern/ceres/include/ceres/internal/port.h b/extern/ceres/include/ceres/internal/port.h index e57049dde4b..f4dcaee7bd8 100644 --- a/extern/ceres/include/ceres/internal/port.h +++ b/extern/ceres/include/ceres/internal/port.h @@ -33,9 +33,8 @@ // This file needs to compile as c code. #ifdef __cplusplus - +#include #include "ceres/internal/config.h" - #if defined(CERES_TR1_MEMORY_HEADER) #include #else @@ -50,6 +49,25 @@ using std::tr1::shared_ptr; using std::shared_ptr; #endif +// We allocate some Eigen objects on the stack and other places they +// might not be aligned to 16-byte boundaries. If we have C++11, we +// can specify their alignment anyway, and thus can safely enable +// vectorization on those matrices; in C++99, we are out of luck. Figure out +// what case we're in and write macros that do the right thing. +#ifdef CERES_USE_CXX11 +namespace port_constants { +static constexpr size_t kMaxAlignBytes = + // Work around a GCC 4.8 bug + // (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56019) where + // std::max_align_t is misplaced. +#if defined (__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 8 + alignof(::max_align_t); +#else + alignof(std::max_align_t); +#endif +} // namespace port_constants +#endif + } // namespace ceres #endif // __cplusplus diff --git a/extern/ceres/include/ceres/iteration_callback.h b/extern/ceres/include/ceres/iteration_callback.h index 6bab00439c5..db5d0efe53a 100644 --- a/extern/ceres/include/ceres/iteration_callback.h +++ b/extern/ceres/include/ceres/iteration_callback.h @@ -69,7 +69,7 @@ struct CERES_EXPORT IterationSummary { // Step was numerically valid, i.e., all values are finite and the // step reduces the value of the linearized model. // - // Note: step_is_valid is false when iteration = 0. + // Note: step_is_valid is always true when iteration = 0. bool step_is_valid; // Step did not reduce the value of the objective function @@ -77,7 +77,7 @@ struct CERES_EXPORT IterationSummary { // acceptance criterion used by the non-monotonic trust region // algorithm. // - // Note: step_is_nonmonotonic is false when iteration = 0; + // Note: step_is_nonmonotonic is always false when iteration = 0; bool step_is_nonmonotonic; // Whether or not the minimizer accepted this step or not. If the @@ -89,7 +89,7 @@ struct CERES_EXPORT IterationSummary { // relative decrease is not sufficient, the algorithm may accept the // step and the step is declared successful. // - // Note: step_is_successful is false when iteration = 0. + // Note: step_is_successful is always true when iteration = 0. bool step_is_successful; // Value of the objective function. diff --git a/extern/ceres/include/ceres/jet.h b/extern/ceres/include/ceres/jet.h index a21fd7adb90..a104707298c 100644 --- a/extern/ceres/include/ceres/jet.h +++ b/extern/ceres/include/ceres/jet.h @@ -164,6 +164,7 @@ #include "Eigen/Core" #include "ceres/fpclassify.h" +#include "ceres/internal/port.h" namespace ceres { @@ -227,21 +228,23 @@ struct Jet { T a; // The infinitesimal part. - // - // Note the Eigen::DontAlign bit is needed here because this object - // gets allocated on the stack and as part of other arrays and - // structs. Forcing the right alignment there is the source of much - // pain and suffering. Even if that works, passing Jets around to - // functions by value has problems because the C++ ABI does not - // guarantee alignment for function arguments. - // - // Setting the DontAlign bit prevents Eigen from using SSE for the - // various operations on Jets. This is a small performance penalty - // since the AutoDiff code will still expose much of the code as - // statically sized loops to the compiler. But given the subtle - // issues that arise due to alignment, especially when dealing with - // multiple platforms, it seems to be a trade off worth making. + + // We allocate Jets on the stack and other places they + // might not be aligned to 16-byte boundaries. If we have C++11, we + // can specify their alignment anyway, and thus can safely enable + // vectorization on those matrices; in C++99, we are out of luck. Figure out + // what case we're in and do the right thing. +#ifndef CERES_USE_CXX11 + // fall back to safe version: Eigen::Matrix v; +#else + static constexpr bool kShouldAlignMatrix = + 16 <= ::ceres::port_constants::kMaxAlignBytes; + static constexpr int kAlignHint = kShouldAlignMatrix ? + Eigen::AutoAlign : Eigen::DontAlign; + static constexpr size_t kAlignment = kShouldAlignMatrix ? 16 : 1; + alignas(kAlignment) Eigen::Matrix v; +#endif }; // Unary + @@ -388,6 +391,8 @@ inline double atan (double x) { return std::atan(x); } inline double sinh (double x) { return std::sinh(x); } inline double cosh (double x) { return std::cosh(x); } inline double tanh (double x) { return std::tanh(x); } +inline double floor (double x) { return std::floor(x); } +inline double ceil (double x) { return std::ceil(x); } inline double pow (double x, double y) { return std::pow(x, y); } inline double atan2(double y, double x) { return std::atan2(y, x); } @@ -482,10 +487,51 @@ Jet tanh(const Jet& f) { return Jet(tanh_a, tmp * f.v); } +// The floor function should be used with extreme care as this operation will +// result in a zero derivative which provides no information to the solver. +// +// floor(a + h) ~= floor(a) + 0 +template inline +Jet floor(const Jet& f) { + return Jet(floor(f.a)); +} + +// The ceil function should be used with extreme care as this operation will +// result in a zero derivative which provides no information to the solver. +// +// ceil(a + h) ~= ceil(a) + 0 +template inline +Jet ceil(const Jet& f) { + return Jet(ceil(f.a)); +} + // Bessel functions of the first kind with integer order equal to 0, 1, n. -inline double BesselJ0(double x) { return j0(x); } -inline double BesselJ1(double x) { return j1(x); } -inline double BesselJn(int n, double x) { return jn(n, x); } +// +// Microsoft has deprecated the j[0,1,n]() POSIX Bessel functions in favour of +// _j[0,1,n](). Where available on MSVC, use _j[0,1,n]() to avoid deprecated +// function errors in client code (the specific warning is suppressed when +// Ceres itself is built). +inline double BesselJ0(double x) { +#if defined(_MSC_VER) && defined(_j0) + return _j0(x); +#else + return j0(x); +#endif +} +inline double BesselJ1(double x) { +#if defined(_MSC_VER) && defined(_j1) + return _j1(x); +#else + return j1(x); +#endif +} +inline double BesselJn(int n, double x) { +#if defined(_MSC_VER) && defined(_jn) + return _jn(n, x); +#else + return jn(n, x); +#endif +} // For the formulae of the derivatives of the Bessel functions see the book: // Olver, Lozier, Boisvert, Clark, NIST Handbook of Mathematical Functions, @@ -743,7 +789,15 @@ template inline Jet ei_pow (const Jet& x, // strange compile errors. template inline std::ostream &operator<<(std::ostream &s, const Jet& z) { - return s << "[" << z.a << " ; " << z.v.transpose() << "]"; + s << "[" << z.a << " ; "; + for (int i = 0; i < N; ++i) { + s << z.v[i]; + if (i != N - 1) { + s << ", "; + } + } + s << "]"; + return s; } } // namespace ceres @@ -757,6 +811,7 @@ struct NumTraits > { typedef ceres::Jet Real; typedef ceres::Jet NonInteger; typedef ceres::Jet Nested; + typedef ceres::Jet Literal; static typename ceres::Jet dummy_precision() { return ceres::Jet(1e-12); @@ -777,6 +832,21 @@ struct NumTraits > { HasFloatingPoint = 1, RequireInitialization = 1 }; + + template + struct Div { + enum { +#if defined(EIGEN_VECTORIZE_AVX) + AVX = true, +#else + AVX = false, +#endif + + // Assuming that for Jets, division is as expensive as + // multiplication. + Cost = 3 + }; + }; }; } // namespace Eigen diff --git a/extern/ceres/include/ceres/local_parameterization.h b/extern/ceres/include/ceres/local_parameterization.h index 67633de309f..379fc684921 100644 --- a/extern/ceres/include/ceres/local_parameterization.h +++ b/extern/ceres/include/ceres/local_parameterization.h @@ -211,6 +211,28 @@ class CERES_EXPORT QuaternionParameterization : public LocalParameterization { virtual int LocalSize() const { return 3; } }; +// Implements the quaternion local parameterization for Eigen's representation +// of the quaternion. Eigen uses a different internal memory layout for the +// elements of the quaternion than what is commonly used. Specifically, Eigen +// stores the elements in memory as [x, y, z, w] where the real part is last +// whereas it is typically stored first. Note, when creating an Eigen quaternion +// through the constructor the elements are accepted in w, x, y, z order. Since +// Ceres operates on parameter blocks which are raw double pointers this +// difference is important and requires a different parameterization. +// +// Plus(x, delta) = [sin(|delta|) delta / |delta|, cos(|delta|)] * x +// with * being the quaternion multiplication operator. +class EigenQuaternionParameterization : public ceres::LocalParameterization { + public: + virtual ~EigenQuaternionParameterization() {} + virtual bool Plus(const double* x, + const double* delta, + double* x_plus_delta) const; + virtual bool ComputeJacobian(const double* x, + double* jacobian) const; + virtual int GlobalSize() const { return 4; } + virtual int LocalSize() const { return 3; } +}; // This provides a parameterization for homogeneous vectors which are commonly // used in Structure for Motion problems. One example where they are used is diff --git a/extern/ceres/include/ceres/numeric_diff_cost_function.h b/extern/ceres/include/ceres/numeric_diff_cost_function.h index fa96078df02..5dfaeab6241 100644 --- a/extern/ceres/include/ceres/numeric_diff_cost_function.h +++ b/extern/ceres/include/ceres/numeric_diff_cost_function.h @@ -206,29 +206,6 @@ class NumericDiffCostFunction } } - // Deprecated. New users should avoid using this constructor. Instead, use the - // constructor with NumericDiffOptions. - NumericDiffCostFunction(CostFunctor* functor, - Ownership ownership, - int num_residuals, - const double relative_step_size) - :functor_(functor), - ownership_(ownership), - options_() { - LOG(WARNING) << "This constructor is deprecated and will be removed in " - "a future version. Please use the NumericDiffOptions " - "constructor instead."; - - if (kNumResiduals == DYNAMIC) { - SizedCostFunction - ::set_num_residuals(num_residuals); - } - - options_.relative_step_size = relative_step_size; - } - ~NumericDiffCostFunction() { if (ownership_ != TAKE_OWNERSHIP) { functor_.release(); diff --git a/extern/ceres/include/ceres/problem.h b/extern/ceres/include/ceres/problem.h index 409274c62c2..27ed4ef15da 100644 --- a/extern/ceres/include/ceres/problem.h +++ b/extern/ceres/include/ceres/problem.h @@ -309,6 +309,9 @@ class CERES_EXPORT Problem { // Allow the indicated parameter block to vary during optimization. void SetParameterBlockVariable(double* values); + // Returns true if a parameter block is set constant, and false otherwise. + bool IsParameterBlockConstant(double* values) const; + // Set the local parameterization for one of the parameter blocks. // The local_parameterization is owned by the Problem by default. It // is acceptable to set the same parameterization for multiple @@ -461,6 +464,10 @@ class CERES_EXPORT Problem { // parameter block has a local parameterization, then it contributes // "LocalSize" entries to the gradient vector (and the number of // columns in the jacobian). + // + // Note 3: This function cannot be called while the problem is being + // solved, for example it cannot be called from an IterationCallback + // at the end of an iteration during a solve. bool Evaluate(const EvaluateOptions& options, double* cost, std::vector* residuals, diff --git a/extern/ceres/include/ceres/rotation.h b/extern/ceres/include/ceres/rotation.h index e9496d772e4..b6a06f772c4 100644 --- a/extern/ceres/include/ceres/rotation.h +++ b/extern/ceres/include/ceres/rotation.h @@ -48,7 +48,6 @@ #include #include #include -#include "glog/logging.h" namespace ceres { @@ -418,7 +417,6 @@ template inline void EulerAnglesToRotationMatrix(const T* euler, const int row_stride_parameter, T* R) { - CHECK_EQ(row_stride_parameter, 3); EulerAnglesToRotationMatrix(euler, RowMajorAdapter3x3(R)); } @@ -496,7 +494,6 @@ void QuaternionToRotation(const T q[4], QuaternionToScaledRotation(q, R); T normalizer = q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]; - CHECK_NE(normalizer, T(0)); normalizer = T(1) / normalizer; for (int i = 0; i < 3; ++i) { diff --git a/extern/ceres/include/ceres/solver.h b/extern/ceres/include/ceres/solver.h index 318cf48cb83..0d77d242dfe 100644 --- a/extern/ceres/include/ceres/solver.h +++ b/extern/ceres/include/ceres/solver.h @@ -134,7 +134,7 @@ class CERES_EXPORT Solver { trust_region_problem_dump_format_type = TEXTFILE; check_gradients = false; gradient_check_relative_precision = 1e-8; - numeric_derivative_relative_step_size = 1e-6; + gradient_check_numeric_derivative_relative_step_size = 1e-6; update_state_every_iteration = false; } @@ -701,12 +701,22 @@ class CERES_EXPORT Solver { // this number, then the jacobian for that cost term is dumped. double gradient_check_relative_precision; - // Relative shift used for taking numeric derivatives. For finite - // differencing, each dimension is evaluated at slightly shifted - // values; for the case of central difference, this is what gets - // evaluated: + // WARNING: This option only applies to the to the numeric + // differentiation used for checking the user provided derivatives + // when when Solver::Options::check_gradients is true. If you are + // using NumericDiffCostFunction and are interested in changing + // the step size for numeric differentiation in your cost + // function, please have a look at + // include/ceres/numeric_diff_options.h. // - // delta = numeric_derivative_relative_step_size; + // Relative shift used for taking numeric derivatives when + // Solver::Options::check_gradients is true. + // + // For finite differencing, each dimension is evaluated at + // slightly shifted values; for the case of central difference, + // this is what gets evaluated: + // + // delta = gradient_check_numeric_derivative_relative_step_size; // f_initial = f(x) // f_forward = f((1 + delta) * x) // f_backward = f((1 - delta) * x) @@ -723,7 +733,7 @@ class CERES_EXPORT Solver { // theory a good choice is sqrt(eps) * x, which for doubles means // about 1e-8 * x. However, I have found this number too // optimistic. This number should be exposed for users to change. - double numeric_derivative_relative_step_size; + double gradient_check_numeric_derivative_relative_step_size; // If true, the user's parameter blocks are updated at the end of // every Minimizer iteration, otherwise they are updated when the @@ -801,6 +811,13 @@ class CERES_EXPORT Solver { // Number of times inner iterations were performed. int num_inner_iteration_steps; + // Total number of iterations inside the line search algorithm + // across all invocations. We call these iterations "steps" to + // distinguish them from the outer iterations of the line search + // and trust region minimizer algorithms which call the line + // search algorithm as a subroutine. + int num_line_search_steps; + // All times reported below are wall times. // When the user calls Solve, before the actual optimization diff --git a/extern/ceres/include/ceres/version.h b/extern/ceres/include/ceres/version.h index 66505a515c9..2f1cc297a38 100644 --- a/extern/ceres/include/ceres/version.h +++ b/extern/ceres/include/ceres/version.h @@ -32,7 +32,7 @@ #define CERES_PUBLIC_VERSION_H_ #define CERES_VERSION_MAJOR 1 -#define CERES_VERSION_MINOR 11 +#define CERES_VERSION_MINOR 12 #define CERES_VERSION_REVISION 0 // Classic CPP stringifcation; the extra level of indirection allows the diff --git a/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc b/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc index 64b6ac00447..40977b74c67 100644 --- a/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc +++ b/extern/ceres/internal/ceres/compressed_row_jacobian_writer.cc @@ -46,6 +46,7 @@ namespace internal { using std::make_pair; using std::pair; using std::vector; +using std::adjacent_find; void CompressedRowJacobianWriter::PopulateJacobianRowAndColumnBlockVectors( const Program* program, CompressedRowSparseMatrix* jacobian) { @@ -140,12 +141,21 @@ SparseMatrix* CompressedRowJacobianWriter::CreateJacobian() const { // Sort the parameters by their position in the state vector. sort(parameter_indices.begin(), parameter_indices.end()); - CHECK(unique(parameter_indices.begin(), parameter_indices.end()) == - parameter_indices.end()) - << "Ceres internal error: " - << "Duplicate parameter blocks detected in a cost function. " - << "This should never happen. Please report this to " - << "the Ceres developers."; + if (adjacent_find(parameter_indices.begin(), parameter_indices.end()) != + parameter_indices.end()) { + std::string parameter_block_description; + for (int j = 0; j < num_parameter_blocks; ++j) { + ParameterBlock* parameter_block = residual_block->parameter_blocks()[j]; + parameter_block_description += + parameter_block->ToString() + "\n"; + } + LOG(FATAL) << "Ceres internal error: " + << "Duplicate parameter blocks detected in a cost function. " + << "This should never happen. Please report this to " + << "the Ceres developers.\n" + << "Residual Block: " << residual_block->ToString() << "\n" + << "Parameter Blocks: " << parameter_block_description; + } // Update the row indices. const int num_residuals = residual_block->NumResiduals(); diff --git a/extern/ceres/internal/ceres/covariance.cc b/extern/ceres/internal/ceres/covariance.cc index 690847945a9..cb280a36847 100644 --- a/extern/ceres/internal/ceres/covariance.cc +++ b/extern/ceres/internal/ceres/covariance.cc @@ -38,6 +38,7 @@ namespace ceres { +using std::make_pair; using std::pair; using std::vector; @@ -54,6 +55,12 @@ bool Covariance::Compute( return impl_->Compute(covariance_blocks, problem->problem_impl_.get()); } +bool Covariance::Compute( + const vector& parameter_blocks, + Problem* problem) { + return impl_->Compute(parameter_blocks, problem->problem_impl_.get()); +} + bool Covariance::GetCovarianceBlock(const double* parameter_block1, const double* parameter_block2, double* covariance_block) const { @@ -73,4 +80,20 @@ bool Covariance::GetCovarianceBlockInTangentSpace( covariance_block); } +bool Covariance::GetCovarianceMatrix( + const vector& parameter_blocks, + double* covariance_matrix) { + return impl_->GetCovarianceMatrixInTangentOrAmbientSpace(parameter_blocks, + true, // ambient + covariance_matrix); +} + +bool Covariance::GetCovarianceMatrixInTangentSpace( + const std::vector& parameter_blocks, + double *covariance_matrix) { + return impl_->GetCovarianceMatrixInTangentOrAmbientSpace(parameter_blocks, + false, // tangent + covariance_matrix); +} + } // namespace ceres diff --git a/extern/ceres/internal/ceres/covariance_impl.cc b/extern/ceres/internal/ceres/covariance_impl.cc index 3e8302bed55..d698f88fa9b 100644 --- a/extern/ceres/internal/ceres/covariance_impl.cc +++ b/extern/ceres/internal/ceres/covariance_impl.cc @@ -36,6 +36,8 @@ #include #include +#include +#include #include #include @@ -43,6 +45,7 @@ #include "Eigen/SparseQR" #include "Eigen/SVD" +#include "ceres/collections_port.h" #include "ceres/compressed_col_sparse_matrix_utils.h" #include "ceres/compressed_row_sparse_matrix.h" #include "ceres/covariance.h" @@ -51,6 +54,7 @@ #include "ceres/map_util.h" #include "ceres/parameter_block.h" #include "ceres/problem_impl.h" +#include "ceres/residual_block.h" #include "ceres/suitesparse.h" #include "ceres/wall_time.h" #include "glog/logging.h" @@ -61,6 +65,7 @@ namespace internal { using std::make_pair; using std::map; using std::pair; +using std::sort; using std::swap; using std::vector; @@ -86,8 +91,38 @@ CovarianceImpl::CovarianceImpl(const Covariance::Options& options) CovarianceImpl::~CovarianceImpl() { } +template void CheckForDuplicates(vector blocks) { + sort(blocks.begin(), blocks.end()); + typename vector::iterator it = + std::adjacent_find(blocks.begin(), blocks.end()); + if (it != blocks.end()) { + // In case there are duplicates, we search for their location. + map > blocks_map; + for (int i = 0; i < blocks.size(); ++i) { + blocks_map[blocks[i]].push_back(i); + } + + std::ostringstream duplicates; + while (it != blocks.end()) { + duplicates << "("; + for (int i = 0; i < blocks_map[*it].size() - 1; ++i) { + duplicates << blocks_map[*it][i] << ", "; + } + duplicates << blocks_map[*it].back() << ")"; + it = std::adjacent_find(it + 1, blocks.end()); + if (it < blocks.end()) { + duplicates << " and "; + } + } + + LOG(FATAL) << "Covariance::Compute called with duplicate blocks at " + << "indices " << duplicates.str(); + } +} + bool CovarianceImpl::Compute(const CovarianceBlocks& covariance_blocks, ProblemImpl* problem) { + CheckForDuplicates >(covariance_blocks); problem_ = problem; parameter_block_to_row_index_.clear(); covariance_matrix_.reset(NULL); @@ -97,6 +132,20 @@ bool CovarianceImpl::Compute(const CovarianceBlocks& covariance_blocks, return is_valid_; } +bool CovarianceImpl::Compute(const vector& parameter_blocks, + ProblemImpl* problem) { + CheckForDuplicates(parameter_blocks); + CovarianceBlocks covariance_blocks; + for (int i = 0; i < parameter_blocks.size(); ++i) { + for (int j = i; j < parameter_blocks.size(); ++j) { + covariance_blocks.push_back(make_pair(parameter_blocks[i], + parameter_blocks[j])); + } + } + + return Compute(covariance_blocks, problem); +} + bool CovarianceImpl::GetCovarianceBlockInTangentOrAmbientSpace( const double* original_parameter_block1, const double* original_parameter_block2, @@ -120,9 +169,17 @@ bool CovarianceImpl::GetCovarianceBlockInTangentOrAmbientSpace( ParameterBlock* block2 = FindOrDie(parameter_map, const_cast(original_parameter_block2)); + const int block1_size = block1->Size(); const int block2_size = block2->Size(); - MatrixRef(covariance_block, block1_size, block2_size).setZero(); + const int block1_local_size = block1->LocalSize(); + const int block2_local_size = block2->LocalSize(); + if (!lift_covariance_to_ambient_space) { + MatrixRef(covariance_block, block1_local_size, block2_local_size) + .setZero(); + } else { + MatrixRef(covariance_block, block1_size, block2_size).setZero(); + } return true; } @@ -240,6 +297,94 @@ bool CovarianceImpl::GetCovarianceBlockInTangentOrAmbientSpace( return true; } +bool CovarianceImpl::GetCovarianceMatrixInTangentOrAmbientSpace( + const vector& parameters, + bool lift_covariance_to_ambient_space, + double* covariance_matrix) const { + CHECK(is_computed_) + << "Covariance::GetCovarianceMatrix called before Covariance::Compute"; + CHECK(is_valid_) + << "Covariance::GetCovarianceMatrix called when Covariance::Compute " + << "returned false."; + + const ProblemImpl::ParameterMap& parameter_map = problem_->parameter_map(); + // For OpenMP compatibility we need to define these vectors in advance + const int num_parameters = parameters.size(); + vector parameter_sizes; + vector cum_parameter_size; + parameter_sizes.reserve(num_parameters); + cum_parameter_size.resize(num_parameters + 1); + cum_parameter_size[0] = 0; + for (int i = 0; i < num_parameters; ++i) { + ParameterBlock* block = + FindOrDie(parameter_map, const_cast(parameters[i])); + if (lift_covariance_to_ambient_space) { + parameter_sizes.push_back(block->Size()); + } else { + parameter_sizes.push_back(block->LocalSize()); + } + } + std::partial_sum(parameter_sizes.begin(), parameter_sizes.end(), + cum_parameter_size.begin() + 1); + const int max_covariance_block_size = + *std::max_element(parameter_sizes.begin(), parameter_sizes.end()); + const int covariance_size = cum_parameter_size.back(); + + // Assemble the blocks in the covariance matrix. + MatrixRef covariance(covariance_matrix, covariance_size, covariance_size); + const int num_threads = options_.num_threads; + scoped_array workspace( + new double[num_threads * max_covariance_block_size * + max_covariance_block_size]); + + bool success = true; + +// The collapse() directive is only supported in OpenMP 3.0 and higher. OpenMP +// 3.0 was released in May 2008 (hence the version number). +#if _OPENMP >= 200805 +# pragma omp parallel for num_threads(num_threads) schedule(dynamic) collapse(2) +#else +# pragma omp parallel for num_threads(num_threads) schedule(dynamic) +#endif + for (int i = 0; i < num_parameters; ++i) { + for (int j = 0; j < num_parameters; ++j) { + // The second loop can't start from j = i for compatibility with OpenMP + // collapse command. The conditional serves as a workaround + if (j >= i) { + int covariance_row_idx = cum_parameter_size[i]; + int covariance_col_idx = cum_parameter_size[j]; + int size_i = parameter_sizes[i]; + int size_j = parameter_sizes[j]; +#ifdef CERES_USE_OPENMP + int thread_id = omp_get_thread_num(); +#else + int thread_id = 0; +#endif + double* covariance_block = + workspace.get() + + thread_id * max_covariance_block_size * max_covariance_block_size; + if (!GetCovarianceBlockInTangentOrAmbientSpace( + parameters[i], parameters[j], lift_covariance_to_ambient_space, + covariance_block)) { + success = false; + } + + covariance.block(covariance_row_idx, covariance_col_idx, + size_i, size_j) = + MatrixRef(covariance_block, size_i, size_j); + + if (i != j) { + covariance.block(covariance_col_idx, covariance_row_idx, + size_j, size_i) = + MatrixRef(covariance_block, size_i, size_j).transpose(); + + } + } + } + } + return success; +} + // Determine the sparsity pattern of the covariance matrix based on // the block pairs requested by the user. bool CovarianceImpl::ComputeCovarianceSparsity( @@ -252,18 +397,28 @@ bool CovarianceImpl::ComputeCovarianceSparsity( vector all_parameter_blocks; problem->GetParameterBlocks(&all_parameter_blocks); const ProblemImpl::ParameterMap& parameter_map = problem->parameter_map(); + HashSet parameter_blocks_in_use; + vector residual_blocks; + problem->GetResidualBlocks(&residual_blocks); + + for (int i = 0; i < residual_blocks.size(); ++i) { + ResidualBlock* residual_block = residual_blocks[i]; + parameter_blocks_in_use.insert(residual_block->parameter_blocks(), + residual_block->parameter_blocks() + + residual_block->NumParameterBlocks()); + } + constant_parameter_blocks_.clear(); vector& active_parameter_blocks = evaluate_options_.parameter_blocks; active_parameter_blocks.clear(); for (int i = 0; i < all_parameter_blocks.size(); ++i) { double* parameter_block = all_parameter_blocks[i]; - ParameterBlock* block = FindOrDie(parameter_map, parameter_block); - if (block->IsConstant()) { - constant_parameter_blocks_.insert(parameter_block); - } else { + if (!block->IsConstant() && (parameter_blocks_in_use.count(block) > 0)) { active_parameter_blocks.push_back(parameter_block); + } else { + constant_parameter_blocks_.insert(parameter_block); } } @@ -386,8 +541,8 @@ bool CovarianceImpl::ComputeCovarianceValues() { switch (options_.algorithm_type) { case DENSE_SVD: return ComputeCovarianceValuesUsingDenseSVD(); -#ifndef CERES_NO_SUITESPARSE case SUITE_SPARSE_QR: +#ifndef CERES_NO_SUITESPARSE return ComputeCovarianceValuesUsingSuiteSparseQR(); #else LOG(ERROR) << "SuiteSparse is required to use the " @@ -624,7 +779,10 @@ bool CovarianceImpl::ComputeCovarianceValuesUsingDenseSVD() { if (automatic_truncation) { break; } else { - LOG(ERROR) << "Cholesky factorization of J'J is not reliable. " + LOG(ERROR) << "Error: Covariance matrix is near rank deficient " + << "and the user did not specify a non-zero" + << "Covariance::Options::null_space_rank " + << "to enable the computation of a Pseudo-Inverse. " << "Reciprocal condition number: " << singular_value_ratio * singular_value_ratio << " " << "min_reciprocal_condition_number: " diff --git a/extern/ceres/internal/ceres/covariance_impl.h b/extern/ceres/internal/ceres/covariance_impl.h index eb0cd040666..a3f0761f57c 100644 --- a/extern/ceres/internal/ceres/covariance_impl.h +++ b/extern/ceres/internal/ceres/covariance_impl.h @@ -55,12 +55,21 @@ class CovarianceImpl { const double*> >& covariance_blocks, ProblemImpl* problem); + bool Compute( + const std::vector& parameter_blocks, + ProblemImpl* problem); + bool GetCovarianceBlockInTangentOrAmbientSpace( const double* parameter_block1, const double* parameter_block2, bool lift_covariance_to_ambient_space, double* covariance_block) const; + bool GetCovarianceMatrixInTangentOrAmbientSpace( + const std::vector& parameters, + bool lift_covariance_to_ambient_space, + double *covariance_matrix) const; + bool ComputeCovarianceSparsity( const std::vector >& covariance_blocks, diff --git a/extern/ceres/internal/ceres/gradient_checker.cc b/extern/ceres/internal/ceres/gradient_checker.cc new file mode 100644 index 00000000000..c16c141db09 --- /dev/null +++ b/extern/ceres/internal/ceres/gradient_checker.cc @@ -0,0 +1,276 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2016 Google Inc. All rights reserved. +// http://ceres-solver.org/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Authors: wjr@google.com (William Rucklidge), +// keir@google.com (Keir Mierle), +// dgossow@google.com (David Gossow) + +#include "ceres/gradient_checker.h" + +#include +#include +#include +#include +#include + +#include "ceres/is_close.h" +#include "ceres/stringprintf.h" +#include "ceres/types.h" + +namespace ceres { + +using internal::IsClose; +using internal::StringAppendF; +using internal::StringPrintf; +using std::string; +using std::vector; + +namespace { +// Evaluate the cost function and transform the returned Jacobians to +// the local space of the respective local parameterizations. +bool EvaluateCostFunction( + const ceres::CostFunction* function, + double const* const * parameters, + const std::vector& + local_parameterizations, + Vector* residuals, + std::vector* jacobians, + std::vector* local_jacobians) { + CHECK_NOTNULL(residuals); + CHECK_NOTNULL(jacobians); + CHECK_NOTNULL(local_jacobians); + + const vector& block_sizes = function->parameter_block_sizes(); + const int num_parameter_blocks = block_sizes.size(); + + // Allocate Jacobian matrices in local space. + local_jacobians->resize(num_parameter_blocks); + vector local_jacobian_data(num_parameter_blocks); + for (int i = 0; i < num_parameter_blocks; ++i) { + int block_size = block_sizes.at(i); + if (local_parameterizations.at(i) != NULL) { + block_size = local_parameterizations.at(i)->LocalSize(); + } + local_jacobians->at(i).resize(function->num_residuals(), block_size); + local_jacobians->at(i).setZero(); + local_jacobian_data.at(i) = local_jacobians->at(i).data(); + } + + // Allocate Jacobian matrices in global space. + jacobians->resize(num_parameter_blocks); + vector jacobian_data(num_parameter_blocks); + for (int i = 0; i < num_parameter_blocks; ++i) { + jacobians->at(i).resize(function->num_residuals(), block_sizes.at(i)); + jacobians->at(i).setZero(); + jacobian_data.at(i) = jacobians->at(i).data(); + } + + // Compute residuals & jacobians. + CHECK_NE(0, function->num_residuals()); + residuals->resize(function->num_residuals()); + residuals->setZero(); + if (!function->Evaluate(parameters, residuals->data(), + jacobian_data.data())) { + return false; + } + + // Convert Jacobians from global to local space. + for (size_t i = 0; i < local_jacobians->size(); ++i) { + if (local_parameterizations.at(i) == NULL) { + local_jacobians->at(i) = jacobians->at(i); + } else { + int global_size = local_parameterizations.at(i)->GlobalSize(); + int local_size = local_parameterizations.at(i)->LocalSize(); + CHECK_EQ(jacobians->at(i).cols(), global_size); + Matrix global_J_local(global_size, local_size); + local_parameterizations.at(i)->ComputeJacobian( + parameters[i], global_J_local.data()); + local_jacobians->at(i) = jacobians->at(i) * global_J_local; + } + } + return true; +} +} // namespace + +GradientChecker::GradientChecker( + const CostFunction* function, + const vector* local_parameterizations, + const NumericDiffOptions& options) : + function_(function) { + CHECK_NOTNULL(function); + if (local_parameterizations != NULL) { + local_parameterizations_ = *local_parameterizations; + } else { + local_parameterizations_.resize(function->parameter_block_sizes().size(), + NULL); + } + DynamicNumericDiffCostFunction* + finite_diff_cost_function = + new DynamicNumericDiffCostFunction( + function, DO_NOT_TAKE_OWNERSHIP, options); + finite_diff_cost_function_.reset(finite_diff_cost_function); + + const vector& parameter_block_sizes = + function->parameter_block_sizes(); + const int num_parameter_blocks = parameter_block_sizes.size(); + for (int i = 0; i < num_parameter_blocks; ++i) { + finite_diff_cost_function->AddParameterBlock(parameter_block_sizes[i]); + } + finite_diff_cost_function->SetNumResiduals(function->num_residuals()); +} + +bool GradientChecker::Probe(double const* const * parameters, + double relative_precision, + ProbeResults* results_param) const { + int num_residuals = function_->num_residuals(); + + // Make sure that we have a place to store results, no matter if the user has + // provided an output argument. + ProbeResults* results; + ProbeResults results_local; + if (results_param != NULL) { + results = results_param; + results->residuals.resize(0); + results->jacobians.clear(); + results->numeric_jacobians.clear(); + results->local_jacobians.clear(); + results->local_numeric_jacobians.clear(); + results->error_log.clear(); + } else { + results = &results_local; + } + results->maximum_relative_error = 0.0; + results->return_value = true; + + // Evaluate the derivative using the user supplied code. + vector& jacobians = results->jacobians; + vector& local_jacobians = results->local_jacobians; + if (!EvaluateCostFunction(function_, parameters, local_parameterizations_, + &results->residuals, &jacobians, &local_jacobians)) { + results->error_log = "Function evaluation with Jacobians failed."; + results->return_value = false; + } + + // Evaluate the derivative using numeric derivatives. + vector& numeric_jacobians = results->numeric_jacobians; + vector& local_numeric_jacobians = results->local_numeric_jacobians; + Vector finite_diff_residuals; + if (!EvaluateCostFunction(finite_diff_cost_function_.get(), parameters, + local_parameterizations_, &finite_diff_residuals, + &numeric_jacobians, &local_numeric_jacobians)) { + results->error_log += "\nFunction evaluation with numerical " + "differentiation failed."; + results->return_value = false; + } + + if (!results->return_value) { + return false; + } + + for (int i = 0; i < num_residuals; ++i) { + if (!IsClose( + results->residuals[i], + finite_diff_residuals[i], + relative_precision, + NULL, + NULL)) { + results->error_log = "Function evaluation with and without Jacobians " + "resulted in different residuals."; + LOG(INFO) << results->residuals.transpose(); + LOG(INFO) << finite_diff_residuals.transpose(); + return false; + } + } + + // See if any elements have relative error larger than the threshold. + int num_bad_jacobian_components = 0; + double& worst_relative_error = results->maximum_relative_error; + worst_relative_error = 0; + + // Accumulate the error message for all the jacobians, since it won't get + // output if there are no bad jacobian components. + string error_log; + for (int k = 0; k < function_->parameter_block_sizes().size(); k++) { + StringAppendF(&error_log, + "========== " + "Jacobian for " "block %d: (%ld by %ld)) " + "==========\n", + k, + static_cast(local_jacobians[k].rows()), + static_cast(local_jacobians[k].cols())); + // The funny spacing creates appropriately aligned column headers. + error_log += + " block row col user dx/dy num diff dx/dy " + "abs error relative error parameter residual\n"; + + for (int i = 0; i < local_jacobians[k].rows(); i++) { + for (int j = 0; j < local_jacobians[k].cols(); j++) { + double term_jacobian = local_jacobians[k](i, j); + double finite_jacobian = local_numeric_jacobians[k](i, j); + double relative_error, absolute_error; + bool bad_jacobian_entry = + !IsClose(term_jacobian, + finite_jacobian, + relative_precision, + &relative_error, + &absolute_error); + worst_relative_error = std::max(worst_relative_error, relative_error); + + StringAppendF(&error_log, + "%6d %4d %4d %17g %17g %17g %17g %17g %17g", + k, i, j, + term_jacobian, finite_jacobian, + absolute_error, relative_error, + parameters[k][j], + results->residuals[i]); + + if (bad_jacobian_entry) { + num_bad_jacobian_components++; + StringAppendF( + &error_log, + " ------ (%d,%d,%d) Relative error worse than %g", + k, i, j, relative_precision); + } + error_log += "\n"; + } + } + } + + // Since there were some bad errors, dump comprehensive debug info. + if (num_bad_jacobian_components) { + string header = StringPrintf("\nDetected %d bad Jacobian component(s). " + "Worst relative error was %g.\n", + num_bad_jacobian_components, + worst_relative_error); + results->error_log = header + "\n" + error_log; + return false; + } + return true; +} + +} // namespace ceres diff --git a/extern/ceres/internal/ceres/gradient_checking_cost_function.cc b/extern/ceres/internal/ceres/gradient_checking_cost_function.cc index 580fd260e15..f2c73367891 100644 --- a/extern/ceres/internal/ceres/gradient_checking_cost_function.cc +++ b/extern/ceres/internal/ceres/gradient_checking_cost_function.cc @@ -26,7 +26,8 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // -// Author: keir@google.com (Keir Mierle) +// Authors: keir@google.com (Keir Mierle), +// dgossow@google.com (David Gossow) #include "ceres/gradient_checking_cost_function.h" @@ -36,7 +37,7 @@ #include #include -#include "ceres/cost_function.h" +#include "ceres/gradient_checker.h" #include "ceres/internal/eigen.h" #include "ceres/internal/scoped_ptr.h" #include "ceres/parameter_block.h" @@ -59,55 +60,25 @@ using std::vector; namespace { -// True if x and y have an absolute relative difference less than -// relative_precision and false otherwise. Stores the relative and absolute -// difference in relative/absolute_error if non-NULL. -bool IsClose(double x, double y, double relative_precision, - double *relative_error, - double *absolute_error) { - double local_absolute_error; - double local_relative_error; - if (!absolute_error) { - absolute_error = &local_absolute_error; - } - if (!relative_error) { - relative_error = &local_relative_error; - } - *absolute_error = abs(x - y); - *relative_error = *absolute_error / max(abs(x), abs(y)); - if (x == 0 || y == 0) { - // If x or y is exactly zero, then relative difference doesn't have any - // meaning. Take the absolute difference instead. - *relative_error = *absolute_error; - } - return abs(*relative_error) < abs(relative_precision); -} - class GradientCheckingCostFunction : public CostFunction { public: - GradientCheckingCostFunction(const CostFunction* function, - const NumericDiffOptions& options, - double relative_precision, - const string& extra_info) + GradientCheckingCostFunction( + const CostFunction* function, + const std::vector* local_parameterizations, + const NumericDiffOptions& options, + double relative_precision, + const string& extra_info, + GradientCheckingIterationCallback* callback) : function_(function), + gradient_checker_(function, local_parameterizations, options), relative_precision_(relative_precision), - extra_info_(extra_info) { - DynamicNumericDiffCostFunction* - finite_diff_cost_function = - new DynamicNumericDiffCostFunction( - function, - DO_NOT_TAKE_OWNERSHIP, - options); - + extra_info_(extra_info), + callback_(callback) { + CHECK_NOTNULL(callback_); const vector& parameter_block_sizes = function->parameter_block_sizes(); - for (int i = 0; i < parameter_block_sizes.size(); ++i) { - finite_diff_cost_function->AddParameterBlock(parameter_block_sizes[i]); - } *mutable_parameter_block_sizes() = parameter_block_sizes; set_num_residuals(function->num_residuals()); - finite_diff_cost_function->SetNumResiduals(num_residuals()); - finite_diff_cost_function_.reset(finite_diff_cost_function); } virtual ~GradientCheckingCostFunction() { } @@ -120,133 +91,92 @@ class GradientCheckingCostFunction : public CostFunction { return function_->Evaluate(parameters, residuals, NULL); } - int num_residuals = function_->num_residuals(); + GradientChecker::ProbeResults results; + bool okay = gradient_checker_.Probe(parameters, + relative_precision_, + &results); - // Make space for the jacobians of the two methods. - const vector& block_sizes = function_->parameter_block_sizes(); - vector term_jacobians(block_sizes.size()); - vector finite_difference_jacobians(block_sizes.size()); - vector term_jacobian_pointers(block_sizes.size()); - vector finite_difference_jacobian_pointers(block_sizes.size()); - for (int i = 0; i < block_sizes.size(); i++) { - term_jacobians[i].resize(num_residuals, block_sizes[i]); - term_jacobian_pointers[i] = term_jacobians[i].data(); - finite_difference_jacobians[i].resize(num_residuals, block_sizes[i]); - finite_difference_jacobian_pointers[i] = - finite_difference_jacobians[i].data(); - } - - // Evaluate the derivative using the user supplied code. - if (!function_->Evaluate(parameters, - residuals, - &term_jacobian_pointers[0])) { - LOG(WARNING) << "Function evaluation failed."; + // If the cost function returned false, there's nothing we can say about + // the gradients. + if (results.return_value == false) { return false; } - // Evaluate the derivative using numeric derivatives. - finite_diff_cost_function_->Evaluate( - parameters, - residuals, - &finite_difference_jacobian_pointers[0]); + // Copy the residuals. + const int num_residuals = function_->num_residuals(); + MatrixRef(residuals, num_residuals, 1) = results.residuals; - // See if any elements have relative error larger than the threshold. - int num_bad_jacobian_components = 0; - double worst_relative_error = 0; - - // Accumulate the error message for all the jacobians, since it won't get - // output if there are no bad jacobian components. - string m; + // Copy the original jacobian blocks into the jacobians array. + const vector& block_sizes = function_->parameter_block_sizes(); for (int k = 0; k < block_sizes.size(); k++) { - // Copy the original jacobian blocks into the jacobians array. if (jacobians[k] != NULL) { MatrixRef(jacobians[k], - term_jacobians[k].rows(), - term_jacobians[k].cols()) = term_jacobians[k]; - } - - StringAppendF(&m, - "========== " - "Jacobian for " "block %d: (%ld by %ld)) " - "==========\n", - k, - static_cast(term_jacobians[k].rows()), - static_cast(term_jacobians[k].cols())); - // The funny spacing creates appropriately aligned column headers. - m += " block row col user dx/dy num diff dx/dy " - "abs error relative error parameter residual\n"; - - for (int i = 0; i < term_jacobians[k].rows(); i++) { - for (int j = 0; j < term_jacobians[k].cols(); j++) { - double term_jacobian = term_jacobians[k](i, j); - double finite_jacobian = finite_difference_jacobians[k](i, j); - double relative_error, absolute_error; - bool bad_jacobian_entry = - !IsClose(term_jacobian, - finite_jacobian, - relative_precision_, - &relative_error, - &absolute_error); - worst_relative_error = max(worst_relative_error, relative_error); - - StringAppendF(&m, "%6d %4d %4d %17g %17g %17g %17g %17g %17g", - k, i, j, - term_jacobian, finite_jacobian, - absolute_error, relative_error, - parameters[k][j], - residuals[i]); - - if (bad_jacobian_entry) { - num_bad_jacobian_components++; - StringAppendF( - &m, " ------ (%d,%d,%d) Relative error worse than %g", - k, i, j, relative_precision_); - } - m += "\n"; - } + results.jacobians[k].rows(), + results.jacobians[k].cols()) = results.jacobians[k]; } } - // Since there were some bad errors, dump comprehensive debug info. - if (num_bad_jacobian_components) { - string header = StringPrintf("Detected %d bad jacobian component(s). " - "Worst relative error was %g.\n", - num_bad_jacobian_components, - worst_relative_error); - if (!extra_info_.empty()) { - header += "Extra info for this residual: " + extra_info_ + "\n"; - } - LOG(WARNING) << "\n" << header << m; + if (!okay) { + std::string error_log = "Gradient Error detected!\nExtra info for " + "this residual: " + extra_info_ + "\n" + results.error_log; + callback_->SetGradientErrorDetected(error_log); } return true; } private: const CostFunction* function_; - internal::scoped_ptr finite_diff_cost_function_; + GradientChecker gradient_checker_; double relative_precision_; string extra_info_; + GradientCheckingIterationCallback* callback_; }; } // namespace -CostFunction *CreateGradientCheckingCostFunction( - const CostFunction *cost_function, +GradientCheckingIterationCallback::GradientCheckingIterationCallback() + : gradient_error_detected_(false) { +} + +CallbackReturnType GradientCheckingIterationCallback::operator()( + const IterationSummary& summary) { + if (gradient_error_detected_) { + LOG(ERROR)<< "Gradient error detected. Terminating solver."; + return SOLVER_ABORT; + } + return SOLVER_CONTINUE; +} +void GradientCheckingIterationCallback::SetGradientErrorDetected( + std::string& error_log) { + mutex_.Lock(); + gradient_error_detected_ = true; + error_log_ += "\n" + error_log; + mutex_.Unlock(); +} + +CostFunction* CreateGradientCheckingCostFunction( + const CostFunction* cost_function, + const std::vector* local_parameterizations, double relative_step_size, double relative_precision, - const string& extra_info) { + const std::string& extra_info, + GradientCheckingIterationCallback* callback) { NumericDiffOptions numeric_diff_options; numeric_diff_options.relative_step_size = relative_step_size; return new GradientCheckingCostFunction(cost_function, + local_parameterizations, numeric_diff_options, - relative_precision, - extra_info); + relative_precision, extra_info, + callback); } -ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl, - double relative_step_size, - double relative_precision) { +ProblemImpl* CreateGradientCheckingProblemImpl( + ProblemImpl* problem_impl, + double relative_step_size, + double relative_precision, + GradientCheckingIterationCallback* callback) { + CHECK_NOTNULL(callback); // We create new CostFunctions by wrapping the original CostFunction // in a gradient checking CostFunction. So its okay for the // ProblemImpl to take ownership of it and destroy it. The @@ -260,6 +190,9 @@ ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl, gradient_checking_problem_options.local_parameterization_ownership = DO_NOT_TAKE_OWNERSHIP; + NumericDiffOptions numeric_diff_options; + numeric_diff_options.relative_step_size = relative_step_size; + ProblemImpl* gradient_checking_problem_impl = new ProblemImpl( gradient_checking_problem_options); @@ -294,19 +227,26 @@ ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl, string extra_info = StringPrintf( "Residual block id %d; depends on parameters [", i); vector parameter_blocks; + vector local_parameterizations; + parameter_blocks.reserve(residual_block->NumParameterBlocks()); + local_parameterizations.reserve(residual_block->NumParameterBlocks()); for (int j = 0; j < residual_block->NumParameterBlocks(); ++j) { ParameterBlock* parameter_block = residual_block->parameter_blocks()[j]; parameter_blocks.push_back(parameter_block->mutable_user_state()); StringAppendF(&extra_info, "%p", parameter_block->mutable_user_state()); extra_info += (j < residual_block->NumParameterBlocks() - 1) ? ", " : "]"; + local_parameterizations.push_back(problem_impl->GetParameterization( + parameter_block->mutable_user_state())); } // Wrap the original CostFunction in a GradientCheckingCostFunction. CostFunction* gradient_checking_cost_function = - CreateGradientCheckingCostFunction(residual_block->cost_function(), - relative_step_size, - relative_precision, - extra_info); + new GradientCheckingCostFunction(residual_block->cost_function(), + &local_parameterizations, + numeric_diff_options, + relative_precision, + extra_info, + callback); // The const_cast is necessary because // ProblemImpl::AddResidualBlock can potentially take ownership of diff --git a/extern/ceres/internal/ceres/gradient_checking_cost_function.h b/extern/ceres/internal/ceres/gradient_checking_cost_function.h index cf92cb72bc5..497f8e2a594 100644 --- a/extern/ceres/internal/ceres/gradient_checking_cost_function.h +++ b/extern/ceres/internal/ceres/gradient_checking_cost_function.h @@ -26,7 +26,8 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. // -// Author: keir@google.com (Keir Mierle) +// Authors: keir@google.com (Keir Mierle), +// dgossow@google.com (David Gossow) #ifndef CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_ #define CERES_INTERNAL_GRADIENT_CHECKING_COST_FUNCTION_H_ @@ -34,50 +35,76 @@ #include #include "ceres/cost_function.h" +#include "ceres/iteration_callback.h" +#include "ceres/local_parameterization.h" +#include "ceres/mutex.h" namespace ceres { namespace internal { class ProblemImpl; -// Creates a CostFunction that checks the jacobians that cost_function computes -// with finite differences. Bad results are logged; required precision is -// controlled by relative_precision and the numeric differentiation step size is -// controlled with relative_step_size. See solver.h for a better explanation of -// relative_step_size. Caller owns result. -// -// The condition enforced is that -// -// (J_actual(i, j) - J_numeric(i, j)) -// ------------------------------------ < relative_precision -// max(J_actual(i, j), J_numeric(i, j)) -// -// where J_actual(i, j) is the jacobian as computed by the supplied cost -// function (by the user) and J_numeric is the jacobian as computed by finite -// differences. -// -// Note: This is quite inefficient and is intended only for debugging. +// Callback that collects information about gradient checking errors, and +// will abort the solve as soon as an error occurs. +class GradientCheckingIterationCallback : public IterationCallback { + public: + GradientCheckingIterationCallback(); + + // Will return SOLVER_CONTINUE until a gradient error has been detected, + // then return SOLVER_ABORT. + virtual CallbackReturnType operator()(const IterationSummary& summary); + + // Notify this that a gradient error has occurred (thread safe). + void SetGradientErrorDetected(std::string& error_log); + + // Retrieve error status (not thread safe). + bool gradient_error_detected() const { return gradient_error_detected_; } + const std::string& error_log() const { return error_log_; } + private: + bool gradient_error_detected_; + std::string error_log_; + // Mutex protecting member variables. + ceres::internal::Mutex mutex_; +}; + +// Creates a CostFunction that checks the Jacobians that cost_function computes +// with finite differences. This API is only intended for unit tests that intend +// to check the functionality of the GradientCheckingCostFunction +// implementation directly. CostFunction* CreateGradientCheckingCostFunction( const CostFunction* cost_function, + const std::vector* local_parameterizations, double relative_step_size, double relative_precision, - const std::string& extra_info); + const std::string& extra_info, + GradientCheckingIterationCallback* callback); -// Create a new ProblemImpl object from the input problem_impl, where -// each CostFunctions in problem_impl are wrapped inside a -// GradientCheckingCostFunctions. This gives us a ProblemImpl object -// which checks its derivatives against estimates from numeric -// differentiation everytime a ResidualBlock is evaluated. +// Create a new ProblemImpl object from the input problem_impl, where all +// cost functions are wrapped so that each time their Evaluate method is called, +// an additional check is performed that compares the Jacobians computed by +// the original cost function with alternative Jacobians computed using +// numerical differentiation. If local parameterizations are given for any +// parameters, the Jacobians will be compared in the local space instead of the +// ambient space. For details on the gradient checking procedure, see the +// documentation of the GradientChecker class. If an error is detected in any +// iteration, the respective cost function will notify the +// GradientCheckingIterationCallback. +// +// The caller owns the returned ProblemImpl object. +// +// Note: This is quite inefficient and is intended only for debugging. // // relative_step_size and relative_precision are parameters to control // the numeric differentiation and the relative tolerance between the // jacobian computed by the CostFunctions in problem_impl and -// jacobians obtained by numerically differentiating them. For more -// details see the documentation for -// CreateGradientCheckingCostFunction above. -ProblemImpl* CreateGradientCheckingProblemImpl(ProblemImpl* problem_impl, - double relative_step_size, - double relative_precision); +// jacobians obtained by numerically differentiating them. See the +// documentation of 'numeric_derivative_relative_step_size' in solver.h for a +// better explanation. +ProblemImpl* CreateGradientCheckingProblemImpl( + ProblemImpl* problem_impl, + double relative_step_size, + double relative_precision, + GradientCheckingIterationCallback* callback); } // namespace internal } // namespace ceres diff --git a/extern/ceres/internal/ceres/gradient_problem_solver.cc b/extern/ceres/internal/ceres/gradient_problem_solver.cc index 9a549c23dac..8709f8f3fbd 100644 --- a/extern/ceres/internal/ceres/gradient_problem_solver.cc +++ b/extern/ceres/internal/ceres/gradient_problem_solver.cc @@ -84,6 +84,12 @@ Solver::Options GradientProblemSolverOptionsToSolverOptions( } // namespace +bool GradientProblemSolver::Options::IsValid(std::string* error) const { + const Solver::Options solver_options = + GradientProblemSolverOptionsToSolverOptions(*this); + return solver_options.IsValid(error); +} + GradientProblemSolver::~GradientProblemSolver() { } @@ -99,8 +105,6 @@ void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options, using internal::SetSummaryFinalCost; double start_time = WallTimeInSeconds(); - Solver::Options solver_options = - GradientProblemSolverOptionsToSolverOptions(options); *CHECK_NOTNULL(summary) = Summary(); summary->num_parameters = problem.NumParameters(); @@ -112,14 +116,16 @@ void GradientProblemSolver::Solve(const GradientProblemSolver::Options& options, summary->nonlinear_conjugate_gradient_type = options.nonlinear_conjugate_gradient_type; // NOLINT // Check validity - if (!solver_options.IsValid(&summary->message)) { + if (!options.IsValid(&summary->message)) { LOG(ERROR) << "Terminating: " << summary->message; return; } - // Assuming that the parameter blocks in the program have been - Minimizer::Options minimizer_options; - minimizer_options = Minimizer::Options(solver_options); + // TODO(sameeragarwal): This is a bit convoluted, we should be able + // to convert to minimizer options directly, but this will do for + // now. + Minimizer::Options minimizer_options = + Minimizer::Options(GradientProblemSolverOptionsToSolverOptions(options)); minimizer_options.evaluator.reset(new GradientProblemEvaluator(problem)); scoped_ptr logging_callback; diff --git a/extern/ceres/internal/ceres/is_close.cc b/extern/ceres/internal/ceres/is_close.cc new file mode 100644 index 00000000000..a91a17454d9 --- /dev/null +++ b/extern/ceres/internal/ceres/is_close.cc @@ -0,0 +1,59 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2016 Google Inc. All rights reserved. +// http://ceres-solver.org/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keir@google.com (Keir Mierle), dgossow@google.com (David Gossow) + +#include "ceres/is_close.h" + +#include +#include + +namespace ceres { +namespace internal { +bool IsClose(double x, double y, double relative_precision, + double *relative_error, + double *absolute_error) { + double local_absolute_error; + double local_relative_error; + if (!absolute_error) { + absolute_error = &local_absolute_error; + } + if (!relative_error) { + relative_error = &local_relative_error; + } + *absolute_error = std::fabs(x - y); + *relative_error = *absolute_error / std::max(std::fabs(x), std::fabs(y)); + if (x == 0 || y == 0) { + // If x or y is exactly zero, then relative difference doesn't have any + // meaning. Take the absolute difference instead. + *relative_error = *absolute_error; + } + return *relative_error < std::fabs(relative_precision); +} +} // namespace internal +} // namespace ceres diff --git a/extern/ceres/internal/ceres/is_close.h b/extern/ceres/internal/ceres/is_close.h new file mode 100644 index 00000000000..7789448c8e8 --- /dev/null +++ b/extern/ceres/internal/ceres/is_close.h @@ -0,0 +1,51 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2016 Google Inc. All rights reserved. +// http://ceres-solver.org/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Authors: keir@google.com (Keir Mierle), dgossow@google.com (David Gossow) +// +// Utility routine for comparing two values. + +#ifndef CERES_INTERNAL_IS_CLOSE_H_ +#define CERES_INTERNAL_IS_CLOSE_H_ + +namespace ceres { +namespace internal { +// Returns true if x and y have a relative (unsigned) difference less than +// relative_precision and false otherwise. Stores the relative and absolute +// difference in relative/absolute_error if non-NULL. If one of the two values +// is exactly zero, the absolute difference will be compared, and relative_error +// will be set to the absolute difference. +bool IsClose(double x, + double y, + double relative_precision, + double *relative_error, + double *absolute_error); +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_IS_CLOSE_H_ diff --git a/extern/ceres/internal/ceres/line_search_minimizer.cc b/extern/ceres/internal/ceres/line_search_minimizer.cc index 62264fb0b64..fdde1ca9c86 100644 --- a/extern/ceres/internal/ceres/line_search_minimizer.cc +++ b/extern/ceres/internal/ceres/line_search_minimizer.cc @@ -191,6 +191,7 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options, options.line_search_sufficient_curvature_decrease; line_search_options.max_step_expansion = options.max_line_search_step_expansion; + line_search_options.is_silent = options.is_silent; line_search_options.function = &line_search_function; scoped_ptr @@ -341,10 +342,12 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options, "as the step was valid when it was selected by the line search."; LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message; break; - } else if (!Evaluate(evaluator, - x_plus_delta, - ¤t_state, - &summary->message)) { + } + + if (!Evaluate(evaluator, + x_plus_delta, + ¤t_state, + &summary->message)) { summary->termination_type = FAILURE; summary->message = "Step failed to evaluate. This should not happen as the step was " @@ -352,15 +355,17 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options, summary->message; LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message; break; - } else { - x = x_plus_delta; } + // Compute the norm of the step in the ambient space. + iteration_summary.step_norm = (x_plus_delta - x).norm(); + x = x_plus_delta; + iteration_summary.gradient_max_norm = current_state.gradient_max_norm; iteration_summary.gradient_norm = sqrt(current_state.gradient_squared_norm); iteration_summary.cost_change = previous_state.cost - current_state.cost; iteration_summary.cost = current_state.cost + summary->fixed_cost; - iteration_summary.step_norm = delta.norm(); + iteration_summary.step_is_valid = true; iteration_summary.step_is_successful = true; iteration_summary.step_size = current_state.step_size; @@ -376,6 +381,13 @@ void LineSearchMinimizer::Minimize(const Minimizer::Options& options, WallTimeInSeconds() - start_time + summary->preprocessor_time_in_seconds; + // Iterations inside the line search algorithm are considered + // 'steps' in the broader context, to distinguish these inner + // iterations from from the outer iterations of the line search + // minimizer. The number of line search steps is the total number + // of inner line search iterations (or steps) across the entire + // minimization. + summary->num_line_search_steps += line_search_summary.num_iterations; summary->line_search_cost_evaluation_time_in_seconds += line_search_summary.cost_evaluation_time_in_seconds; summary->line_search_gradient_evaluation_time_in_seconds += diff --git a/extern/ceres/internal/ceres/local_parameterization.cc b/extern/ceres/internal/ceres/local_parameterization.cc index 82004761ec0..a6bf1f6ddcc 100644 --- a/extern/ceres/internal/ceres/local_parameterization.cc +++ b/extern/ceres/internal/ceres/local_parameterization.cc @@ -30,6 +30,8 @@ #include "ceres/local_parameterization.h" +#include +#include "Eigen/Geometry" #include "ceres/householder_vector.h" #include "ceres/internal/eigen.h" #include "ceres/internal/fixed_array.h" @@ -87,28 +89,17 @@ bool IdentityParameterization::MultiplyByJacobian(const double* x, } SubsetParameterization::SubsetParameterization( - int size, - const vector& constant_parameters) - : local_size_(size - constant_parameters.size()), - constancy_mask_(size, 0) { - CHECK_GT(constant_parameters.size(), 0) - << "The set of constant parameters should contain at least " - << "one element. If you do not wish to hold any parameters " - << "constant, then do not use a SubsetParameterization"; - + int size, const vector& constant_parameters) + : local_size_(size - constant_parameters.size()), constancy_mask_(size, 0) { vector constant = constant_parameters; - sort(constant.begin(), constant.end()); - CHECK(unique(constant.begin(), constant.end()) == constant.end()) + std::sort(constant.begin(), constant.end()); + CHECK_GE(constant.front(), 0) + << "Indices indicating constant parameter must be greater than zero."; + CHECK_LT(constant.back(), size) + << "Indices indicating constant parameter must be less than the size " + << "of the parameter block."; + CHECK(std::adjacent_find(constant.begin(), constant.end()) == constant.end()) << "The set of constant parameters cannot contain duplicates"; - CHECK_LT(constant_parameters.size(), size) - << "Number of parameters held constant should be less " - << "than the size of the parameter block. If you wish " - << "to hold the entire parameter block constant, then a " - << "efficient way is to directly mark it as constant " - << "instead of using a LocalParameterization to do so."; - CHECK_GE(*min_element(constant.begin(), constant.end()), 0); - CHECK_LT(*max_element(constant.begin(), constant.end()), size); - for (int i = 0; i < constant_parameters.size(); ++i) { constancy_mask_[constant_parameters[i]] = 1; } @@ -129,6 +120,10 @@ bool SubsetParameterization::Plus(const double* x, bool SubsetParameterization::ComputeJacobian(const double* x, double* jacobian) const { + if (local_size_ == 0) { + return true; + } + MatrixRef m(jacobian, constancy_mask_.size(), local_size_); m.setZero(); for (int i = 0, j = 0; i < constancy_mask_.size(); ++i) { @@ -143,6 +138,10 @@ bool SubsetParameterization::MultiplyByJacobian(const double* x, const int num_rows, const double* global_matrix, double* local_matrix) const { + if (local_size_ == 0) { + return true; + } + for (int row = 0; row < num_rows; ++row) { for (int col = 0, j = 0; col < constancy_mask_.size(); ++col) { if (!constancy_mask_[col]) { @@ -184,6 +183,39 @@ bool QuaternionParameterization::ComputeJacobian(const double* x, return true; } +bool EigenQuaternionParameterization::Plus(const double* x_ptr, + const double* delta, + double* x_plus_delta_ptr) const { + Eigen::Map x_plus_delta(x_plus_delta_ptr); + Eigen::Map x(x_ptr); + + const double norm_delta = + sqrt(delta[0] * delta[0] + delta[1] * delta[1] + delta[2] * delta[2]); + if (norm_delta > 0.0) { + const double sin_delta_by_delta = sin(norm_delta) / norm_delta; + + // Note, in the constructor w is first. + Eigen::Quaterniond delta_q(cos(norm_delta), + sin_delta_by_delta * delta[0], + sin_delta_by_delta * delta[1], + sin_delta_by_delta * delta[2]); + x_plus_delta = delta_q * x; + } else { + x_plus_delta = x; + } + + return true; +} + +bool EigenQuaternionParameterization::ComputeJacobian(const double* x, + double* jacobian) const { + jacobian[0] = x[3]; jacobian[1] = x[2]; jacobian[2] = -x[1]; // NOLINT + jacobian[3] = -x[2]; jacobian[4] = x[3]; jacobian[5] = x[0]; // NOLINT + jacobian[6] = x[1]; jacobian[7] = -x[0]; jacobian[8] = x[3]; // NOLINT + jacobian[9] = -x[0]; jacobian[10] = -x[1]; jacobian[11] = -x[2]; // NOLINT + return true; +} + HomogeneousVectorParameterization::HomogeneousVectorParameterization(int size) : size_(size) { CHECK_GT(size_, 1) << "The size of the homogeneous vector needs to be " @@ -332,9 +364,9 @@ bool ProductParameterization::ComputeJacobian(const double* x, if (!param->ComputeJacobian(x + x_cursor, buffer.get())) { return false; } - jacobian.block(x_cursor, delta_cursor, global_size, local_size) = MatrixRef(buffer.get(), global_size, local_size); + delta_cursor += local_size; x_cursor += global_size; } diff --git a/extern/ceres/internal/ceres/map_util.h b/extern/ceres/internal/ceres/map_util.h index 61c531f297c..f55aee37689 100644 --- a/extern/ceres/internal/ceres/map_util.h +++ b/extern/ceres/internal/ceres/map_util.h @@ -67,7 +67,7 @@ FindOrDie(const Collection& collection, // If the key is present in the map then the value associated with that // key is returned, otherwise the value passed as a default is returned. template -const typename Collection::value_type::second_type& +const typename Collection::value_type::second_type FindWithDefault(const Collection& collection, const typename Collection::value_type::first_type& key, const typename Collection::value_type::second_type& value) { diff --git a/extern/ceres/internal/ceres/parameter_block.h b/extern/ceres/internal/ceres/parameter_block.h index cb7140d9582..8e21553c668 100644 --- a/extern/ceres/internal/ceres/parameter_block.h +++ b/extern/ceres/internal/ceres/parameter_block.h @@ -161,25 +161,34 @@ class ParameterBlock { // does not take ownership of the parameterization. void SetParameterization(LocalParameterization* new_parameterization) { CHECK(new_parameterization != NULL) << "NULL parameterization invalid."; + // Nothing to do if the new parameterization is the same as the + // old parameterization. + if (new_parameterization == local_parameterization_) { + return; + } + + CHECK(local_parameterization_ == NULL) + << "Can't re-set the local parameterization; it leads to " + << "ambiguous ownership. Current local parameterization is: " + << local_parameterization_; + CHECK(new_parameterization->GlobalSize() == size_) << "Invalid parameterization for parameter block. The parameter block " << "has size " << size_ << " while the parameterization has a global " << "size of " << new_parameterization->GlobalSize() << ". Did you " << "accidentally use the wrong parameter block or parameterization?"; - if (new_parameterization != local_parameterization_) { - CHECK(local_parameterization_ == NULL) - << "Can't re-set the local parameterization; it leads to " - << "ambiguous ownership."; - local_parameterization_ = new_parameterization; - local_parameterization_jacobian_.reset( - new double[local_parameterization_->GlobalSize() * - local_parameterization_->LocalSize()]); - CHECK(UpdateLocalParameterizationJacobian()) - << "Local parameterization Jacobian computation failed for x: " - << ConstVectorRef(state_, Size()).transpose(); - } else { - // Ignore the case that the parameterizations match. - } + + CHECK_GT(new_parameterization->LocalSize(), 0) + << "Invalid parameterization. Parameterizations must have a positive " + << "dimensional tangent space."; + + local_parameterization_ = new_parameterization; + local_parameterization_jacobian_.reset( + new double[local_parameterization_->GlobalSize() * + local_parameterization_->LocalSize()]); + CHECK(UpdateLocalParameterizationJacobian()) + << "Local parameterization Jacobian computation failed for x: " + << ConstVectorRef(state_, Size()).transpose(); } void SetUpperBound(int index, double upper_bound) { diff --git a/extern/ceres/internal/ceres/problem.cc b/extern/ceres/internal/ceres/problem.cc index 03b7d6afa48..730ce642036 100644 --- a/extern/ceres/internal/ceres/problem.cc +++ b/extern/ceres/internal/ceres/problem.cc @@ -174,6 +174,10 @@ void Problem::SetParameterBlockVariable(double* values) { problem_impl_->SetParameterBlockVariable(values); } +bool Problem::IsParameterBlockConstant(double* values) const { + return problem_impl_->IsParameterBlockConstant(values); +} + void Problem::SetParameterization( double* values, LocalParameterization* local_parameterization) { diff --git a/extern/ceres/internal/ceres/problem_impl.cc b/extern/ceres/internal/ceres/problem_impl.cc index 8547d5d3f77..4abea8b33ee 100644 --- a/extern/ceres/internal/ceres/problem_impl.cc +++ b/extern/ceres/internal/ceres/problem_impl.cc @@ -249,10 +249,11 @@ ResidualBlock* ProblemImpl::AddResidualBlock( // Check for duplicate parameter blocks. vector sorted_parameter_blocks(parameter_blocks); sort(sorted_parameter_blocks.begin(), sorted_parameter_blocks.end()); - vector::const_iterator duplicate_items = - unique(sorted_parameter_blocks.begin(), - sorted_parameter_blocks.end()); - if (duplicate_items != sorted_parameter_blocks.end()) { + const bool has_duplicate_items = + (std::adjacent_find(sorted_parameter_blocks.begin(), + sorted_parameter_blocks.end()) + != sorted_parameter_blocks.end()); + if (has_duplicate_items) { string blocks; for (int i = 0; i < parameter_blocks.size(); ++i) { blocks += StringPrintf(" %p ", parameter_blocks[i]); @@ -572,6 +573,16 @@ void ProblemImpl::SetParameterBlockConstant(double* values) { parameter_block->SetConstant(); } +bool ProblemImpl::IsParameterBlockConstant(double* values) const { + const ParameterBlock* parameter_block = + FindWithDefault(parameter_block_map_, values, NULL); + CHECK(parameter_block != NULL) + << "Parameter block not found: " << values << ". You must add the " + << "parameter block to the problem before it can be queried."; + + return parameter_block->IsConstant(); +} + void ProblemImpl::SetParameterBlockVariable(double* values) { ParameterBlock* parameter_block = FindWithDefault(parameter_block_map_, values, NULL); diff --git a/extern/ceres/internal/ceres/problem_impl.h b/extern/ceres/internal/ceres/problem_impl.h index f42bde6c793..a4689c362f6 100644 --- a/extern/ceres/internal/ceres/problem_impl.h +++ b/extern/ceres/internal/ceres/problem_impl.h @@ -128,6 +128,8 @@ class ProblemImpl { void SetParameterBlockConstant(double* values); void SetParameterBlockVariable(double* values); + bool IsParameterBlockConstant(double* values) const; + void SetParameterization(double* values, LocalParameterization* local_parameterization); const LocalParameterization* GetParameterization(double* values) const; diff --git a/extern/ceres/internal/ceres/reorder_program.cc b/extern/ceres/internal/ceres/reorder_program.cc index d0e8f32b3b7..a7c37107591 100644 --- a/extern/ceres/internal/ceres/reorder_program.cc +++ b/extern/ceres/internal/ceres/reorder_program.cc @@ -142,6 +142,11 @@ void OrderingForSparseNormalCholeskyUsingSuiteSparse( ordering); } + VLOG(2) << "Block ordering stats: " + << " flops: " << ss.mutable_cc()->fl + << " lnz : " << ss.mutable_cc()->lnz + << " anz : " << ss.mutable_cc()->anz; + ss.Free(block_jacobian_transpose); #endif // CERES_NO_SUITESPARSE } diff --git a/extern/ceres/internal/ceres/residual_block.h b/extern/ceres/internal/ceres/residual_block.h index 05e6d1f81e5..a32f1c36cd3 100644 --- a/extern/ceres/internal/ceres/residual_block.h +++ b/extern/ceres/internal/ceres/residual_block.h @@ -127,7 +127,7 @@ class ResidualBlock { int index() const { return index_; } void set_index(int index) { index_ = index; } - std::string ToString() { + std::string ToString() const { return StringPrintf("{residual block; index=%d}", index_); } diff --git a/extern/ceres/internal/ceres/schur_complement_solver.cc b/extern/ceres/internal/ceres/schur_complement_solver.cc index 2491060dcdc..65449832c4c 100644 --- a/extern/ceres/internal/ceres/schur_complement_solver.cc +++ b/extern/ceres/internal/ceres/schur_complement_solver.cc @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "ceres/block_random_access_dense_matrix.h" @@ -563,6 +564,12 @@ SparseSchurComplementSolver::SolveReducedLinearSystemUsingEigen( // worse than the one computed using the block version of the // algorithm. simplicial_ldlt_->analyzePattern(eigen_lhs); + if (VLOG_IS_ON(2)) { + std::stringstream ss; + simplicial_ldlt_->dumpMemory(ss); + VLOG(2) << "Symbolic Analysis\n" + << ss.str(); + } event_logger.AddEvent("Analysis"); if (simplicial_ldlt_->info() != Eigen::Success) { summary.termination_type = LINEAR_SOLVER_FATAL_ERROR; diff --git a/extern/ceres/internal/ceres/solver.cc b/extern/ceres/internal/ceres/solver.cc index 9f3228bb0be..8411350986a 100644 --- a/extern/ceres/internal/ceres/solver.cc +++ b/extern/ceres/internal/ceres/solver.cc @@ -94,7 +94,7 @@ bool CommonOptionsAreValid(const Solver::Options& options, string* error) { OPTION_GT(num_linear_solver_threads, 0); if (options.check_gradients) { OPTION_GT(gradient_check_relative_precision, 0.0); - OPTION_GT(numeric_derivative_relative_step_size, 0.0); + OPTION_GT(gradient_check_numeric_derivative_relative_step_size, 0.0); } return true; } @@ -351,6 +351,7 @@ void PreSolveSummarize(const Solver::Options& options, summary->dense_linear_algebra_library_type = options.dense_linear_algebra_library_type; // NOLINT summary->dogleg_type = options.dogleg_type; summary->inner_iteration_time_in_seconds = 0.0; + summary->num_line_search_steps = 0; summary->line_search_cost_evaluation_time_in_seconds = 0.0; summary->line_search_gradient_evaluation_time_in_seconds = 0.0; summary->line_search_polynomial_minimization_time_in_seconds = 0.0; @@ -495,21 +496,28 @@ void Solver::Solve(const Solver::Options& options, // values provided by the user. program->SetParameterBlockStatePtrsToUserStatePtrs(); + // If gradient_checking is enabled, wrap all cost functions in a + // gradient checker and install a callback that terminates if any gradient + // error is detected. scoped_ptr gradient_checking_problem; + internal::GradientCheckingIterationCallback gradient_checking_callback; + Solver::Options modified_options = options; if (options.check_gradients) { + modified_options.callbacks.push_back(&gradient_checking_callback); gradient_checking_problem.reset( CreateGradientCheckingProblemImpl( problem_impl, - options.numeric_derivative_relative_step_size, - options.gradient_check_relative_precision)); + options.gradient_check_numeric_derivative_relative_step_size, + options.gradient_check_relative_precision, + &gradient_checking_callback)); problem_impl = gradient_checking_problem.get(); program = problem_impl->mutable_program(); } scoped_ptr preprocessor( - Preprocessor::Create(options.minimizer_type)); + Preprocessor::Create(modified_options.minimizer_type)); PreprocessedProblem pp; - const bool status = preprocessor->Preprocess(options, problem_impl, &pp); + const bool status = preprocessor->Preprocess(modified_options, problem_impl, &pp); summary->fixed_cost = pp.fixed_cost; summary->preprocessor_time_in_seconds = WallTimeInSeconds() - start_time; @@ -534,6 +542,13 @@ void Solver::Solve(const Solver::Options& options, summary->postprocessor_time_in_seconds = WallTimeInSeconds() - postprocessor_start_time; + // If the gradient checker reported an error, we want to report FAILURE + // instead of USER_FAILURE and provide the error log. + if (gradient_checking_callback.gradient_error_detected()) { + summary->termination_type = FAILURE; + summary->message = gradient_checking_callback.error_log(); + } + summary->total_time_in_seconds = WallTimeInSeconds() - start_time; } @@ -556,6 +571,7 @@ Solver::Summary::Summary() num_successful_steps(-1), num_unsuccessful_steps(-1), num_inner_iteration_steps(-1), + num_line_search_steps(-1), preprocessor_time_in_seconds(-1.0), minimizer_time_in_seconds(-1.0), postprocessor_time_in_seconds(-1.0), @@ -696,16 +712,14 @@ string Solver::Summary::FullReport() const { num_linear_solver_threads_given, num_linear_solver_threads_used); - if (IsSchurType(linear_solver_type_used)) { - string given; - StringifyOrdering(linear_solver_ordering_given, &given); - string used; - StringifyOrdering(linear_solver_ordering_used, &used); - StringAppendF(&report, - "Linear solver ordering %22s %24s\n", - given.c_str(), - used.c_str()); - } + string given; + StringifyOrdering(linear_solver_ordering_given, &given); + string used; + StringifyOrdering(linear_solver_ordering_used, &used); + StringAppendF(&report, + "Linear solver ordering %22s %24s\n", + given.c_str(), + used.c_str()); if (inner_iterations_given) { StringAppendF(&report, @@ -784,9 +798,14 @@ string Solver::Summary::FullReport() const { num_inner_iteration_steps); } - const bool print_line_search_timing_information = - minimizer_type == LINE_SEARCH || - (minimizer_type == TRUST_REGION && is_constrained); + const bool line_search_used = + (minimizer_type == LINE_SEARCH || + (minimizer_type == TRUST_REGION && is_constrained)); + + if (line_search_used) { + StringAppendF(&report, "Line search steps % 14d\n", + num_line_search_steps); + } StringAppendF(&report, "\nTime (in seconds):\n"); StringAppendF(&report, "Preprocessor %25.4f\n", @@ -794,13 +813,13 @@ string Solver::Summary::FullReport() const { StringAppendF(&report, "\n Residual evaluation %23.4f\n", residual_evaluation_time_in_seconds); - if (print_line_search_timing_information) { + if (line_search_used) { StringAppendF(&report, " Line search cost evaluation %10.4f\n", line_search_cost_evaluation_time_in_seconds); } StringAppendF(&report, " Jacobian evaluation %23.4f\n", jacobian_evaluation_time_in_seconds); - if (print_line_search_timing_information) { + if (line_search_used) { StringAppendF(&report, " Line search gradient evaluation %6.4f\n", line_search_gradient_evaluation_time_in_seconds); } @@ -815,7 +834,7 @@ string Solver::Summary::FullReport() const { inner_iteration_time_in_seconds); } - if (print_line_search_timing_information) { + if (line_search_used) { StringAppendF(&report, " Line search polynomial minimization %.4f\n", line_search_polynomial_minimization_time_in_seconds); } diff --git a/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc b/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc index ed00879b47a..a4c2c766ddc 100644 --- a/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc +++ b/extern/ceres/internal/ceres/sparse_normal_cholesky_solver.cc @@ -33,6 +33,7 @@ #include #include #include +#include #include "ceres/compressed_row_sparse_matrix.h" #include "ceres/cxsparse.h" @@ -71,6 +72,12 @@ LinearSolver::Summary SimplicialLDLTSolve( if (do_symbolic_analysis) { solver->analyzePattern(lhs); + if (VLOG_IS_ON(2)) { + std::stringstream ss; + solver->dumpMemory(ss); + VLOG(2) << "Symbolic Analysis\n" + << ss.str(); + } event_logger->AddEvent("Analyze"); if (solver->info() != Eigen::Success) { summary.termination_type = LINEAR_SOLVER_FATAL_ERROR; diff --git a/extern/ceres/internal/ceres/stringprintf.cc b/extern/ceres/internal/ceres/stringprintf.cc index d1d8b5fe8ab..b3b7474d8f8 100644 --- a/extern/ceres/internal/ceres/stringprintf.cc +++ b/extern/ceres/internal/ceres/stringprintf.cc @@ -43,14 +43,27 @@ namespace internal { using std::string; -#ifdef _MSC_VER -enum { IS_COMPILER_MSVC = 1 }; -#if _MSC_VER < 1800 -#define va_copy(d, s) ((d) = (s)) -#endif +// va_copy() was defined in the C99 standard. However, it did not appear in the +// C++ standard until C++11. This means that if Ceres is being compiled with a +// strict pre-C++11 standard (e.g. -std=c++03), va_copy() will NOT be defined, +// as we are using the C++ compiler (it would however be defined if we were +// using the C compiler). Note however that both GCC & Clang will in fact +// define va_copy() when compiling for C++ if the C++ standard is not explicitly +// specified (i.e. no -std=c++ arg), even though it should not strictly be +// defined unless -std=c++11 (or greater) was passed. +#if !defined(va_copy) +#if defined (__GNUC__) +// On GCC/Clang, if va_copy() is not defined (C++ standard < C++11 explicitly +// specified), use the internal __va_copy() version, which should be present +// in even very old GCC versions. +#define va_copy(d, s) __va_copy(d, s) #else -enum { IS_COMPILER_MSVC = 0 }; -#endif +// Some older versions of MSVC do not have va_copy(), in which case define it. +// Although this is required for older MSVC versions, it should also work for +// other non-GCC/Clang compilers which also do not defined va_copy(). +#define va_copy(d, s) ((d) = (s)) +#endif // defined (__GNUC__) +#endif // !defined(va_copy) void StringAppendV(string* dst, const char* format, va_list ap) { // First try with a small fixed size buffer @@ -71,13 +84,13 @@ void StringAppendV(string* dst, const char* format, va_list ap) { return; } - if (IS_COMPILER_MSVC) { - // Error or MSVC running out of space. MSVC 8.0 and higher - // can be asked about space needed with the special idiom below: - va_copy(backup_ap, ap); - result = vsnprintf(NULL, 0, format, backup_ap); - va_end(backup_ap); - } +#if defined (_MSC_VER) + // Error or MSVC running out of space. MSVC 8.0 and higher + // can be asked about space needed with the special idiom below: + va_copy(backup_ap, ap); + result = vsnprintf(NULL, 0, format, backup_ap); + va_end(backup_ap); +#endif if (result < 0) { // Just an error. diff --git a/extern/ceres/internal/ceres/trust_region_minimizer.cc b/extern/ceres/internal/ceres/trust_region_minimizer.cc index d654d0867f1..d809906ab54 100644 --- a/extern/ceres/internal/ceres/trust_region_minimizer.cc +++ b/extern/ceres/internal/ceres/trust_region_minimizer.cc @@ -1,5 +1,5 @@ // Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2015 Google Inc. All rights reserved. +// Copyright 2016 Google Inc. All rights reserved. // http://ceres-solver.org/ // // Redistribution and use in source and binary forms, with or without @@ -43,674 +43,747 @@ #include "ceres/coordinate_descent_minimizer.h" #include "ceres/evaluator.h" #include "ceres/file.h" -#include "ceres/internal/eigen.h" -#include "ceres/internal/scoped_ptr.h" #include "ceres/line_search.h" -#include "ceres/linear_least_squares_problems.h" -#include "ceres/sparse_matrix.h" #include "ceres/stringprintf.h" -#include "ceres/trust_region_strategy.h" #include "ceres/types.h" #include "ceres/wall_time.h" #include "glog/logging.h" +// Helper macro to simplify some of the control flow. +#define RETURN_IF_ERROR_AND_LOG(expr) \ + do { \ + if (!(expr)) { \ + LOG(ERROR) << "Terminating: " << solver_summary_->message; \ + return; \ + } \ + } while (0) + namespace ceres { namespace internal { -namespace { -LineSearch::Summary DoLineSearch(const Minimizer::Options& options, - const Vector& x, - const Vector& gradient, - const double cost, - const Vector& delta, - Evaluator* evaluator) { - LineSearchFunction line_search_function(evaluator); +TrustRegionMinimizer::~TrustRegionMinimizer() {} + +void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, + double* parameters, + Solver::Summary* solver_summary) { + start_time_in_secs_ = WallTimeInSeconds(); + iteration_start_time_in_secs_ = start_time_in_secs_; + Init(options, parameters, solver_summary); + RETURN_IF_ERROR_AND_LOG(IterationZero()); + + // Create the TrustRegionStepEvaluator. The construction needs to be + // delayed to this point because we need the cost for the starting + // point to initialize the step evaluator. + step_evaluator_.reset(new TrustRegionStepEvaluator( + x_cost_, + options_.use_nonmonotonic_steps + ? options_.max_consecutive_nonmonotonic_steps + : 0)); + + while (FinalizeIterationAndCheckIfMinimizerCanContinue()) { + iteration_start_time_in_secs_ = WallTimeInSeconds(); + iteration_summary_ = IterationSummary(); + iteration_summary_.iteration = + solver_summary->iterations.back().iteration + 1; + + RETURN_IF_ERROR_AND_LOG(ComputeTrustRegionStep()); + if (!iteration_summary_.step_is_valid) { + RETURN_IF_ERROR_AND_LOG(HandleInvalidStep()); + continue; + } + + if (options_.is_constrained) { + // Use a projected line search to enforce the bounds constraints + // and improve the quality of the step. + DoLineSearch(x_, gradient_, x_cost_, &delta_); + } + + ComputeCandidatePointAndEvaluateCost(); + DoInnerIterationsIfNeeded(); + + if (ParameterToleranceReached()) { + return; + } + + if (FunctionToleranceReached()) { + return; + } + + if (IsStepSuccessful()) { + RETURN_IF_ERROR_AND_LOG(HandleSuccessfulStep()); + continue; + } + + HandleUnsuccessfulStep(); + } +} + +// Initialize the minimizer, allocate working space and set some of +// the fields in the solver_summary. +void TrustRegionMinimizer::Init(const Minimizer::Options& options, + double* parameters, + Solver::Summary* solver_summary) { + options_ = options; + sort(options_.trust_region_minimizer_iterations_to_dump.begin(), + options_.trust_region_minimizer_iterations_to_dump.end()); + + parameters_ = parameters; + + solver_summary_ = solver_summary; + solver_summary_->termination_type = NO_CONVERGENCE; + solver_summary_->num_successful_steps = 0; + solver_summary_->num_unsuccessful_steps = 0; + solver_summary_->is_constrained = options.is_constrained; + + evaluator_ = CHECK_NOTNULL(options_.evaluator.get()); + jacobian_ = CHECK_NOTNULL(options_.jacobian.get()); + strategy_ = CHECK_NOTNULL(options_.trust_region_strategy.get()); + + is_not_silent_ = !options.is_silent; + inner_iterations_are_enabled_ = + options.inner_iteration_minimizer.get() != NULL; + inner_iterations_were_useful_ = false; + + num_parameters_ = evaluator_->NumParameters(); + num_effective_parameters_ = evaluator_->NumEffectiveParameters(); + num_residuals_ = evaluator_->NumResiduals(); + num_consecutive_invalid_steps_ = 0; + + x_ = ConstVectorRef(parameters_, num_parameters_); + x_norm_ = x_.norm(); + residuals_.resize(num_residuals_); + trust_region_step_.resize(num_effective_parameters_); + delta_.resize(num_effective_parameters_); + candidate_x_.resize(num_parameters_); + gradient_.resize(num_effective_parameters_); + model_residuals_.resize(num_residuals_); + negative_gradient_.resize(num_effective_parameters_); + projected_gradient_step_.resize(num_parameters_); + + // By default scaling is one, if the user requests Jacobi scaling of + // the Jacobian, we will compute and overwrite this vector. + jacobian_scaling_ = Vector::Ones(num_effective_parameters_); + + x_norm_ = -1; // Invalid value + x_cost_ = std::numeric_limits::max(); + minimum_cost_ = x_cost_; + model_cost_change_ = 0.0; +} + +// 1. Project the initial solution onto the feasible set if needed. +// 2. Compute the initial cost, jacobian & gradient. +// +// Return true if all computations can be performed successfully. +bool TrustRegionMinimizer::IterationZero() { + iteration_summary_ = IterationSummary(); + iteration_summary_.iteration = 0; + iteration_summary_.step_is_valid = false; + iteration_summary_.step_is_successful = false; + iteration_summary_.cost_change = 0.0; + iteration_summary_.gradient_max_norm = 0.0; + iteration_summary_.gradient_norm = 0.0; + iteration_summary_.step_norm = 0.0; + iteration_summary_.relative_decrease = 0.0; + iteration_summary_.eta = options_.eta; + iteration_summary_.linear_solver_iterations = 0; + iteration_summary_.step_solver_time_in_seconds = 0; + + if (options_.is_constrained) { + delta_.setZero(); + if (!evaluator_->Plus(x_.data(), delta_.data(), candidate_x_.data())) { + solver_summary_->message = + "Unable to project initial point onto the feasible set."; + solver_summary_->termination_type = FAILURE; + return false; + } + + x_ = candidate_x_; + x_norm_ = x_.norm(); + } + + if (!EvaluateGradientAndJacobian()) { + return false; + } + + solver_summary_->initial_cost = x_cost_ + solver_summary_->fixed_cost; + iteration_summary_.step_is_valid = true; + iteration_summary_.step_is_successful = true; + return true; +} + +// For the current x_, compute +// +// 1. Cost +// 2. Jacobian +// 3. Gradient +// 4. Scale the Jacobian if needed (and compute the scaling if we are +// in iteration zero). +// 5. Compute the 2 and max norm of the gradient. +// +// Returns true if all computations could be performed +// successfully. Any failures are considered fatal and the +// Solver::Summary is updated to indicate this. +bool TrustRegionMinimizer::EvaluateGradientAndJacobian() { + if (!evaluator_->Evaluate(x_.data(), + &x_cost_, + residuals_.data(), + gradient_.data(), + jacobian_)) { + solver_summary_->message = "Residual and Jacobian evaluation failed."; + solver_summary_->termination_type = FAILURE; + return false; + } + + iteration_summary_.cost = x_cost_ + solver_summary_->fixed_cost; + + if (options_.jacobi_scaling) { + if (iteration_summary_.iteration == 0) { + // Compute a scaling vector that is used to improve the + // conditioning of the Jacobian. + // + // jacobian_scaling_ = diag(J'J)^{-1} + jacobian_->SquaredColumnNorm(jacobian_scaling_.data()); + for (int i = 0; i < jacobian_->num_cols(); ++i) { + // Add one to the denominator to prevent division by zero. + jacobian_scaling_[i] = 1.0 / (1.0 + sqrt(jacobian_scaling_[i])); + } + } + + // jacobian = jacobian * diag(J'J) ^{-1} + jacobian_->ScaleColumns(jacobian_scaling_.data()); + } + + // The gradient exists in the local tangent space. To account for + // the bounds constraints correctly, instead of just computing the + // norm of the gradient vector, we compute + // + // |Plus(x, -gradient) - x| + // + // Where the Plus operator lifts the negative gradient to the + // ambient space, adds it to x and projects it on the hypercube + // defined by the bounds. + negative_gradient_ = -gradient_; + if (!evaluator_->Plus(x_.data(), + negative_gradient_.data(), + projected_gradient_step_.data())) { + solver_summary_->message = + "projected_gradient_step = Plus(x, -gradient) failed."; + solver_summary_->termination_type = FAILURE; + return false; + } + + iteration_summary_.gradient_max_norm = + (x_ - projected_gradient_step_).lpNorm(); + iteration_summary_.gradient_norm = (x_ - projected_gradient_step_).norm(); + return true; +} + +// 1. Add the final timing information to the iteration summary. +// 2. Run the callbacks +// 3. Check for termination based on +// a. Run time +// b. Iteration count +// c. Max norm of the gradient +// d. Size of the trust region radius. +// +// Returns true if user did not terminate the solver and none of these +// termination criterion are met. +bool TrustRegionMinimizer::FinalizeIterationAndCheckIfMinimizerCanContinue() { + if (iteration_summary_.step_is_successful) { + ++solver_summary_->num_successful_steps; + if (x_cost_ < minimum_cost_) { + minimum_cost_ = x_cost_; + VectorRef(parameters_, num_parameters_) = x_; + iteration_summary_.step_is_nonmonotonic = false; + } else { + iteration_summary_.step_is_nonmonotonic = true; + } + } else { + ++solver_summary_->num_unsuccessful_steps; + } + + iteration_summary_.trust_region_radius = strategy_->Radius(); + iteration_summary_.iteration_time_in_seconds = + WallTimeInSeconds() - iteration_start_time_in_secs_; + iteration_summary_.cumulative_time_in_seconds = + WallTimeInSeconds() - start_time_in_secs_ + + solver_summary_->preprocessor_time_in_seconds; + + solver_summary_->iterations.push_back(iteration_summary_); + + if (!RunCallbacks(options_, iteration_summary_, solver_summary_)) { + return false; + } + + if (MaxSolverTimeReached()) { + return false; + } + + if (MaxSolverIterationsReached()) { + return false; + } + + if (GradientToleranceReached()) { + return false; + } + + if (MinTrustRegionRadiusReached()) { + return false; + } + + return true; +} + +// Compute the trust region step using the TrustRegionStrategy chosen +// by the user. +// +// If the strategy returns with LINEAR_SOLVER_FATAL_ERROR, which +// indicates an unrecoverable error, return false. This is the only +// condition that returns false. +// +// If the strategy returns with LINEAR_SOLVER_FAILURE, which indicates +// a numerical failure that could be recovered from by retrying +// (e.g. by increasing the strength of the regularization), we set +// iteration_summary_.step_is_valid to false and return true. +// +// In all other cases, we compute the decrease in the trust region +// model problem. In exact arithmetic, this should always be +// positive, but due to numerical problems in the TrustRegionStrategy +// or round off error when computing the decrease it may be +// negative. In which case again, we set +// iteration_summary_.step_is_valid to false. +bool TrustRegionMinimizer::ComputeTrustRegionStep() { + const double strategy_start_time = WallTimeInSeconds(); + iteration_summary_.step_is_valid = false; + TrustRegionStrategy::PerSolveOptions per_solve_options; + per_solve_options.eta = options_.eta; + if (find(options_.trust_region_minimizer_iterations_to_dump.begin(), + options_.trust_region_minimizer_iterations_to_dump.end(), + iteration_summary_.iteration) != + options_.trust_region_minimizer_iterations_to_dump.end()) { + per_solve_options.dump_format_type = + options_.trust_region_problem_dump_format_type; + per_solve_options.dump_filename_base = + JoinPath(options_.trust_region_problem_dump_directory, + StringPrintf("ceres_solver_iteration_%03d", + iteration_summary_.iteration)); + } + + TrustRegionStrategy::Summary strategy_summary = + strategy_->ComputeStep(per_solve_options, + jacobian_, + residuals_.data(), + trust_region_step_.data()); + + if (strategy_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) { + solver_summary_->message = + "Linear solver failed due to unrecoverable " + "non-numeric causes. Please see the error log for clues. "; + solver_summary_->termination_type = FAILURE; + return false; + } + + iteration_summary_.step_solver_time_in_seconds = + WallTimeInSeconds() - strategy_start_time; + iteration_summary_.linear_solver_iterations = strategy_summary.num_iterations; + + if (strategy_summary.termination_type == LINEAR_SOLVER_FAILURE) { + return true; + } + + // new_model_cost + // = 1/2 [f + J * step]^2 + // = 1/2 [ f'f + 2f'J * step + step' * J' * J * step ] + // model_cost_change + // = cost - new_model_cost + // = f'f/2 - 1/2 [ f'f + 2f'J * step + step' * J' * J * step] + // = -f'J * step - step' * J' * J * step / 2 + // = -(J * step)'(f + J * step / 2) + model_residuals_.setZero(); + jacobian_->RightMultiply(trust_region_step_.data(), model_residuals_.data()); + model_cost_change_ = + -model_residuals_.dot(residuals_ + model_residuals_ / 2.0); + + // TODO(sameeragarwal) + // + // 1. What happens if model_cost_change_ = 0 + // 2. What happens if -epsilon <= model_cost_change_ < 0 for some + // small epsilon due to round off error. + iteration_summary_.step_is_valid = (model_cost_change_ > 0.0); + if (iteration_summary_.step_is_valid) { + // Undo the Jacobian column scaling. + delta_ = (trust_region_step_.array() * jacobian_scaling_.array()).matrix(); + num_consecutive_invalid_steps_ = 0; + } + + VLOG_IF(1, is_not_silent_ && !iteration_summary_.step_is_valid) + << "Invalid step: current_cost: " << x_cost_ + << " absolute model cost change: " << model_cost_change_ + << " relative model cost change: " << (model_cost_change_ / x_cost_); + return true; +} + +// Invalid steps can happen due to a number of reasons, and we allow a +// limited number of consecutive failures, and return false if this +// limit is exceeded. +bool TrustRegionMinimizer::HandleInvalidStep() { + // TODO(sameeragarwal): Should we be returning FAILURE or + // NO_CONVERGENCE? The solution value is still usable in many cases, + // it is not clear if we should declare the solver a failure + // entirely. For example the case where model_cost_change ~ 0.0, but + // just slightly negative. + if (++num_consecutive_invalid_steps_ >= + options_.max_num_consecutive_invalid_steps) { + solver_summary_->message = StringPrintf( + "Number of consecutive invalid steps more " + "than Solver::Options::max_num_consecutive_invalid_steps: %d", + options_.max_num_consecutive_invalid_steps); + solver_summary_->termination_type = FAILURE; + return false; + } + + strategy_->StepIsInvalid(); + + // We are going to try and reduce the trust region radius and + // solve again. To do this, we are going to treat this iteration + // as an unsuccessful iteration. Since the various callbacks are + // still executed, we are going to fill the iteration summary + // with data that assumes a step of length zero and no progress. + iteration_summary_.cost = x_cost_ + solver_summary_->fixed_cost; + iteration_summary_.cost_change = 0.0; + iteration_summary_.gradient_max_norm = + solver_summary_->iterations.back().gradient_max_norm; + iteration_summary_.gradient_norm = + solver_summary_->iterations.back().gradient_norm; + iteration_summary_.step_norm = 0.0; + iteration_summary_.relative_decrease = 0.0; + iteration_summary_.eta = options_.eta; + return true; +} + +// Use the supplied coordinate descent minimizer to perform inner +// iterations and compute the improvement due to it. Returns the cost +// after performing the inner iterations. +// +// The optimization is performed with candidate_x_ as the starting +// point, and if the optimization is successful, candidate_x_ will be +// updated with the optimized parameters. +void TrustRegionMinimizer::DoInnerIterationsIfNeeded() { + inner_iterations_were_useful_ = false; + if (!inner_iterations_are_enabled_ || + candidate_cost_ >= std::numeric_limits::max()) { + return; + } + + double inner_iteration_start_time = WallTimeInSeconds(); + ++solver_summary_->num_inner_iteration_steps; + inner_iteration_x_ = candidate_x_; + Solver::Summary inner_iteration_summary; + options_.inner_iteration_minimizer->Minimize( + options_, inner_iteration_x_.data(), &inner_iteration_summary); + double inner_iteration_cost; + if (!evaluator_->Evaluate( + inner_iteration_x_.data(), &inner_iteration_cost, NULL, NULL, NULL)) { + VLOG_IF(2, is_not_silent_) << "Inner iteration failed."; + return; + } + + VLOG_IF(2, is_not_silent_) + << "Inner iteration succeeded; Current cost: " << x_cost_ + << " Trust region step cost: " << candidate_cost_ + << " Inner iteration cost: " << inner_iteration_cost; + + candidate_x_ = inner_iteration_x_; + + // Normally, the quality of a trust region step is measured by + // the ratio + // + // cost_change + // r = ----------------- + // model_cost_change + // + // All the change in the nonlinear objective is due to the trust + // region step so this ratio is a good measure of the quality of + // the trust region radius. However, when inner iterations are + // being used, cost_change includes the contribution of the + // inner iterations and its not fair to credit it all to the + // trust region algorithm. So we change the ratio to be + // + // cost_change + // r = ------------------------------------------------ + // (model_cost_change + inner_iteration_cost_change) + // + // Practically we do this by increasing model_cost_change by + // inner_iteration_cost_change. + + const double inner_iteration_cost_change = + candidate_cost_ - inner_iteration_cost; + model_cost_change_ += inner_iteration_cost_change; + inner_iterations_were_useful_ = inner_iteration_cost < x_cost_; + const double inner_iteration_relative_progress = + 1.0 - inner_iteration_cost / candidate_cost_; + + // Disable inner iterations once the relative improvement + // drops below tolerance. + inner_iterations_are_enabled_ = + (inner_iteration_relative_progress > options_.inner_iteration_tolerance); + VLOG_IF(2, is_not_silent_ && !inner_iterations_are_enabled_) + << "Disabling inner iterations. Progress : " + << inner_iteration_relative_progress; + candidate_cost_ = inner_iteration_cost; + + solver_summary_->inner_iteration_time_in_seconds += + WallTimeInSeconds() - inner_iteration_start_time; +} + +// Perform a projected line search to improve the objective function +// value along delta. +// +// TODO(sameeragarwal): The current implementation does not do +// anything illegal but is incorrect and not terribly effective. +// +// https://github.com/ceres-solver/ceres-solver/issues/187 +void TrustRegionMinimizer::DoLineSearch(const Vector& x, + const Vector& gradient, + const double cost, + Vector* delta) { + LineSearchFunction line_search_function(evaluator_); LineSearch::Options line_search_options; line_search_options.is_silent = true; line_search_options.interpolation_type = - options.line_search_interpolation_type; - line_search_options.min_step_size = options.min_line_search_step_size; + options_.line_search_interpolation_type; + line_search_options.min_step_size = options_.min_line_search_step_size; line_search_options.sufficient_decrease = - options.line_search_sufficient_function_decrease; + options_.line_search_sufficient_function_decrease; line_search_options.max_step_contraction = - options.max_line_search_step_contraction; + options_.max_line_search_step_contraction; line_search_options.min_step_contraction = - options.min_line_search_step_contraction; + options_.min_line_search_step_contraction; line_search_options.max_num_iterations = - options.max_num_line_search_step_size_iterations; + options_.max_num_line_search_step_size_iterations; line_search_options.sufficient_curvature_decrease = - options.line_search_sufficient_curvature_decrease; + options_.line_search_sufficient_curvature_decrease; line_search_options.max_step_expansion = - options.max_line_search_step_expansion; + options_.max_line_search_step_expansion; line_search_options.function = &line_search_function; std::string message; - scoped_ptr line_search( - CHECK_NOTNULL(LineSearch::Create(ceres::ARMIJO, - line_search_options, - &message))); - LineSearch::Summary summary; - line_search_function.Init(x, delta); - line_search->Search(1.0, cost, gradient.dot(delta), &summary); - return summary; -} + scoped_ptr line_search(CHECK_NOTNULL( + LineSearch::Create(ceres::ARMIJO, line_search_options, &message))); + LineSearch::Summary line_search_summary; + line_search_function.Init(x, *delta); + line_search->Search(1.0, cost, gradient.dot(*delta), &line_search_summary); -} // namespace + solver_summary_->num_line_search_steps += line_search_summary.num_iterations; + solver_summary_->line_search_cost_evaluation_time_in_seconds += + line_search_summary.cost_evaluation_time_in_seconds; + solver_summary_->line_search_gradient_evaluation_time_in_seconds += + line_search_summary.gradient_evaluation_time_in_seconds; + solver_summary_->line_search_polynomial_minimization_time_in_seconds += + line_search_summary.polynomial_minimization_time_in_seconds; + solver_summary_->line_search_total_time_in_seconds += + line_search_summary.total_time_in_seconds; -// Compute a scaling vector that is used to improve the conditioning -// of the Jacobian. -void TrustRegionMinimizer::EstimateScale(const SparseMatrix& jacobian, - double* scale) const { - jacobian.SquaredColumnNorm(scale); - for (int i = 0; i < jacobian.num_cols(); ++i) { - scale[i] = 1.0 / (1.0 + sqrt(scale[i])); + if (line_search_summary.success) { + *delta *= line_search_summary.optimal_step_size; } } -void TrustRegionMinimizer::Init(const Minimizer::Options& options) { - options_ = options; - sort(options_.trust_region_minimizer_iterations_to_dump.begin(), - options_.trust_region_minimizer_iterations_to_dump.end()); +// Check if the maximum amount of time allowed by the user for the +// solver has been exceeded, and if so return false after updating +// Solver::Summary::message. +bool TrustRegionMinimizer::MaxSolverTimeReached() { + const double total_solver_time = + WallTimeInSeconds() - start_time_in_secs_ + + solver_summary_->preprocessor_time_in_seconds; + if (total_solver_time < options_.max_solver_time_in_seconds) { + return false; + } + + solver_summary_->message = StringPrintf("Maximum solver time reached. " + "Total solver time: %e >= %e.", + total_solver_time, + options_.max_solver_time_in_seconds); + solver_summary_->termination_type = NO_CONVERGENCE; + VLOG_IF(1, is_not_silent_) << "Terminating: " << solver_summary_->message; + return true; } -void TrustRegionMinimizer::Minimize(const Minimizer::Options& options, - double* parameters, - Solver::Summary* summary) { - double start_time = WallTimeInSeconds(); - double iteration_start_time = start_time; - Init(options); +// Check if the maximum number of iterations allowed by the user for +// the solver has been exceeded, and if so return false after updating +// Solver::Summary::message. +bool TrustRegionMinimizer::MaxSolverIterationsReached() { + if (iteration_summary_.iteration < options_.max_num_iterations) { + return false; + } - Evaluator* evaluator = CHECK_NOTNULL(options_.evaluator.get()); - SparseMatrix* jacobian = CHECK_NOTNULL(options_.jacobian.get()); - TrustRegionStrategy* strategy = - CHECK_NOTNULL(options_.trust_region_strategy.get()); + solver_summary_->message = + StringPrintf("Maximum number of iterations reached. " + "Number of iterations: %d.", + iteration_summary_.iteration); - const bool is_not_silent = !options.is_silent; + solver_summary_->termination_type = NO_CONVERGENCE; + VLOG_IF(1, is_not_silent_) << "Terminating: " << solver_summary_->message; + return true; +} - // If the problem is bounds constrained, then enable the use of a - // line search after the trust region step has been computed. This - // line search will automatically use a projected test point onto - // the feasible set, there by guaranteeing the feasibility of the - // final output. +// Check convergence based on the max norm of the gradient (only for +// iterations where the step was declared successful). +bool TrustRegionMinimizer::GradientToleranceReached() { + if (!iteration_summary_.step_is_successful || + iteration_summary_.gradient_max_norm > options_.gradient_tolerance) { + return false; + } + + solver_summary_->message = StringPrintf( + "Gradient tolerance reached. " + "Gradient max norm: %e <= %e", + iteration_summary_.gradient_max_norm, + options_.gradient_tolerance); + solver_summary_->termination_type = CONVERGENCE; + VLOG_IF(1, is_not_silent_) << "Terminating: " << solver_summary_->message; + return true; +} + +// Check convergence based the size of the trust region radius. +bool TrustRegionMinimizer::MinTrustRegionRadiusReached() { + if (iteration_summary_.trust_region_radius > + options_.min_trust_region_radius) { + return false; + } + + solver_summary_->message = + StringPrintf("Minimum trust region radius reached. " + "Trust region radius: %e <= %e", + iteration_summary_.trust_region_radius, + options_.min_trust_region_radius); + solver_summary_->termination_type = CONVERGENCE; + VLOG_IF(1, is_not_silent_) << "Terminating: " << solver_summary_->message; + return true; +} + +// Solver::Options::parameter_tolerance based convergence check. +bool TrustRegionMinimizer::ParameterToleranceReached() { + // Compute the norm of the step in the ambient space. + iteration_summary_.step_norm = (x_ - candidate_x_).norm(); + const double step_size_tolerance = + options_.parameter_tolerance * (x_norm_ + options_.parameter_tolerance); + + if (iteration_summary_.step_norm > step_size_tolerance) { + return false; + } + + solver_summary_->message = StringPrintf( + "Parameter tolerance reached. " + "Relative step_norm: %e <= %e.", + (iteration_summary_.step_norm / (x_norm_ + options_.parameter_tolerance)), + options_.parameter_tolerance); + solver_summary_->termination_type = CONVERGENCE; + VLOG_IF(1, is_not_silent_) << "Terminating: " << solver_summary_->message; + return true; +} + +// Solver::Options::function_tolerance based convergence check. +bool TrustRegionMinimizer::FunctionToleranceReached() { + iteration_summary_.cost_change = x_cost_ - candidate_cost_; + const double absolute_function_tolerance = + options_.function_tolerance * x_cost_; + + if (fabs(iteration_summary_.cost_change) > absolute_function_tolerance) { + return false; + } + + solver_summary_->message = StringPrintf( + "Function tolerance reached. " + "|cost_change|/cost: %e <= %e", + fabs(iteration_summary_.cost_change) / x_cost_, + options_.function_tolerance); + solver_summary_->termination_type = CONVERGENCE; + VLOG_IF(1, is_not_silent_) << "Terminating: " << solver_summary_->message; + return true; +} + +// Compute candidate_x_ = Plus(x_, delta_) +// Evaluate the cost of candidate_x_ as candidate_cost_. +// +// Failure to compute the step or the cost mean that candidate_cost_ +// is set to std::numeric_limits::max(). Unlike +// EvaluateGradientAndJacobian, failure in this function is not fatal +// as we are only computing and evaluating a candidate point, and if +// for some reason we are unable to evaluate it, we consider it to be +// a point with very high cost. This allows the user to deal with edge +// cases/constraints as part of the LocalParameterization and +// CostFunction objects. +void TrustRegionMinimizer::ComputeCandidatePointAndEvaluateCost() { + if (!evaluator_->Plus(x_.data(), delta_.data(), candidate_x_.data())) { + LOG_IF(WARNING, is_not_silent_) + << "x_plus_delta = Plus(x, delta) failed. " + << "Treating it as a step with infinite cost"; + candidate_cost_ = std::numeric_limits::max(); + return; + } + + if (!evaluator_->Evaluate( + candidate_x_.data(), &candidate_cost_, NULL, NULL, NULL)) { + LOG_IF(WARNING, is_not_silent_) + << "Step failed to evaluate. " + << "Treating it as a step with infinite cost"; + candidate_cost_ = std::numeric_limits::max(); + } +} + +bool TrustRegionMinimizer::IsStepSuccessful() { + iteration_summary_.relative_decrease = + step_evaluator_->StepQuality(candidate_cost_, model_cost_change_); + + // In most cases, boosting the model_cost_change by the + // improvement caused by the inner iterations is fine, but it can + // be the case that the original trust region step was so bad that + // the resulting improvement in the cost was negative, and the + // change caused by the inner iterations was large enough to + // improve the step, but also to make relative decrease quite + // small. // - // TODO(sameeragarwal): Make line search available more generally. - const bool use_line_search = options.is_constrained; - - summary->termination_type = NO_CONVERGENCE; - summary->num_successful_steps = 0; - summary->num_unsuccessful_steps = 0; - summary->is_constrained = options.is_constrained; - - const int num_parameters = evaluator->NumParameters(); - const int num_effective_parameters = evaluator->NumEffectiveParameters(); - const int num_residuals = evaluator->NumResiduals(); - - Vector residuals(num_residuals); - Vector trust_region_step(num_effective_parameters); - Vector delta(num_effective_parameters); - Vector x_plus_delta(num_parameters); - Vector gradient(num_effective_parameters); - Vector model_residuals(num_residuals); - Vector scale(num_effective_parameters); - Vector negative_gradient(num_effective_parameters); - Vector projected_gradient_step(num_parameters); - - IterationSummary iteration_summary; - iteration_summary.iteration = 0; - iteration_summary.step_is_valid = false; - iteration_summary.step_is_successful = false; - iteration_summary.cost_change = 0.0; - iteration_summary.gradient_max_norm = 0.0; - iteration_summary.gradient_norm = 0.0; - iteration_summary.step_norm = 0.0; - iteration_summary.relative_decrease = 0.0; - iteration_summary.trust_region_radius = strategy->Radius(); - iteration_summary.eta = options_.eta; - iteration_summary.linear_solver_iterations = 0; - iteration_summary.step_solver_time_in_seconds = 0; - - VectorRef x_min(parameters, num_parameters); - Vector x = x_min; - // Project onto the feasible set. - if (options.is_constrained) { - delta.setZero(); - if (!evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) { - summary->message = - "Unable to project initial point onto the feasible set."; - summary->termination_type = FAILURE; - LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message; - return; - } - x_min = x_plus_delta; - x = x_plus_delta; - } - - double x_norm = x.norm(); - - // Do initial cost and Jacobian evaluation. - double cost = 0.0; - if (!evaluator->Evaluate(x.data(), - &cost, - residuals.data(), - gradient.data(), - jacobian)) { - summary->message = "Residual and Jacobian evaluation failed."; - summary->termination_type = FAILURE; - LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message; - return; - } - - negative_gradient = -gradient; - if (!evaluator->Plus(x.data(), - negative_gradient.data(), - projected_gradient_step.data())) { - summary->message = "Unable to compute gradient step."; - summary->termination_type = FAILURE; - LOG(ERROR) << "Terminating: " << summary->message; - return; - } - - summary->initial_cost = cost + summary->fixed_cost; - iteration_summary.cost = cost + summary->fixed_cost; - iteration_summary.gradient_max_norm = - (x - projected_gradient_step).lpNorm(); - iteration_summary.gradient_norm = (x - projected_gradient_step).norm(); - - if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) { - summary->message = StringPrintf("Gradient tolerance reached. " - "Gradient max norm: %e <= %e", - iteration_summary.gradient_max_norm, - options_.gradient_tolerance); - summary->termination_type = CONVERGENCE; - VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message; - - // Ensure that there is an iteration summary object for iteration - // 0 in Summary::iterations. - iteration_summary.iteration_time_in_seconds = - WallTimeInSeconds() - iteration_start_time; - iteration_summary.cumulative_time_in_seconds = - WallTimeInSeconds() - start_time + - summary->preprocessor_time_in_seconds; - summary->iterations.push_back(iteration_summary); - return; - } - - if (options_.jacobi_scaling) { - EstimateScale(*jacobian, scale.data()); - jacobian->ScaleColumns(scale.data()); - } else { - scale.setOnes(); - } - - iteration_summary.iteration_time_in_seconds = - WallTimeInSeconds() - iteration_start_time; - iteration_summary.cumulative_time_in_seconds = - WallTimeInSeconds() - start_time - + summary->preprocessor_time_in_seconds; - summary->iterations.push_back(iteration_summary); - - int num_consecutive_nonmonotonic_steps = 0; - double minimum_cost = cost; - double reference_cost = cost; - double accumulated_reference_model_cost_change = 0.0; - double candidate_cost = cost; - double accumulated_candidate_model_cost_change = 0.0; - int num_consecutive_invalid_steps = 0; - bool inner_iterations_are_enabled = - options.inner_iteration_minimizer.get() != NULL; - while (true) { - bool inner_iterations_were_useful = false; - if (!RunCallbacks(options, iteration_summary, summary)) { - return; - } - - iteration_start_time = WallTimeInSeconds(); - if (iteration_summary.iteration >= options_.max_num_iterations) { - summary->message = "Maximum number of iterations reached."; - summary->termination_type = NO_CONVERGENCE; - VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message; - return; - } - - const double total_solver_time = iteration_start_time - start_time + - summary->preprocessor_time_in_seconds; - if (total_solver_time >= options_.max_solver_time_in_seconds) { - summary->message = "Maximum solver time reached."; - summary->termination_type = NO_CONVERGENCE; - VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message; - return; - } - - const double strategy_start_time = WallTimeInSeconds(); - TrustRegionStrategy::PerSolveOptions per_solve_options; - per_solve_options.eta = options_.eta; - if (find(options_.trust_region_minimizer_iterations_to_dump.begin(), - options_.trust_region_minimizer_iterations_to_dump.end(), - iteration_summary.iteration) != - options_.trust_region_minimizer_iterations_to_dump.end()) { - per_solve_options.dump_format_type = - options_.trust_region_problem_dump_format_type; - per_solve_options.dump_filename_base = - JoinPath(options_.trust_region_problem_dump_directory, - StringPrintf("ceres_solver_iteration_%03d", - iteration_summary.iteration)); - } else { - per_solve_options.dump_format_type = TEXTFILE; - per_solve_options.dump_filename_base.clear(); - } - - TrustRegionStrategy::Summary strategy_summary = - strategy->ComputeStep(per_solve_options, - jacobian, - residuals.data(), - trust_region_step.data()); - - if (strategy_summary.termination_type == LINEAR_SOLVER_FATAL_ERROR) { - summary->message = - "Linear solver failed due to unrecoverable " - "non-numeric causes. Please see the error log for clues. "; - summary->termination_type = FAILURE; - LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message; - return; - } - - iteration_summary = IterationSummary(); - iteration_summary.iteration = summary->iterations.back().iteration + 1; - iteration_summary.step_solver_time_in_seconds = - WallTimeInSeconds() - strategy_start_time; - iteration_summary.linear_solver_iterations = - strategy_summary.num_iterations; - iteration_summary.step_is_valid = false; - iteration_summary.step_is_successful = false; - - double model_cost_change = 0.0; - if (strategy_summary.termination_type != LINEAR_SOLVER_FAILURE) { - // new_model_cost - // = 1/2 [f + J * step]^2 - // = 1/2 [ f'f + 2f'J * step + step' * J' * J * step ] - // model_cost_change - // = cost - new_model_cost - // = f'f/2 - 1/2 [ f'f + 2f'J * step + step' * J' * J * step] - // = -f'J * step - step' * J' * J * step / 2 - model_residuals.setZero(); - jacobian->RightMultiply(trust_region_step.data(), model_residuals.data()); - model_cost_change = - - model_residuals.dot(residuals + model_residuals / 2.0); - - if (model_cost_change < 0.0) { - VLOG_IF(1, is_not_silent) - << "Invalid step: current_cost: " << cost - << " absolute difference " << model_cost_change - << " relative difference " << (model_cost_change / cost); - } else { - iteration_summary.step_is_valid = true; - } - } - - if (!iteration_summary.step_is_valid) { - // Invalid steps can happen due to a number of reasons, and we - // allow a limited number of successive failures, and return with - // FAILURE if this limit is exceeded. - if (++num_consecutive_invalid_steps >= - options_.max_num_consecutive_invalid_steps) { - summary->message = StringPrintf( - "Number of successive invalid steps more " - "than Solver::Options::max_num_consecutive_invalid_steps: %d", - options_.max_num_consecutive_invalid_steps); - summary->termination_type = FAILURE; - LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message; - return; - } - - // We are going to try and reduce the trust region radius and - // solve again. To do this, we are going to treat this iteration - // as an unsuccessful iteration. Since the various callbacks are - // still executed, we are going to fill the iteration summary - // with data that assumes a step of length zero and no progress. - iteration_summary.cost = cost + summary->fixed_cost; - iteration_summary.cost_change = 0.0; - iteration_summary.gradient_max_norm = - summary->iterations.back().gradient_max_norm; - iteration_summary.gradient_norm = - summary->iterations.back().gradient_norm; - iteration_summary.step_norm = 0.0; - iteration_summary.relative_decrease = 0.0; - iteration_summary.eta = options_.eta; - } else { - // The step is numerically valid, so now we can judge its quality. - num_consecutive_invalid_steps = 0; - - // Undo the Jacobian column scaling. - delta = (trust_region_step.array() * scale.array()).matrix(); - - // Try improving the step further by using an ARMIJO line - // search. - // - // TODO(sameeragarwal): What happens to trust region sizing as - // it interacts with the line search ? - if (use_line_search) { - const LineSearch::Summary line_search_summary = - DoLineSearch(options, x, gradient, cost, delta, evaluator); - - summary->line_search_cost_evaluation_time_in_seconds += - line_search_summary.cost_evaluation_time_in_seconds; - summary->line_search_gradient_evaluation_time_in_seconds += - line_search_summary.gradient_evaluation_time_in_seconds; - summary->line_search_polynomial_minimization_time_in_seconds += - line_search_summary.polynomial_minimization_time_in_seconds; - summary->line_search_total_time_in_seconds += - line_search_summary.total_time_in_seconds; - - if (line_search_summary.success) { - delta *= line_search_summary.optimal_step_size; - } - } - - double new_cost = std::numeric_limits::max(); - if (evaluator->Plus(x.data(), delta.data(), x_plus_delta.data())) { - if (!evaluator->Evaluate(x_plus_delta.data(), - &new_cost, - NULL, - NULL, - NULL)) { - LOG_IF(WARNING, is_not_silent) - << "Step failed to evaluate. " - << "Treating it as a step with infinite cost"; - new_cost = std::numeric_limits::max(); - } - } else { - LOG_IF(WARNING, is_not_silent) - << "x_plus_delta = Plus(x, delta) failed. " - << "Treating it as a step with infinite cost"; - } - - if (new_cost < std::numeric_limits::max()) { - // Check if performing an inner iteration will make it better. - if (inner_iterations_are_enabled) { - ++summary->num_inner_iteration_steps; - double inner_iteration_start_time = WallTimeInSeconds(); - const double x_plus_delta_cost = new_cost; - Vector inner_iteration_x = x_plus_delta; - Solver::Summary inner_iteration_summary; - options.inner_iteration_minimizer->Minimize(options, - inner_iteration_x.data(), - &inner_iteration_summary); - if (!evaluator->Evaluate(inner_iteration_x.data(), - &new_cost, - NULL, NULL, NULL)) { - VLOG_IF(2, is_not_silent) << "Inner iteration failed."; - new_cost = x_plus_delta_cost; - } else { - x_plus_delta = inner_iteration_x; - // Boost the model_cost_change, since the inner iteration - // improvements are not accounted for by the trust region. - model_cost_change += x_plus_delta_cost - new_cost; - VLOG_IF(2, is_not_silent) - << "Inner iteration succeeded; Current cost: " << cost - << " Trust region step cost: " << x_plus_delta_cost - << " Inner iteration cost: " << new_cost; - - inner_iterations_were_useful = new_cost < cost; - - const double inner_iteration_relative_progress = - 1.0 - new_cost / x_plus_delta_cost; - // Disable inner iterations once the relative improvement - // drops below tolerance. - inner_iterations_are_enabled = - (inner_iteration_relative_progress > - options.inner_iteration_tolerance); - VLOG_IF(2, is_not_silent && !inner_iterations_are_enabled) - << "Disabling inner iterations. Progress : " - << inner_iteration_relative_progress; - } - summary->inner_iteration_time_in_seconds += - WallTimeInSeconds() - inner_iteration_start_time; - } - } - - iteration_summary.step_norm = (x - x_plus_delta).norm(); - - // Convergence based on parameter_tolerance. - const double step_size_tolerance = options_.parameter_tolerance * - (x_norm + options_.parameter_tolerance); - if (iteration_summary.step_norm <= step_size_tolerance) { - summary->message = - StringPrintf("Parameter tolerance reached. " - "Relative step_norm: %e <= %e.", - (iteration_summary.step_norm / - (x_norm + options_.parameter_tolerance)), - options_.parameter_tolerance); - summary->termination_type = CONVERGENCE; - VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message; - return; - } - - iteration_summary.cost_change = cost - new_cost; - const double absolute_function_tolerance = - options_.function_tolerance * cost; - if (fabs(iteration_summary.cost_change) <= absolute_function_tolerance) { - summary->message = - StringPrintf("Function tolerance reached. " - "|cost_change|/cost: %e <= %e", - fabs(iteration_summary.cost_change) / cost, - options_.function_tolerance); - summary->termination_type = CONVERGENCE; - VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message; - return; - } - - const double relative_decrease = - iteration_summary.cost_change / model_cost_change; - - const double historical_relative_decrease = - (reference_cost - new_cost) / - (accumulated_reference_model_cost_change + model_cost_change); - - // If monotonic steps are being used, then the relative_decrease - // is the usual ratio of the change in objective function value - // divided by the change in model cost. - // - // If non-monotonic steps are allowed, then we take the maximum - // of the relative_decrease and the - // historical_relative_decrease, which measures the increase - // from a reference iteration. The model cost change is - // estimated by accumulating the model cost changes since the - // reference iteration. The historical relative_decrease offers - // a boost to a step which is not too bad compared to the - // reference iteration, allowing for non-monotonic steps. - iteration_summary.relative_decrease = - options.use_nonmonotonic_steps - ? std::max(relative_decrease, historical_relative_decrease) - : relative_decrease; - - // Normally, the quality of a trust region step is measured by - // the ratio - // - // cost_change - // r = ----------------- - // model_cost_change - // - // All the change in the nonlinear objective is due to the trust - // region step so this ratio is a good measure of the quality of - // the trust region radius. However, when inner iterations are - // being used, cost_change includes the contribution of the - // inner iterations and its not fair to credit it all to the - // trust region algorithm. So we change the ratio to be - // - // cost_change - // r = ------------------------------------------------ - // (model_cost_change + inner_iteration_cost_change) - // - // In most cases this is fine, but it can be the case that the - // change in solution quality due to inner iterations is so large - // and the trust region step is so bad, that this ratio can become - // quite small. - // - // This can cause the trust region loop to reject this step. To - // get around this, we expicitly check if the inner iterations - // led to a net decrease in the objective function value. If - // they did, we accept the step even if the trust region ratio - // is small. - // - // Notice that we do not just check that cost_change is positive - // which is a weaker condition and would render the - // min_relative_decrease threshold useless. Instead, we keep - // track of inner_iterations_were_useful, which is true only - // when inner iterations lead to a net decrease in the cost. - iteration_summary.step_is_successful = - (inner_iterations_were_useful || - iteration_summary.relative_decrease > - options_.min_relative_decrease); - - if (iteration_summary.step_is_successful) { - accumulated_candidate_model_cost_change += model_cost_change; - accumulated_reference_model_cost_change += model_cost_change; - - if (!inner_iterations_were_useful && - relative_decrease <= options_.min_relative_decrease) { - iteration_summary.step_is_nonmonotonic = true; - VLOG_IF(2, is_not_silent) - << "Non-monotonic step! " - << " relative_decrease: " - << relative_decrease - << " historical_relative_decrease: " - << historical_relative_decrease; - } - } - } - - if (iteration_summary.step_is_successful) { - ++summary->num_successful_steps; - strategy->StepAccepted(iteration_summary.relative_decrease); - - x = x_plus_delta; - x_norm = x.norm(); - - // Step looks good, evaluate the residuals and Jacobian at this - // point. - if (!evaluator->Evaluate(x.data(), - &cost, - residuals.data(), - gradient.data(), - jacobian)) { - summary->message = "Residual and Jacobian evaluation failed."; - summary->termination_type = FAILURE; - LOG_IF(WARNING, is_not_silent) << "Terminating: " << summary->message; - return; - } - - negative_gradient = -gradient; - if (!evaluator->Plus(x.data(), - negative_gradient.data(), - projected_gradient_step.data())) { - summary->message = - "projected_gradient_step = Plus(x, -gradient) failed."; - summary->termination_type = FAILURE; - LOG(ERROR) << "Terminating: " << summary->message; - return; - } - - iteration_summary.gradient_max_norm = - (x - projected_gradient_step).lpNorm(); - iteration_summary.gradient_norm = (x - projected_gradient_step).norm(); - - if (options_.jacobi_scaling) { - jacobian->ScaleColumns(scale.data()); - } - - // Update the best, reference and candidate iterates. - // - // Based on algorithm 10.1.2 (page 357) of "Trust Region - // Methods" by Conn Gould & Toint, or equations 33-40 of - // "Non-monotone trust-region algorithms for nonlinear - // optimization subject to convex constraints" by Phil Toint, - // Mathematical Programming, 77, 1997. - if (cost < minimum_cost) { - // A step that improves solution quality was found. - x_min = x; - minimum_cost = cost; - // Set the candidate iterate to the current point. - candidate_cost = cost; - num_consecutive_nonmonotonic_steps = 0; - accumulated_candidate_model_cost_change = 0.0; - } else { - ++num_consecutive_nonmonotonic_steps; - if (cost > candidate_cost) { - // The current iterate is has a higher cost than the - // candidate iterate. Set the candidate to this point. - VLOG_IF(2, is_not_silent) - << "Updating the candidate iterate to the current point."; - candidate_cost = cost; - accumulated_candidate_model_cost_change = 0.0; - } - - // At this point we have made too many non-monotonic steps and - // we are going to reset the value of the reference iterate so - // as to force the algorithm to descend. - // - // This is the case because the candidate iterate has a value - // greater than minimum_cost but smaller than the reference - // iterate. - if (num_consecutive_nonmonotonic_steps == - options.max_consecutive_nonmonotonic_steps) { - VLOG_IF(2, is_not_silent) - << "Resetting the reference point to the candidate point"; - reference_cost = candidate_cost; - accumulated_reference_model_cost_change = - accumulated_candidate_model_cost_change; - } - } - } else { - ++summary->num_unsuccessful_steps; - if (iteration_summary.step_is_valid) { - strategy->StepRejected(iteration_summary.relative_decrease); - } else { - strategy->StepIsInvalid(); - } - } - - iteration_summary.cost = cost + summary->fixed_cost; - iteration_summary.trust_region_radius = strategy->Radius(); - iteration_summary.iteration_time_in_seconds = - WallTimeInSeconds() - iteration_start_time; - iteration_summary.cumulative_time_in_seconds = - WallTimeInSeconds() - start_time - + summary->preprocessor_time_in_seconds; - summary->iterations.push_back(iteration_summary); - - // If the step was successful, check for the gradient norm - // collapsing to zero, and if the step is unsuccessful then check - // if the trust region radius has collapsed to zero. - // - // For correctness (Number of IterationSummary objects, correct - // final cost, and state update) these convergence tests need to - // be performed at the end of the iteration. - if (iteration_summary.step_is_successful) { - // Gradient norm can only go down in successful steps. - if (iteration_summary.gradient_max_norm <= options.gradient_tolerance) { - summary->message = StringPrintf("Gradient tolerance reached. " - "Gradient max norm: %e <= %e", - iteration_summary.gradient_max_norm, - options_.gradient_tolerance); - summary->termination_type = CONVERGENCE; - VLOG_IF(1, is_not_silent) << "Terminating: " << summary->message; - return; - } - } else { - // Trust region radius can only go down if the step if - // unsuccessful. - if (iteration_summary.trust_region_radius < - options_.min_trust_region_radius) { - summary->message = "Termination. Minimum trust region radius reached."; - summary->termination_type = CONVERGENCE; - VLOG_IF(1, is_not_silent) << summary->message; - return; - } - } - } + // This can cause the trust region loop to reject this step. To + // get around this, we expicitly check if the inner iterations + // led to a net decrease in the objective function value. If + // they did, we accept the step even if the trust region ratio + // is small. + // + // Notice that we do not just check that cost_change is positive + // which is a weaker condition and would render the + // min_relative_decrease threshold useless. Instead, we keep + // track of inner_iterations_were_useful, which is true only + // when inner iterations lead to a net decrease in the cost. + return (inner_iterations_were_useful_ || + iteration_summary_.relative_decrease > + options_.min_relative_decrease); } +// Declare the step successful, move to candidate_x, update the +// derivatives and let the trust region strategy and the step +// evaluator know that the step has been accepted. +bool TrustRegionMinimizer::HandleSuccessfulStep() { + x_ = candidate_x_; + x_norm_ = x_.norm(); + + if (!EvaluateGradientAndJacobian()) { + return false; + } + + iteration_summary_.step_is_successful = true; + strategy_->StepAccepted(iteration_summary_.relative_decrease); + step_evaluator_->StepAccepted(candidate_cost_, model_cost_change_); + return true; +} + +// Declare the step unsuccessful and inform the trust region strategy. +void TrustRegionMinimizer::HandleUnsuccessfulStep() { + iteration_summary_.step_is_successful = false; + strategy_->StepRejected(iteration_summary_.relative_decrease); + iteration_summary_.cost = candidate_cost_ + solver_summary_->fixed_cost; +} } // namespace internal } // namespace ceres diff --git a/extern/ceres/internal/ceres/trust_region_minimizer.h b/extern/ceres/internal/ceres/trust_region_minimizer.h index ed52c2642d1..43141da58a1 100644 --- a/extern/ceres/internal/ceres/trust_region_minimizer.h +++ b/extern/ceres/internal/ceres/trust_region_minimizer.h @@ -1,5 +1,5 @@ // Ceres Solver - A fast non-linear least squares minimizer -// Copyright 2015 Google Inc. All rights reserved. +// Copyright 2016 Google Inc. All rights reserved. // http://ceres-solver.org/ // // Redistribution and use in source and binary forms, with or without @@ -31,35 +31,136 @@ #ifndef CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_ #define CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_ +#include "ceres/internal/eigen.h" +#include "ceres/internal/scoped_ptr.h" #include "ceres/minimizer.h" #include "ceres/solver.h" +#include "ceres/sparse_matrix.h" +#include "ceres/trust_region_step_evaluator.h" +#include "ceres/trust_region_strategy.h" #include "ceres/types.h" namespace ceres { namespace internal { -// Generic trust region minimization algorithm. The heavy lifting is -// done by a TrustRegionStrategy object passed in as part of options. +// Generic trust region minimization algorithm. // // For example usage, see SolverImpl::Minimize. class TrustRegionMinimizer : public Minimizer { public: - ~TrustRegionMinimizer() {} + ~TrustRegionMinimizer(); + + // This method is not thread safe. virtual void Minimize(const Minimizer::Options& options, double* parameters, - Solver::Summary* summary); + Solver::Summary* solver_summary); private: - void Init(const Minimizer::Options& options); - void EstimateScale(const SparseMatrix& jacobian, double* scale) const; - bool MaybeDumpLinearLeastSquaresProblem(const int iteration, - const SparseMatrix* jacobian, - const double* residuals, - const double* step) const; + void Init(const Minimizer::Options& options, + double* parameters, + Solver::Summary* solver_summary); + bool IterationZero(); + bool FinalizeIterationAndCheckIfMinimizerCanContinue(); + bool ComputeTrustRegionStep(); + + bool EvaluateGradientAndJacobian(); + void ComputeCandidatePointAndEvaluateCost(); + + void DoLineSearch(const Vector& x, + const Vector& gradient, + const double cost, + Vector* delta); + void DoInnerIterationsIfNeeded(); + + bool ParameterToleranceReached(); + bool FunctionToleranceReached(); + bool GradientToleranceReached(); + bool MaxSolverTimeReached(); + bool MaxSolverIterationsReached(); + bool MinTrustRegionRadiusReached(); + + bool IsStepSuccessful(); + void HandleUnsuccessfulStep(); + bool HandleSuccessfulStep(); + bool HandleInvalidStep(); Minimizer::Options options_; + + // These pointers are shortcuts to objects passed to the + // TrustRegionMinimizer. The TrustRegionMinimizer does not own them. + double* parameters_; + Solver::Summary* solver_summary_; + Evaluator* evaluator_; + SparseMatrix* jacobian_; + TrustRegionStrategy* strategy_; + + scoped_ptr step_evaluator_; + + bool is_not_silent_; + bool inner_iterations_are_enabled_; + bool inner_iterations_were_useful_; + + // Summary of the current iteration. + IterationSummary iteration_summary_; + + // Dimensionality of the problem in the ambient space. + int num_parameters_; + // Dimensionality of the problem in the tangent space. This is the + // number of columns in the Jacobian. + int num_effective_parameters_; + // Length of the residual vector, also the number of rows in the Jacobian. + int num_residuals_; + + // Current point. + Vector x_; + // Residuals at x_; + Vector residuals_; + // Gradient at x_. + Vector gradient_; + // Solution computed by the inner iterations. + Vector inner_iteration_x_; + // model_residuals = J * trust_region_step + Vector model_residuals_; + Vector negative_gradient_; + // projected_gradient_step = Plus(x, -gradient), an intermediate + // quantity used to compute the projected gradient norm. + Vector projected_gradient_step_; + // The step computed by the trust region strategy. If Jacobi scaling + // is enabled, this is a vector in the scaled space. + Vector trust_region_step_; + // The current proposal for how far the trust region algorithm + // thinks we should move. In the most basic case, it is just the + // trust_region_step_ with the Jacobi scaling undone. If bounds + // constraints are present, then it is the result of the projected + // line search. + Vector delta_; + // candidate_x = Plus(x, delta) + Vector candidate_x_; + // Scaling vector to scale the columns of the Jacobian. + Vector jacobian_scaling_; + + // Euclidean norm of x_. + double x_norm_; + // Cost at x_. + double x_cost_; + // Minimum cost encountered up till now. + double minimum_cost_; + // How much did the trust region strategy reduce the cost of the + // linearized Gauss-Newton model. + double model_cost_change_; + // Cost at candidate_x_. + double candidate_cost_; + + // Time at which the minimizer was started. + double start_time_in_secs_; + // Time at which the current iteration was started. + double iteration_start_time_in_secs_; + // Number of consecutive steps where the minimizer loop computed a + // numerically invalid step. + int num_consecutive_invalid_steps_; }; } // namespace internal } // namespace ceres + #endif // CERES_INTERNAL_TRUST_REGION_MINIMIZER_H_ diff --git a/extern/ceres/internal/ceres/trust_region_step_evaluator.cc b/extern/ceres/internal/ceres/trust_region_step_evaluator.cc new file mode 100644 index 00000000000..c9167e623ef --- /dev/null +++ b/extern/ceres/internal/ceres/trust_region_step_evaluator.cc @@ -0,0 +1,107 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2016 Google Inc. All rights reserved. +// http://ceres-solver.org/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#include +#include "ceres/trust_region_step_evaluator.h" +#include "glog/logging.h" + +namespace ceres { +namespace internal { + +TrustRegionStepEvaluator::TrustRegionStepEvaluator( + const double initial_cost, + const int max_consecutive_nonmonotonic_steps) + : max_consecutive_nonmonotonic_steps_(max_consecutive_nonmonotonic_steps), + minimum_cost_(initial_cost), + current_cost_(initial_cost), + reference_cost_(initial_cost), + candidate_cost_(initial_cost), + accumulated_reference_model_cost_change_(0.0), + accumulated_candidate_model_cost_change_(0.0), + num_consecutive_nonmonotonic_steps_(0){ +} + +double TrustRegionStepEvaluator::StepQuality( + const double cost, + const double model_cost_change) const { + const double relative_decrease = (current_cost_ - cost) / model_cost_change; + const double historical_relative_decrease = + (reference_cost_ - cost) / + (accumulated_reference_model_cost_change_ + model_cost_change); + return std::max(relative_decrease, historical_relative_decrease); +} + +void TrustRegionStepEvaluator::StepAccepted( + const double cost, + const double model_cost_change) { + // Algorithm 10.1.2 from Trust Region Methods by Conn, Gould & + // Toint. + // + // Step 3a + current_cost_ = cost; + accumulated_candidate_model_cost_change_ += model_cost_change; + accumulated_reference_model_cost_change_ += model_cost_change; + + // Step 3b. + if (current_cost_ < minimum_cost_) { + minimum_cost_ = current_cost_; + num_consecutive_nonmonotonic_steps_ = 0; + candidate_cost_ = current_cost_; + accumulated_candidate_model_cost_change_ = 0.0; + } else { + // Step 3c. + ++num_consecutive_nonmonotonic_steps_; + if (current_cost_ > candidate_cost_) { + candidate_cost_ = current_cost_; + accumulated_candidate_model_cost_change_ = 0.0; + } + } + + // Step 3d. + // + // At this point we have made too many non-monotonic steps and + // we are going to reset the value of the reference iterate so + // as to force the algorithm to descend. + // + // Note: In the original algorithm by Toint, this step was only + // executed if the step was non-monotonic, but that would not handle + // the case of max_consecutive_nonmonotonic_steps = 0. The small + // modification of doing this always handles that corner case + // correctly. + if (num_consecutive_nonmonotonic_steps_ == + max_consecutive_nonmonotonic_steps_) { + reference_cost_ = candidate_cost_; + accumulated_reference_model_cost_change_ = + accumulated_candidate_model_cost_change_; + } +} + +} // namespace internal +} // namespace ceres diff --git a/extern/ceres/internal/ceres/trust_region_step_evaluator.h b/extern/ceres/internal/ceres/trust_region_step_evaluator.h new file mode 100644 index 00000000000..06df102a308 --- /dev/null +++ b/extern/ceres/internal/ceres/trust_region_step_evaluator.h @@ -0,0 +1,122 @@ +// Ceres Solver - A fast non-linear least squares minimizer +// Copyright 2016 Google Inc. All rights reserved. +// http://ceres-solver.org/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of Google Inc. nor the names of its contributors may be +// used to endorse or promote products derived from this software without +// specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Author: sameeragarwal@google.com (Sameer Agarwal) + +#ifndef CERES_INTERNAL_TRUST_REGION_STEP_EVALUATOR_H_ +#define CERES_INTERNAL_TRUST_REGION_STEP_EVALUATOR_H_ + +namespace ceres { +namespace internal { + +// The job of the TrustRegionStepEvaluator is to evaluate the quality +// of a step, i.e., how the cost of a step compares with the reduction +// in the objective of the trust region problem. +// +// Classic trust region methods are descent methods, in that they only +// accept a point if it strictly reduces the value of the objective +// function. They do this by measuring the quality of a step as +// +// cost_change / model_cost_change. +// +// Relaxing the monotonic descent requirement allows the algorithm to +// be more efficient in the long term at the cost of some local +// increase in the value of the objective function. +// +// This is because allowing for non-decreasing objective function +// values in a principled manner allows the algorithm to "jump over +// boulders" as the method is not restricted to move into narrow +// valleys while preserving its convergence properties. +// +// The parameter max_consecutive_nonmonotonic_steps controls the +// window size used by the step selection algorithm to accept +// non-monotonic steps. Setting this parameter to zero, recovers the +// classic montonic descent algorithm. +// +// Based on algorithm 10.1.2 (page 357) of "Trust Region +// Methods" by Conn Gould & Toint, or equations 33-40 of +// "Non-monotone trust-region algorithms for nonlinear +// optimization subject to convex constraints" by Phil Toint, +// Mathematical Programming, 77, 1997. +// +// Example usage: +// +// TrustRegionStepEvaluator* step_evaluator = ... +// +// cost = ... // Compute the non-linear objective function value. +// model_cost_change = ... // Change in the value of the trust region objective. +// if (step_evaluator->StepQuality(cost, model_cost_change) > threshold) { +// x = x + delta; +// step_evaluator->StepAccepted(cost, model_cost_change); +// } +class TrustRegionStepEvaluator { + public: + // initial_cost is as the name implies the cost of the starting + // state of the trust region minimizer. + // + // max_consecutive_nonmonotonic_steps controls the window size used + // by the step selection algorithm to accept non-monotonic + // steps. Setting this parameter to zero, recovers the classic + // montonic descent algorithm. + TrustRegionStepEvaluator(double initial_cost, + int max_consecutive_nonmonotonic_steps); + + // Return the quality of the step given its cost and the decrease in + // the cost of the model. model_cost_change has to be positive. + double StepQuality(double cost, double model_cost_change) const; + + // Inform the step evaluator that a step with the given cost and + // model_cost_change has been accepted by the trust region + // minimizer. + void StepAccepted(double cost, double model_cost_change); + + private: + const int max_consecutive_nonmonotonic_steps_; + // The minimum cost encountered up till now. + double minimum_cost_; + // The current cost of the trust region minimizer as informed by the + // last call to StepAccepted. + double current_cost_; + double reference_cost_; + double candidate_cost_; + // Accumulated model cost since the last time the reference model + // cost was updated, i.e., when a step with cost less than the + // current known minimum cost is accepted. + double accumulated_reference_model_cost_change_; + // Accumulated model cost since the last time the candidate model + // cost was updated, i.e., a non-monotonic step was taken with a + // cost that was greater than the current candidate cost. + double accumulated_candidate_model_cost_change_; + // Number of steps taken since the last time minimum_cost was updated. + int num_consecutive_nonmonotonic_steps_; +}; + +} // namespace internal +} // namespace ceres + +#endif // CERES_INTERNAL_TRUST_REGION_STEP_EVALUATOR_H_ diff --git a/extern/ceres/internal/ceres/trust_region_strategy.h b/extern/ceres/internal/ceres/trust_region_strategy.h index 9560e67459a..36e8e981cc0 100644 --- a/extern/ceres/internal/ceres/trust_region_strategy.h +++ b/extern/ceres/internal/ceres/trust_region_strategy.h @@ -86,20 +86,20 @@ class TrustRegionStrategy { struct PerSolveOptions { PerSolveOptions() : eta(0), - dump_filename_base(""), dump_format_type(TEXTFILE) { } // Forcing sequence for inexact solves. double eta; + DumpFormatType dump_format_type; + // If non-empty and dump_format_type is not CONSOLE, the trust // regions strategy will write the linear system to file(s) with // name starting with dump_filename_base. If dump_format_type is // CONSOLE then dump_filename_base will be ignored and the linear // system will be written to the standard error. std::string dump_filename_base; - DumpFormatType dump_format_type; }; struct Summary { From 1ee43c5aef03c1a3218163d9450545fdb9ad4482 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 1 Nov 2016 13:39:31 +0100 Subject: [PATCH 080/590] Fix T49856: Blender 2.78 crashes after loading data from a blendfile Issue here was that py API code was keeping references (pointers) to the liniked data-blocks, which can actually be duplicated and then deleted during the 'make local' process... Would have like to find a better way than passing optional GHash to get the oldid->newid mapping, but could not think of a better idea. --- source/blender/blenkernel/BKE_library.h | 4 +++- source/blender/blenkernel/intern/blender_copybuffer.c | 4 ++-- source/blender/blenkernel/intern/library.c | 7 ++++++- source/blender/editors/object/object_relations.c | 2 +- source/blender/python/intern/bpy_library_load.c | 7 ++++++- source/blender/windowmanager/intern/wm_files_link.c | 4 ++-- 6 files changed, 20 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 0d82de09165..79373e343a6 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -39,6 +39,7 @@ extern "C" { #include "BLI_compiler_attrs.h" struct BlendThumbnail; +struct GHash; struct ListBase; struct ID; struct ImBuf; @@ -125,7 +126,8 @@ void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id); void BKE_library_free(struct Library *lib); void BKE_library_make_local( - struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake); + struct Main *bmain, const struct Library *lib, struct GHash *old_to_new_ids, + const bool untagged_only, const bool set_fake); /* use when "" is given to new_id() */ diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index a4c28121040..e57524af546 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -101,7 +101,7 @@ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *repor IMB_colormanagement_check_file_config(bmain_dst); /* Append, rather than linking. */ Library *lib = BLI_findstring(&bmain_dst->library, libname, offsetof(Library, filepath)); - BKE_library_make_local(bmain_dst, lib, true, false); + BKE_library_make_local(bmain_dst, lib, NULL, true, false); /* Important we unset, otherwise these object wont * link into other scenes from this blend file. */ @@ -150,7 +150,7 @@ bool BKE_copybuffer_paste(bContext *C, const char *libname, const short flag, Re /* append, rather than linking */ lib = BLI_findstring(&bmain->library, libname, offsetof(Library, filepath)); - BKE_library_make_local(bmain, lib, true, false); + BKE_library_make_local(bmain, lib, NULL, true, false); /* important we unset, otherwise these object wont * link into other scenes from this blend file */ diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 14612151a8e..622f79df4ee 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -73,6 +73,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_linklist.h" #include "BLI_memarena.h" @@ -1640,7 +1641,8 @@ void BKE_main_id_clear_newpoins(Main *bmain) * We'll probably need at some point a true dependency graph between datablocks, but for now this should work * good enough (performances is not a critical point here anyway). */ -void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged_only, const bool set_fake) +void BKE_library_make_local( + Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake) { ListBase *lbarray[MAX_LIBARRAY]; ID *id, *id_next; @@ -1712,6 +1714,9 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged BLI_assert(id->lib != NULL); BKE_libblock_remap(bmain, id, id->newid, ID_REMAP_SKIP_INDIRECT_USAGE); + if (old_to_new_ids) { + BLI_ghash_insert(old_to_new_ids, id, id->newid); + } } /* Third step: remove datablocks that have been copied to be localized and are no more used in the end... diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index d1232fd2aab..16ee6f4ed89 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2235,7 +2235,7 @@ static int make_local_exec(bContext *C, wmOperator *op) "Orphan library objects added to the current scene to avoid loss"); } - BKE_library_make_local(bmain, NULL, false, false); /* NULL is all libs */ + BKE_library_make_local(bmain, NULL, NULL, false, false); /* NULL is all libs */ WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; } diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index ec69abbb1df..15f3c665fcf 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -33,6 +33,7 @@ #include #include "BLI_utildefines.h" +#include "BLI_ghash.h" #include "BLI_string.h" #include "BLI_linklist.h" #include "BLI_path_util.h" @@ -405,6 +406,8 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) BLO_blendhandle_close(self->blo_handle); self->blo_handle = NULL; + GHash *old_to_new_ids = BLI_ghash_ptr_new(__func__); + /* copied from wm_operator.c */ { /* mark all library linked objects to be updated */ @@ -412,7 +415,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* append, rather than linking */ if ((self->flag & FILE_LINK) == 0) { - BKE_library_make_local(bmain, lib, true, false); + BKE_library_make_local(bmain, lib, old_to_new_ids, true, false); } } @@ -439,6 +442,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) ID *id; id = PyCapsule_GetPointer(item, NULL); + id = BLI_ghash_lookup_default(old_to_new_ids, id, id); Py_DECREF(item); RNA_id_pointer_create(id, &id_ptr); @@ -452,6 +456,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) } #endif /* USE_RNA_DATABLOCKS */ + BLI_ghash_free(old_to_new_ids, NULL, NULL); Py_RETURN_NONE; } } diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index e872ec1a524..3b733f9558c 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -419,7 +419,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive"); if (use_recursive) { - BKE_library_make_local(bmain, NULL, true, set_fake); + BKE_library_make_local(bmain, NULL, NULL, true, set_fake); } else { LinkNode *itemlink; @@ -430,7 +430,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) ID *new_id = ((WMLinkAppendDataItem *)(itemlink->link))->new_id; if (new_id && !BLI_gset_haskey(done_libraries, new_id->lib)) { - BKE_library_make_local(bmain, new_id->lib, true, set_fake); + BKE_library_make_local(bmain, new_id->lib, NULL, true, set_fake); BLI_gset_insert(done_libraries, new_id->lib); } } From 4e95a9069e6fcbbdac10898e83dce8f993eb6518 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 1 Nov 2016 14:59:12 +0100 Subject: [PATCH 081/590] Add 'copy array' for rna buttons ctrl-alt-c/v allows to copy/paste whole RNA array, e.g. location, rotation, etc., from UI buttons. Request from Andy at the studio. --- .../editors/interface/interface_handlers.c | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 0555529599c..f3eeadb6604 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2219,7 +2219,7 @@ static void ui_but_drop(bContext *C, const wmEvent *event, uiBut *but, uiHandleB /* ******************* copy and paste ******************** */ /* c = copy, v = paste */ -static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, char mode) +static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, const char mode, const bool copy_array) { int buf_paste_len = 0; const char *buf_paste = ""; @@ -2255,6 +2255,46 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data, if (but->poin == NULL && but->rnapoin.data == NULL) { /* pass */ } + else if (copy_array && but->rnapoin.data && but->rnaprop && + ELEM(RNA_property_subtype(but->rnaprop), PROP_COLOR, PROP_TRANSLATION, PROP_DIRECTION, + PROP_VELOCITY, PROP_ACCELERATION, PROP_MATRIX, PROP_EULER, PROP_QUATERNION, PROP_AXISANGLE, + PROP_XYZ, PROP_XYZ_LENGTH, PROP_COLOR_GAMMA, PROP_COORDS)) + { + float values[4]; + int array_length = RNA_property_array_length(&but->rnapoin, but->rnaprop); + + if (mode == 'c') { + char buf_copy[UI_MAX_DRAW_STR]; + + if (array_length == 4) { + values[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3); + } + else { + values[3] = 0.0f; + } + ui_but_v3_get(but, values); + + BLI_snprintf(buf_copy, sizeof(buf_copy), "[%f, %f, %f, %f]", values[0], values[1], values[2], values[3]); + WM_clipboard_text_set(buf_copy, 0); + } + else { + if (sscanf(buf_paste, "[%f, %f, %f, %f]", &values[0], &values[1], &values[2], &values[3]) >= array_length) { + button_activate_state(C, but, BUTTON_STATE_NUM_EDITING); + + ui_but_v3_set(but, values); + if (but->rnaprop && array_length == 4) { + RNA_property_float_set_index(&but->rnapoin, but->rnaprop, 3, values[3]); + } + data->value = values[but->rnaindex]; + + button_activate_state(C, but, BUTTON_STATE_EXIT); + } + else { + WM_report(RPT_ERROR, "Paste expected 4 numbers, formatted: '[n, n, n, n]'"); + show_report = true; + } + } + } else if (mode == 'c') { /* Get many decimal places, then strip trailing zeros. * note: too high values start to give strange results */ @@ -6965,7 +7005,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) && !event->shift && !event->alt) + IS_EVENT_MOD(event, ctrl, oskey) && !event->shift) { /* Specific handling for listrows, we try to find their overlapping tex button. */ if (but->type == UI_BTYPE_LISTROW) { @@ -6975,7 +7015,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * data = but->active; } } - ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v'); + ui_but_copy_paste(C, but, data, (event->type == CKEY) ? 'c' : 'v', event->alt); return WM_UI_HANDLER_BREAK; } /* handle drop */ From 13ee9b8ebe08ee95478f51537f10e9a1b1e4d863 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Tue, 1 Nov 2016 22:09:42 +0100 Subject: [PATCH 082/590] Change frame for animations should not bein the UNDO stack Request from Hjalti Hjalmarsson for the animation work. Basically a common part of the workflow of animation is to change the pose, scrub back and forth a few times and roll back the changes when unsatisfied. However if you go back and forth too many times the UNDO stack would be full, and it would not be possible to bring back the previous pose. I'm leaving clip_editor change frames as it is for now. But we can probably change the behaviour there as well. --- source/blender/editors/animation/anim_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 262ce0b9e23..d7899061218 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -263,7 +263,7 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) ot->poll = change_frame_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; /* rna */ ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); From f94a460397a86beb9f71e665e8f484fa4e10ebdc Mon Sep 17 00:00:00 2001 From: lazydodo Date: Tue, 1 Nov 2016 15:30:12 -0600 Subject: [PATCH 083/590] [msvc/make.bat] Detect spaces in the build path and error out. --- make.bat | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/make.bat b/make.bat index c7f2dbbf369..74148e5599d 100644 --- a/make.bat +++ b/make.bat @@ -4,6 +4,11 @@ REM This is for users who like to configure & build Blender with a single comman setlocal ENABLEEXTENSIONS set BLENDER_DIR=%~dp0 +set BLENDER_DIR_NOSPACES=%BLENDER_DIR: =% +if not "%BLENDER_DIR%"=="%BLENDER_DIR_NOSPACES%" ( + echo There are spaces detected in the build path "%BLENDER_DIR%", this is currently not supported, exiting.... + goto EOF +) set BUILD_DIR=%BLENDER_DIR%..\build_windows set BUILD_TYPE=Release rem reset all variables so they do not get accidentally get carried over from previous builds From 97a8cd68833f5f580cf1adf91ff561975471bfc5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 2 Nov 2016 10:32:46 +0100 Subject: [PATCH 084/590] CMake: Fix use of some option which was never defined This way it seems more logical to me. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f3c22d9b717..fe226dd769b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -731,7 +731,7 @@ elseif(WITH_CYCLES OR WITH_OPENIMAGEIO OR WITH_AUDASPACE OR WITH_INTERNATIONAL O # Keep enabled else() # New dependency graph needs either Boost or C++11 for function bindings. - if(NOT USE_CXX11) + if(NOT WITH_CXX11) # Enabled but we don't need it set(WITH_BOOST OFF) endif() From 83ebf501cdfdb21a8b111dcaf32481bc021094f0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 2 Nov 2016 10:42:15 +0100 Subject: [PATCH 085/590] CMake: Make ld.gold linker optional Some platforms are having hard time using this linker so added an option to not use it. The options is an advanced one and enabled by default so should not cause any changes for current users. --- CMakeLists.txt | 6 ++++++ .../cmake/platform/platform_unix.cmake | 21 ++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fe226dd769b..bbab208409b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -508,6 +508,12 @@ mark_as_advanced(WITH_C11) option(WITH_CXX11 "Build with C++11 standard enabled, for development use only!" ${_cxx11_init}) mark_as_advanced(WITH_CXX11) +# Compiler toolchain +if(CMAKE_COMPILER_IS_GNUCC) + option(WITH_LINKER_GOLD "Use ld.gold linker which is usually faster than ld.bfd" ON) + mark_as_advanced(WITH_LINKER_GOLD) +endif() + # Dependency graph option(WITH_LEGACY_DEPSGRAPH "Build Blender with legacy dependency graph" ON) mark_as_advanced(WITH_LEGACY_DEPSGRAPH) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index e33141f8012..62e0caa7c43 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -384,17 +384,18 @@ add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE if(CMAKE_COMPILER_IS_GNUCC) set(PLATFORM_CFLAGS "-pipe -fPIC -funsigned-char -fno-strict-aliasing") - # use ld.gold linker if available, could make optional - execute_process( - COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version - ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) - if("${LD_VERSION}" MATCHES "GNU gold") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=gold") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold") - else() - message(STATUS "GNU gold linker isn't available, using the default system linker.") + if(WITH_LINKER_GOLD) + execute_process( + COMMAND ${CMAKE_C_COMPILER} -fuse-ld=gold -Wl,--version + ERROR_QUIET OUTPUT_VARIABLE LD_VERSION) + if("${LD_VERSION}" MATCHES "GNU gold") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=gold") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=gold") + else() + message(STATUS "GNU gold linker isn't available, using the default system linker.") + endif() + unset(LD_VERSION) endif() - unset(LD_VERSION) # CLang is the same as GCC for now. elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") From 4fdf68271c65e204cd75ec976daf879b0049e1fa Mon Sep 17 00:00:00 2001 From: Martijn Berger Date: Wed, 2 Nov 2016 10:54:47 +0100 Subject: [PATCH 086/590] Cycles standalone, compile fix UINT_MAX is not defined in device_cuda.cpp --- intern/cycles/device/device_cuda.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 7f8a0bf2f43..42e9cf75258 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include #include #include #include From 630c0559f97d4e9fbdbbd4278ddfbfaa07019165 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 2 Nov 2016 12:23:00 +0100 Subject: [PATCH 087/590] Depsgraph: Fix some errors printed to the console They were not real issues, it's just some areas of code tried to create relations between non-existing nodes without checking whether such relations are really needed. Now it should be easier to see real bugs printed. Hopefully should be no regressions here. --- .../depsgraph/intern/builder/deg_builder_relations.cc | 8 ++++---- .../depsgraph/intern/builder/deg_builder_relations.h | 1 + source/blender/modifiers/intern/MOD_hook.c | 5 +---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 09c7d9ab9de..47672d206de 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -500,7 +500,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o build_animdata(&ob->id); // XXX: This should be hooked up by the build_animdata code - if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) { + if (needs_animdata_node(&ob->id)) { ComponentKey adt_key(&ob->id, DEPSNODE_TYPE_ANIMATION); add_relation(adt_key, local_transform_key, DEPSREL_TYPE_OPERATION, "Object Animation"); } @@ -1527,7 +1527,7 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) "Armature Eval"); add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency"); - if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) { + if (needs_animdata_node(&ob->id)) { ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION); add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation"); } @@ -1765,7 +1765,7 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje * for either the modifier needing time, or that it is animated. */ /* XXX: Remove this hack when these links are added as part of build_animdata() instead */ - if (modifier_dependsOnTime(md) == false) { + if (modifier_dependsOnTime(md) == false && needs_animdata_node(&ob->id)) { ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION); add_relation(animation_key, mod_key, DEPSREL_TYPE_OPERATION, "Modifier Animation"); } @@ -2063,7 +2063,7 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id) { AnimData *adt = BKE_animdata_from_id(id); if (adt != NULL) { - return adt->action != NULL; + return (adt->action != NULL) || (adt->nla_tracks.first != NULL); } return false; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 5240aa24b54..d60499e9cbe 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -318,6 +318,7 @@ void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from, else { if (!op_from) { /* XXX TODO handle as error or report if needed */ + node_from = find_node(key_from); fprintf(stderr, "add_relation(%d, %s) - Could not find op_from (%s)\n", type, description, key_from.identifier().c_str()); } diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 83c4ca7984c..9186b10d8ca 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -145,12 +145,9 @@ static void updateDepsgraph(ModifierData *md, HookModifierData *hmd = (HookModifierData *)md; if (hmd->object != NULL) { if (hmd->subtarget[0]) { - DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier"); } - else { - DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); - } + DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); } /* We need own transformation as well. */ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier"); From dac543856205a68975cb61b80769574b5986da18 Mon Sep 17 00:00:00 2001 From: Gaia Clary Date: Wed, 2 Nov 2016 14:11:46 +0100 Subject: [PATCH 088/590] COLLADA: Removed obsolete Export select option 'Both' which created invalid data (duplicate transformation information for nodes) --- source/blender/collada/TransformWriter.cpp | 5 ----- source/blender/collada/collada.h | 3 +-- source/blender/editors/io/io_collada.c | 1 - 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp index b16e2e2b0d3..908111ebae6 100644 --- a/source/blender/collada/TransformWriter.cpp +++ b/source/blender/collada/TransformWriter.cpp @@ -113,11 +113,6 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B node.addMatrix("transform",d_obmat); break; } - case BC_TRANSFORMATION_TYPE_BOTH: - { - node.addMatrix("transform",d_obmat); - /* fall-through */ - } case BC_TRANSFORMATION_TYPE_TRANSROTLOC: { float loc[3], rot[3], scale[3]; diff --git a/source/blender/collada/collada.h b/source/blender/collada/collada.h index 0017c66836a..a4416608584 100644 --- a/source/blender/collada/collada.h +++ b/source/blender/collada/collada.h @@ -43,8 +43,7 @@ typedef enum BC_export_mesh_type { typedef enum BC_export_transformation_type { BC_TRANSFORMATION_TYPE_MATRIX, - BC_TRANSFORMATION_TYPE_TRANSROTLOC, - BC_TRANSFORMATION_TYPE_BOTH + BC_TRANSFORMATION_TYPE_TRANSROTLOC } BC_export_transformation_type; struct bContext; diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 8659100df87..baae92f962e 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -305,7 +305,6 @@ void WM_OT_collada_export(wmOperatorType *ot) static EnumPropertyItem prop_bc_export_transformation_type[] = { {BC_TRANSFORMATION_TYPE_MATRIX, "matrix", 0, "Matrix", "Use to specify transformations"}, {BC_TRANSFORMATION_TYPE_TRANSROTLOC, "transrotloc", 0, "TransRotLoc", "Use , , to specify transformations"}, - {BC_TRANSFORMATION_TYPE_BOTH, "both", 0, "Both", "Use AND , , to specify transformations"}, {0, NULL, 0, NULL, NULL} }; From 15f2a5123256482c15815ea3385eb0a9f7e10bbb Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 2 Nov 2016 15:09:32 +0100 Subject: [PATCH 089/590] Solve threading conflict when calculating smooth normals It was possible to have synchronization issues whe naccumulating smooth normal to a vertex, causing shading artifacts during playback. Bug found by Dalai, thanks! --- source/blender/blenkernel/intern/mesh_evaluate.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index fa113ef5eef..016c9c863f0 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -58,6 +58,7 @@ #include "BLI_strict_flags.h" +#include "atomic_ops.h" #include "mikktspace.h" // #define DEBUG_TIME @@ -236,7 +237,9 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx) const float fac = saacos(-dot_v3v3(cur_edge, prev_edge)); /* accumulate */ - madd_v3_v3fl(vnors[ml[i].v], pnor, fac); + for (int k = 3; k--; ) { + atomic_add_fl(&vnors[ml[i].v][k], pnor[k] * fac); + } prev_edge = cur_edge; } } From c9ffb6fc91cfe65b986b843e259fe17c87c43fea Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 2 Nov 2016 15:32:11 +0100 Subject: [PATCH 090/590] Libmv: Update tests to make tests pass after recent Ceres update Just a precision issue, difference is around 1e-7. Should be fine to simply update expected value. --- intern/libmv/libmv/simple_pipeline/modal_solver_test.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc b/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc index 8b87acd95bb..b4cae8defb2 100644 --- a/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc +++ b/intern/libmv/libmv/simple_pipeline/modal_solver_test.cc @@ -65,9 +65,9 @@ TEST(ModalSolver, SyntheticCubeSceneMotion) { NULL); Mat3 expected_rotation; - expected_rotation << 0.98215101299251, 0.17798357184544, 0.06083778292258, - -0.16875286001759, 0.97665299913606, -0.13293378620359, - -0.08307743323957, 0.12029450291547, 0.98925596922871; + expected_rotation << 0.98215101743472, 0.17798354937546, 0.06083777694542, + -0.16875283983360, 0.97665300495333, -0.13293376908719, + -0.08307742172243, 0.12029448893171, 0.98925597189636; Mat3 &first_camera_R = reconstruction.CameraForImage(1)->R; Mat3 &second_camera_R = reconstruction.CameraForImage(2)->R; From c5510df2682fccd7a8f1b9aa2b80aef31cf1d9a9 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 2 Nov 2016 15:35:18 +0100 Subject: [PATCH 091/590] tests: Update hash for OBJ Was a recent update of UV precision. --- tests/python/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 8487c6a2094..a29b612e0ef 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -130,7 +130,7 @@ add_test(export_obj_cube ${TEST_BLENDER_EXE} --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_cube.obj',use_selection=False\) --md5_source=${TEST_OUT_DIR}/export_obj_cube.obj --md5_source=${TEST_OUT_DIR}/export_obj_cube.mtl - --md5=826f74e6b7a2128b0b61a52071ada36e --md5_method=FILE + --md5=e80660437ad9bfe082849641c361a233 --md5_method=FILE ) add_test(export_obj_nurbs ${TEST_BLENDER_EXE} From 643c5a24d56f00c45d03b52f4b1211c05a78bf0f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 2 Nov 2016 18:05:38 +0100 Subject: [PATCH 092/590] Depsgraph: Fix race condition writing drivers to array property Animation system has separate fcurves for each of array elements and dependency graph creates separate nodes for each of fcurve, This is needed to keep granularity of updates, but causes issues because animation system will actually write the whole array to property when modifying single value (this is a limitation of RNA API). Worked around by adding operation relation between array drivers so we never write same array form multiple threads. --- .../intern/builder/deg_builder_relations.cc | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 47672d206de..e506b8712e8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -842,6 +842,55 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) /* create the driver's relations to targets */ build_driver(id, fcu); + /* Special case for array drivers: we can not multithread them because + * of the way how they work internally: animation system will write the + * whole array back to RNA even when changing individual array value. + * + * Some tricky things here: + * - array_index is -1 for single channel drivers, meaning we only have + * to do some magic when array_index is not -1. + * - We do relation from next array index to a previous one, so we don't + * have to deal with array index 0. + * + * TODO(sergey): Avoid liner lookup somehow. + */ + if (fcu->array_index > 0) { + FCurve *fcu_prev = NULL; + for (FCurve *fcu_candidate = (FCurve *)adt->drivers.first; + fcu_candidate != NULL; + fcu_candidate = fcu_candidate->next) + { + /* Writing to different RNA paths is */ + if (!STREQ(fcu_candidate->rna_path, fcu->rna_path)) { + continue; + } + /* We only do relation from previous fcurve to previous one. */ + if (fcu_candidate->array_index >= fcu->array_index) { + continue; + } + /* Choose fcurve with highest possible array index. */ + if (fcu_prev == NULL || + fcu_candidate->array_index > fcu_prev->array_index) + { + fcu_prev = fcu_candidate; + } + } + if (fcu_prev != NULL) { + OperationKey prev_driver_key(id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + deg_fcurve_id_name(fcu_prev)); + OperationKey driver_key(id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + deg_fcurve_id_name(fcu)); + add_relation(prev_driver_key, + driver_key, + DEPSREL_TYPE_OPERATION, + "[Driver Order]"); + } + } + /* prevent driver from occurring before own animation... */ if (adt->action || adt->nla_tracks.first) { add_relation(adt_key, driver_key, DEPSREL_TYPE_OPERATION, From 9847ad977a29685d3400ec222213dfb484ec01f5 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Thu, 3 Nov 2016 03:08:14 +0100 Subject: [PATCH 093/590] Cycles: Fix T49901: OpenCL build error after recent light texture coordinate commit Basically, the problem here was that the transform that's used to bring texture coordinates to world space is either fetched while setting up the shader (with Object Motion is enabled) or fetched when needed (otherwise). That helps to save ShaderData memory on OpenCL when Object Motion isn't needed. Now, if OM is enabled, the Lamp transform can just be stored inside the ShaderData as well. The original commit just assumed it is. However, when it's not (on OpenCL by default, for example), there is no easy way to fetch it when needed, since the ShaderData doesn't store the Lamp index. So, for now the lamps just don't support local texture coordinates anymore when Object Motion is disabled. To fix and support this properly, one of the following could be done: - Just always pre-fetch the transform. Downside: Memory Usage increases when not using OM on OpenCL - Add a variable to ShaderData that stores the Lamp ID to allow fetching it when needed - Store the Lamp ID inside prim or object. Problem: Cycles currently checks these for whether an object was hit - these checks would need to be changed. - Enable OM whenever a Texture Coordinate's Normal output is used. Downside: Might not actually be needed. --- intern/cycles/kernel/geom/geom_object.h | 12 ++++++++---- intern/cycles/kernel/kernel_shader.h | 7 ++----- intern/cycles/kernel/svm/svm_image.h | 3 +-- intern/cycles/kernel/svm/svm_tex_coord.h | 9 +++------ 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index 6b42f66b0d5..73dc5a0a726 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -161,11 +161,15 @@ ccl_device_inline void object_inverse_position_transform(KernelGlobals *kg, cons ccl_device_inline void object_inverse_normal_transform(KernelGlobals *kg, const ShaderData *sd, float3 *N) { -#ifdef __OBJECT_MOTION__ - *N = normalize(transform_direction_transposed_auto(&ccl_fetch(sd, ob_tfm), *N)); +#ifdef __OBJECT_MOTION_ + if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP)) { + *N = normalize(transform_direction_transposed_auto(&ccl_fetch(sd, ob_tfm), *N)); + } #else - Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM); - *N = normalize(transform_direction_transposed(&tfm, *N)); + if(ccl_fetch(sd, object) != OBJECT_NONE) { + Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM); + *N = normalize(transform_direction_transposed(&tfm, *N)); + } #endif } diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index b4b980c4e90..c1b3153d8fe 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -276,16 +276,13 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, #ifdef __OBJECT_MOTION__ shader_setup_object_transforms(kg, sd, time); -#endif + ccl_fetch(sd, time) = time; } else if(lamp != LAMP_NONE) { ccl_fetch(sd, ob_tfm) = lamp_fetch_transform(kg, lamp, false); ccl_fetch(sd, ob_itfm) = lamp_fetch_transform(kg, lamp, true); - } - -#ifdef __OBJECT_MOTION__ - ccl_fetch(sd, time) = time; #endif + } /* transform into world space */ if(object_space) { diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 9606064492e..2afdf61b476 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -241,8 +241,7 @@ ccl_device void svm_node_tex_image_box(KernelGlobals *kg, ShaderData *sd, float float3 N = ccl_fetch(sd, N); N = ccl_fetch(sd, N); - if(ccl_fetch(sd, object) != OBJECT_NONE) - object_inverse_normal_transform(kg, sd, &N); + object_inverse_normal_transform(kg, sd, &N); /* project from direction vector to barycentric coordinates in triangles */ N.x = fabsf(N.x); diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index 6c3394adbce..c0b01262212 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -49,8 +49,7 @@ ccl_device void svm_node_tex_coord(KernelGlobals *kg, } case NODE_TEXCO_NORMAL: { data = ccl_fetch(sd, N); - if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP)) - object_inverse_normal_transform(kg, sd, &data); + object_inverse_normal_transform(kg, sd, &data); break; } case NODE_TEXCO_CAMERA: { @@ -131,8 +130,7 @@ ccl_device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, } case NODE_TEXCO_NORMAL: { data = ccl_fetch(sd, N); - if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP)) - object_inverse_normal_transform(kg, sd, &data); + object_inverse_normal_transform(kg, sd, &data); break; } case NODE_TEXCO_CAMERA: { @@ -216,8 +214,7 @@ ccl_device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, } case NODE_TEXCO_NORMAL: { data = ccl_fetch(sd, N); - if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP)) - object_inverse_normal_transform(kg, sd, &data); + object_inverse_normal_transform(kg, sd, &data); break; } case NODE_TEXCO_CAMERA: { From f800794b97f1d3c0e596afeb15172b0288396240 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Thu, 3 Nov 2016 03:15:39 +0100 Subject: [PATCH 094/590] Cycles: Fix OpenCL build error caused by light termination commit --- intern/cycles/kernel/kernel_random.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index 2372b07d974..2b767da5041 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -301,7 +301,7 @@ ccl_device_inline void path_branched_rng_2D(KernelGlobals *kg, ccl_addr_space RN } /* Utitility functions to get light termination value, since it might not be needed in many cases. */ -ccl_device_inline float path_state_rng_light_termination(KernelGlobals *kg, ccl_addr_space RNG *rng, const PathState *state) +ccl_device_inline float path_state_rng_light_termination(KernelGlobals *kg, ccl_addr_space RNG *rng, const ccl_addr_space PathState *state) { if(kernel_data.integrator.light_inv_rr_threshold > 0.0f) { return path_state_rng_1D_for_decision(kg, rng, state, PRNG_LIGHT_TERMINATE); From 534f11f71ee71b87a17ceddf56da0bcfa2cab352 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 10:25:31 +0100 Subject: [PATCH 095/590] Fix T49857: Blender crashes after adding texture node to compositing tree --- source/blender/compositor/operations/COM_TextureOperation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp index bba5c8702b8..6bfd8ae3888 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.cpp +++ b/source/blender/compositor/operations/COM_TextureOperation.cpp @@ -118,7 +118,7 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y * interpolaiton and (b) in such configuration multitex() sinply floor's the value * which often produces artifacts. */ - if ((m_texture->imaflag & TEX_INTERPOL) == 0) { + if (m_texture != NULL && (m_texture->imaflag & TEX_INTERPOL) == 0) { u += 0.5f / cx; v += 0.5f / cy; } From fc1b35e44c09f22d0116bcddb7b39a50a9868580 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 11:19:42 +0100 Subject: [PATCH 096/590] Depsgraph: Fix wrong comparison of ID type vs. node type --- .../depsgraph/intern/builder/deg_builder_nodes.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 1812384440f..befc1ea3b7f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -1171,15 +1171,17 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree /* nodetree's nodes... */ for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) { - if (bnode->id) { - if (GS(bnode->id->name) == ID_MA) { - build_material(owner_node, (Material *)bnode->id); + ID *id = bnode->id; + if (id != NULL) { + short id_type = GS(id->name); + if (id_type == ID_MA) { + build_material(owner_node, (Material *)id); } - else if (bnode->type == ID_TE) { - build_texture(owner_node, (Tex *)bnode->id); + else if (id_type == ID_TE) { + build_texture(owner_node, (Tex *)id); } else if (bnode->type == NODE_GROUP) { - bNodeTree *group_ntree = (bNodeTree *)bnode->id; + bNodeTree *group_ntree = (bNodeTree *)id; if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) { build_nodetree(owner_node, group_ntree); } From 647255db939596b1b51e88f40e28086f92caf281 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 11:31:49 +0100 Subject: [PATCH 097/590] Fix T49826: NEW-DEPSGRAPH - Texture is not updated after changing its space color The issue was caused by image ID nodes not being in the depsgraph. Now, tricky part: we only add nodes but do not add relations yet. Reasoning: - It's currently important to only call editor's ID update callback to solve the issue, without need to flush changes somewhere deeper. - Adding relations might cause some unwanted updates, so will leave that for a later investigation. --- .../intern/builder/deg_builder_nodes.cc | 30 +++++++++++++++++-- .../intern/builder/deg_builder_nodes.h | 2 ++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index befc1ea3b7f..d1469e850e6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -1180,6 +1180,9 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree else if (id_type == ID_TE) { build_texture(owner_node, (Tex *)id); } + else if (id_type == ID_IM) { + build_image((Image *)id); + } else if (bnode->type == NODE_GROUP) { bNodeTree *group_ntree = (bNodeTree *)id; if ((group_ntree->id.tag & LIB_TAG_DOIT) == 0) { @@ -1238,10 +1241,33 @@ void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex) return; } tex_id->tag |= LIB_TAG_DOIT; - /* texture itself */ + /* Texture itself. */ build_animdata(tex_id); - /* texture's nodetree */ + /* Texture's nodetree. */ build_nodetree(owner_node, tex->nodetree); + /* Special cases for different IDs which texture uses. */ + if (tex->type == TEX_IMAGE) { + if (tex->ima != NULL) { + build_image(tex->ima); + } + } +} + +void DepsgraphNodeBuilder::build_image(Image *image) { + ID *image_id = &image->id; + if (image_id->tag & LIB_TAG_DOIT) { + return; + } + image_id->tag |= LIB_TAG_DOIT; + /* Image ID node itself. */ + add_id_node(image_id); + /* Placeholder so we can add relations and tag ID node for update. */ + add_operation_node(image_id, + DEPSNODE_TYPE_PARAMETERS, + DEPSOP_TYPE_EXEC, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Image Eval"); } void DepsgraphNodeBuilder::build_compositor(Scene *scene) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index f378f076804..09d264c4b59 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -38,6 +38,7 @@ struct bGPdata; struct ListBase; struct GHash; struct ID; +struct Image; struct FCurve; struct Group; struct Key; @@ -142,6 +143,7 @@ struct DepsgraphNodeBuilder { void build_material(DepsNode *owner_node, Material *ma); void build_texture(DepsNode *owner_node, Tex *tex); void build_texture_stack(DepsNode *owner_node, MTex **texture_stack); + void build_image(Image *image); void build_world(World *world); void build_compositor(Scene *scene); void build_gpencil(bGPdata *gpd); From 27c559f059056ad2973d581354426f458a82e278 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Thu, 3 Nov 2016 12:38:00 +0100 Subject: [PATCH 098/590] Cycles: Fix missing underscore in geom_object.h --- intern/cycles/kernel/geom/geom_object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index 73dc5a0a726..9f0fe032ba4 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -161,7 +161,7 @@ ccl_device_inline void object_inverse_position_transform(KernelGlobals *kg, cons ccl_device_inline void object_inverse_normal_transform(KernelGlobals *kg, const ShaderData *sd, float3 *N) { -#ifdef __OBJECT_MOTION_ +#ifdef __OBJECT_MOTION__ if((ccl_fetch(sd, object) != OBJECT_NONE) || (ccl_fetch(sd, type) == PRIMITIVE_LAMP)) { *N = normalize(transform_direction_transposed_auto(&ccl_fetch(sd, ob_tfm), *N)); } From b6980ade90766d355690a551103b50aa97cd22fd Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 13:24:41 +0100 Subject: [PATCH 099/590] Depsgraph: Add code for timing despgraph builder --- .../blender/depsgraph/intern/depsgraph_build.cc | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 7a3b19e82c6..7b3922a2eaf 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -32,6 +32,8 @@ #include "MEM_guardedalloc.h" +// #define DEBUG_TIME + extern "C" { #include "DNA_cachefile_types.h" #include "DNA_object_types.h" @@ -41,6 +43,11 @@ extern "C" { #include "BLI_utildefines.h" #include "BLI_ghash.h" +#ifdef DEBUG_TIME +# include "PIL_time.h" +# include "PIL_time_utildefines.h" +#endif + #include "BKE_main.h" #include "BKE_collision.h" #include "BKE_effect.h" @@ -190,6 +197,10 @@ void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag) */ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene) { +#ifdef DEBUG_TIME + TIMEIT_START(DEG_graph_build_from_scene); +#endif + DEG::Depsgraph *deg_graph = reinterpret_cast(graph); /* 1) Generate all the nodes in the graph first */ @@ -239,6 +250,10 @@ void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene) abort(); } #endif + +#ifdef DEBUG_TIME + TIMEIT_END(DEG_graph_build_from_scene); +#endif } /* Tag graph relations for update. */ From dd6fa94dcc9fa6002d4901f4afe0b1e997f5fa0c Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 2 Nov 2016 15:11:58 +0100 Subject: [PATCH 100/590] Add 'Set From Faces' tool to custom split normals. Feature request during bconf, makes sense to have it even as an hack for now, since this is probably one of the most common use cases. This should be redone in bmesh once we have proper custom noramls handling in edit mode... --- release/scripts/startup/bl_operators/mesh.py | 50 +++++++++++++++++++ .../startup/bl_ui/space_view3d_toolbar.py | 1 + 2 files changed, 51 insertions(+) diff --git a/release/scripts/startup/bl_operators/mesh.py b/release/scripts/startup/bl_operators/mesh.py index be74f8dbc0e..58eab5436e6 100644 --- a/release/scripts/startup/bl_operators/mesh.py +++ b/release/scripts/startup/bl_operators/mesh.py @@ -198,3 +198,53 @@ class MeshSelectPrev(Operator): bmesh.update_edit_mesh(me, False) return {'FINISHED'} + + +# XXX This is hackish (going forth and back from Object mode...), to be redone once we have proper support of +# custom normals in BMesh/edit mode. +class MehsSetNormalsFromFaces(Operator): + """Set the custom vertex normals from the selected faces ones""" + bl_idname = "mesh.set_normals_from_faces" + bl_label = "Set Normals From Faces" + bl_options = {'REGISTER', 'UNDO'} + + @classmethod + def poll(cls, context): + return (context.mode == 'EDIT_MESH' and context.edit_object.data.polygons) + + def execute(self, context): + import mathutils + + bpy.ops.object.mode_set(mode='OBJECT') + obj = context.active_object + me = obj.data + + v2nors = {} + for p in me.polygons: + if not p.select: + continue + for lidx, vidx in zip(p.loop_indices, p.vertices): + assert(me.loops[lidx].vertex_index == vidx) + v2nors.setdefault(vidx, []).append(p.normal) + + for nors in v2nors.values(): + nors[:] = [sum(nors, mathutils.Vector((0, 0, 0))).normalized()] + + if not me.has_custom_normals: + me.create_normals_split() + me.calc_normals_split() + + normals = [] + for l in me.loops: + nor = v2nors.get(l.vertex_index, [None])[0] + if nor is None: + nor = l.normal + normals.append(nor.to_tuple()) + + me.normals_split_custom_set(normals) + + me.free_normals_split() + bpy.ops.object.mode_set(mode='EDIT') + + return {'FINISHED'} + diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 8019c8d2f34..f97e2d5b2d1 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -431,6 +431,7 @@ class VIEW3D_PT_tools_shading(View3DPanel, Panel): col.label(text="Normals:") col.operator("mesh.normals_make_consistent", text="Recalculate") col.operator("mesh.flip_normals", text="Flip Direction") + col.operator("mesh.set_normals_from_faces", text="Set From Faces") class VIEW3D_PT_tools_uvs(View3DPanel, Panel): From e27d9facdfbdd6d7dade202d6c318accca2f5c3e Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 3 Nov 2016 20:08:04 +0100 Subject: [PATCH 101/590] install_deps cleanup: some Debian stuff was still present in the 'generic compile-only' part of the script. --- build_files/build_environment/install_deps.sh | 9 --------- 1 file changed, 9 deletions(-) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index d6ea7d99f04..7844ff5ffda 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -4023,9 +4023,6 @@ install_OTHER() { fi if [ "$_do_compile_llvm" = true ]; then - install_packages_DEB libffi-dev - # LLVM can't find the debian ffi header dir - _FFI_INCLUDE_DIR=`dpkg -L libffi-dev | grep -e ".*/ffi.h" | sed -r 's/(.*)\/ffi.h/\1/'` PRINT "" compile_LLVM have_llvm=true @@ -4044,7 +4041,6 @@ install_OTHER() { if [ "$_do_compile_osl" = true ]; then if [ "$have_llvm" = true ]; then - install_packages_DEB flex bison libtbb-dev PRINT "" compile_OSL else @@ -4063,7 +4059,6 @@ install_OTHER() { fi if [ "$_do_compile_osd" = true ]; then - install_packages_DEB flex bison libtbb-dev PRINT "" compile_OSD fi @@ -4080,10 +4075,6 @@ install_OTHER() { fi if [ "$_do_compile_collada" = true ]; then - install_packages_DEB libpcre3-dev - # Find path to libxml shared lib... - _XML2_LIB=`dpkg -L libxml2-dev | grep -e ".*/libxml2.so"` - # No package PRINT "" compile_OpenCOLLADA fi From 4a68ff150f47bfeb4d4252473b2b906d14f091c5 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 3 Nov 2016 21:06:10 +0100 Subject: [PATCH 102/590] Fix T49903: Blender crashes -> Append Group incl. Object using boolean modifier New code dealing with getting rid of lib-only cycles of data-blocks could add several time the same datablock to the list of candidates. Now this is avoided, and pointers are further cleaned up as double-safety measure. --- source/blender/blenkernel/intern/library.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 622f79df4ee..5d28a84ef18 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1778,7 +1778,8 @@ void BKE_library_make_local( it->link = NULL; do_loop = true; } - else { /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */ + /* Only used by linked data, potential candidate to ugly lib-only dependency cycles... */ + else if ((id->tag & LIB_TAG_DOIT) == 0) { /* Check TAG_DOIT to avoid adding same ID several times... */ /* 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); @@ -1821,6 +1822,7 @@ void BKE_library_make_local( BKE_libblock_unlink(bmain, id, false, false); BKE_libblock_free(bmain, id); #endif + ((LinkNode *)it->link)->link = NULL; /* Not strictly necessary, but safer (see T49903)... */ it->link = NULL; } } From 4e5d251ccbebd472ed345df753af379919b3cf22 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 4 Nov 2016 08:11:40 +0100 Subject: [PATCH 103/590] Fix T49918: Make duplicates real crash on clicking operator toggles. handle_mutex may be NULL here... --- source/blender/blenkernel/intern/cachefile.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/cachefile.c b/source/blender/blenkernel/intern/cachefile.c index 6a08673144e..deeb35bd880 100644 --- a/source/blender/blenkernel/intern/cachefile.c +++ b/source/blender/blenkernel/intern/cachefile.c @@ -93,7 +93,9 @@ void BKE_cachefile_free(CacheFile *cache_file) ABC_free_handle(cache_file->handle); #endif - BLI_mutex_free(cache_file->handle_mutex); + if (cache_file->handle_mutex) { + BLI_mutex_free(cache_file->handle_mutex); + } BLI_freelistN(&cache_file->object_paths); } From 17fb504bcf5b9c1288e1e5bf9c9b0ebbbc99f96d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 4 Nov 2016 08:30:22 +0100 Subject: [PATCH 104/590] Fix (unreported) asserts in `make_object_duplilist_real()`. Code would try to add multiple time the same key in `parent_gh` (for this ghash a lot of dupliobjects may generate same key). Was making the tool unusable in debug builds. Also optimise things a bit by avoiding creating parent_gh when only `use_base_parent` is set. --- source/blender/editors/object/object_add.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 9f91feee4c6..8e64cdc9751 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1307,7 +1307,9 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (use_hierarchy || use_base_parent) { dupli_gh = BLI_ghash_ptr_new(__func__); - parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + if (use_hierarchy) { + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + } } for (dob = lb->first; dob; dob = dob->next) { @@ -1344,10 +1346,17 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, copy_m4_m4(ob->obmat, dob->mat); BKE_object_apply_mat4(ob, ob->obmat, false, false); - if (dupli_gh) + if (dupli_gh) { BLI_ghash_insert(dupli_gh, dob, ob); - if (parent_gh) - BLI_ghash_insert(parent_gh, dob, ob); + } + if (parent_gh) { + void **val; + /* Due to nature of hash/comparison of this ghash, a lot of duplis may be considered as 'the same', + * this avoids trying to insert same key several time and raise asserts in debug builds... */ + if (!BLI_ghash_ensure_p(parent_gh, dob, &val)) { + *val = ob; + } + } DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } From f0ac661aa8362f5c990b238a2366e2730cd4cb72 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 4 Nov 2016 09:55:46 +0100 Subject: [PATCH 105/590] Fix T49905: Segfault when copying object data of linked object. We have to clear `newid` of all datablocks, not only object ones. Note that this whole stuff is still using some kind of older, primitive 'ID remapping', would like to see whether we can replace it with new, more generic one, but that's for another day. --- source/blender/editors/object/object_relations.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 16ee6f4ed89..f448e925dd9 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1740,10 +1740,16 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in clear_sca_new_poins(); /* sensor/contr/act */ - /* newid may still have some trash from Outliner tree building, - * so clear that first to avoid errors [#26002] */ - for (ob = bmain->object.first; ob; ob = ob->id.next) - ob->id.newid = NULL; + /* newid may still have some trash from Outliner tree building, so clear that first to avoid errors, see T26002. + * We have to clear whole datablocks, not only Object one may be accessed here, see T49905. */ + ListBase *lbarray[MAX_LIBARRAY]; + int a = set_listbasepointers(bmain, lbarray); + while (a--) { + ListBase *lb = lbarray[a]; + for (ID *id = lb->first; id; id = id->next) { + id->newid = NULL; + } + } /* duplicate (must set newid) */ for (base = FIRSTBASE; base; base = base->next) { From c02cce7b752f248b0f3fc4cd55082a9b6400effd Mon Sep 17 00:00:00 2001 From: Martijn Berger Date: Fri, 4 Nov 2016 14:49:54 +0100 Subject: [PATCH 106/590] cycles, cuDeviceComputeCapability is deprecated as of cuda 5.0 --- intern/cycles/device/device_cuda.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 42e9cf75258..73c9221e6a2 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -214,7 +214,8 @@ public: return; int major, minor; - cuDeviceComputeCapability(&major, &minor, cuDevId); + cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevId); + cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevId); cuDevArchitecture = major*100 + minor*10; cuda_pop_context(); @@ -234,7 +235,8 @@ public: bool support_device(const DeviceRequestedFeatures& /*requested_features*/) { int major, minor; - cuDeviceComputeCapability(&major, &minor, cuDevId); + cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevId); + cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevId); /* We only support sm_20 and above */ if(major < 2) { @@ -316,7 +318,8 @@ public: { /* Compute cubin name. */ int major, minor; - cuDeviceComputeCapability(&major, &minor, cuDevId); + cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, cuDevId); + cuDeviceGetAttribute(&minor, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MINOR, cuDevId); /* Attempt to use kernel provided with Blender. */ if(!use_adaptive_compilation()) { @@ -1395,8 +1398,8 @@ void device_cuda_info(vector& devices) if(cuDeviceGetName(name, 256, num) != CUDA_SUCCESS) continue; - int major, minor; - cuDeviceComputeCapability(&major, &minor, num); + int major; + cuDeviceGetAttribute(&major, CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR, num); if(major < 2) { continue; } From 521b98157568deb39d13d45e5bca6e67186e60b6 Mon Sep 17 00:00:00 2001 From: Martijn Berger Date: Sat, 5 Nov 2016 14:23:00 +0100 Subject: [PATCH 107/590] change default for quicktime suport for macOS to off --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bbab208409b..afc1d9d5872 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -333,7 +333,7 @@ option(WITH_ALEMBIC "Enable Alembic Support" OFF) option(WITH_ALEMBIC_HDF5 "Enable Legacy Alembic Support (not officially supported)" OFF) if(APPLE) - option(WITH_CODEC_QUICKTIME "Enable Quicktime Support" ON) + option(WITH_CODEC_QUICKTIME "Enable Quicktime Support" OFF) endif() # 3D format support From 2b1d3318f4c5a8f80f46dbb25ceb80eb86e9fcdc Mon Sep 17 00:00:00 2001 From: lazydodo Date: Sat, 5 Nov 2016 13:58:32 -0600 Subject: [PATCH 108/590] [msvc2015] Add support for copying the vc runtime. There's more dll's hanging out in the ucrt folder, but I just grabbed the ones blender requested (not sure if that's a wise idea, but it seems to work) Reviewers: sergey, juicyfruit Reviewed By: juicyfruit Differential Revision: https://developer.blender.org/D2335 --- source/creator/CMakeLists.txt | 59 +++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index f65688e1304..187df26a375 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1153,13 +1153,12 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE) COMPONENT Blender DESTINATION "." ) - + if(CMAKE_CL_64) + set(_WIN_PLATFORM x64) + else() + set(_WIN_PLATFORM x86) + endif() if(MSVC12_REDIST_DIR) - if(CMAKE_CL_64) - set(_WIN_PLATFORM x64) - else() - set(_WIN_PLATFORM x86) - endif() install( FILES ${MSVC12_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC120.CRT/msvcp120.dll @@ -1173,4 +1172,52 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE) ) endif() endif() + + if(MSVC14_REDIST_DIR) + set(KITSDIRx86 "$ENV{${ProgramFilesX86_NAME}}/Windows Kits/10/") + set(KITSDIR "$ENV{ProgramFiles}/Windows Kits/10/") + if(IS_DIRECTORY ${KITSDIR}) + set(KITSPATH "${KITSDIR}/Redist/ucrt/DLLs/${_WIN_PLATFORM}") + else() + if(IS_DIRECTORY ${KITSDIRx86}) + set(KITSPATH "${KITSDIRx86}/Redist/ucrt/DLLs/${_WIN_PLATFORM}") + else() + message(FATAL_ERROR "Windows 10 SDK directory not found") + endif() + endif() + + install( + FILES + ${KITSPATH}/api-ms-win-core-file-l1-2-0.dll + ${KITSPATH}/api-ms-win-core-file-l2-1-0.dll + ${KITSPATH}/api-ms-win-core-localization-l1-2-0.dll + ${KITSPATH}/api-ms-win-core-processthreads-l1-1-0.dll + ${KITSPATH}/api-ms-win-core-processthreads-l1-1-1.dll + ${KITSPATH}/api-ms-win-core-synch-l1-1-0.dll + ${KITSPATH}/api-ms-win-core-synch-l1-2-0.dll + ${KITSPATH}/api-ms-win-core-timezone-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-conio-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-convert-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-environment-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-filesystem-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-heap-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-locale-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-math-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-process-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-runtime-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-stdio-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-string-l1-1-0.dll + ${KITSPATH}/api-ms-win-crt-time-l1-1-0.dll + ${KITSPATH}/ucrtbase.dll + ${MSVC14_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC140.CRT/vcruntime140.dll + DESTINATION "." + ) + if(WITH_OPENMP) + install( + FILES ${MSVC14_REDIST_DIR}/${_WIN_PLATFORM}/Microsoft.VC140.OpenMP/vcomp140.dll + DESTINATION "." + ) + endif() + Message("KITSPATH = ${KITSPATH}") + endif() endif() From 818af9c3315cb883436a3d75d634f449133cd3d9 Mon Sep 17 00:00:00 2001 From: lazydodo Date: Sat, 5 Nov 2016 14:04:23 -0600 Subject: [PATCH 109/590] MSVC Runtime copy : Remove erroneously left in diagnostic message from CMakeLists.txt --- source/creator/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 187df26a375..10af0d5489e 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1218,6 +1218,5 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE) DESTINATION "." ) endif() - Message("KITSPATH = ${KITSPATH}") endif() endif() From f89fbf580eae6202cef9da08756fd415ca34a8f3 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sun, 6 Nov 2016 19:12:45 +0100 Subject: [PATCH 110/590] Cycles: Fix T49952: Bad MIS sampling of backgrounds with single bright pixels With this fix, using a MIS map resolution equal to the image size for closest imterpolation or twice the size for linear interpolation gets rid of all fireflies. Previously, a much higher resolution was needed to get acceptable noise levels. --- intern/cycles/render/light.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index 777f3229ce6..c43d646f515 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -43,8 +43,8 @@ static void shade_background_pixels(Device *device, DeviceScene *dscene, int res for(int y = 0; y < height; y++) { for(int x = 0; x < width; x++) { - float u = x/(float)width; - float v = y/(float)height; + float u = (x + 0.5f)/width; + float v = (y + 0.5f)/height; uint4 in = make_uint4(__float_as_int(u), __float_as_int(v), 0, 0); d_input_data[x + y*width] = in; From dd921238d9223f550d3043313c9c38d07620de5d Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Mon, 7 Nov 2016 02:33:53 +0100 Subject: [PATCH 111/590] Cycles: Refactor Device selection to allow individual GPU compute device selection Previously, it was only possible to choose a single GPU or all of that type (CUDA or OpenCL). Now, a toggle button is displayed for every device. These settings are tied to the PCI Bus ID of the devices, so they're consistent across hardware addition and removal (but not when swapping/moving cards). From the code perspective, the more important change is that now, the compute device properties are stored in the Addon preferences of the Cycles addon, instead of directly in the User Preferences. This allows for a cleaner implementation, removing the Cycles C API functions that were called by the RNA code to specify the enum items. Note that this change is neither backwards- nor forwards-compatible, but since it's only a User Preference no existing files are broken. Reviewers: #cycles, brecht Reviewed By: #cycles, brecht Subscribers: brecht, juicyfruit, mib2berlin, Blendify Differential Revision: https://developer.blender.org/D2338 --- intern/cycles/blender/CCL_api.h | 11 -- intern/cycles/blender/addon/properties.py | 110 ++++++++++++++++- intern/cycles/blender/addon/ui.py | 36 ++++-- intern/cycles/blender/blender_python.cpp | 91 ++++---------- intern/cycles/blender/blender_sync.cpp | 47 +++++-- intern/cycles/device/device.cpp | 54 +++++--- intern/cycles/device/device.h | 9 +- intern/cycles/device/device_cuda.cpp | 7 +- intern/cycles/device/device_intern.h | 1 - intern/cycles/device/device_multi.cpp | 115 ------------------ intern/cycles/device/device_opencl.cpp | 7 +- intern/cycles/device/opencl/opencl.h | 9 +- intern/cycles/device/opencl/opencl_util.cpp | 25 +++- intern/cycles/render/session.h | 3 +- release/scripts/startup/bl_operators/wm.py | 29 +++++ .../scripts/startup/bl_ui/space_userpref.py | 7 -- source/blender/makesrna/intern/rna_userdef.c | 107 ---------------- .../bad_level_call_stubs/stubs.c | 5 - 18 files changed, 310 insertions(+), 363 deletions(-) diff --git a/intern/cycles/blender/CCL_api.h b/intern/cycles/blender/CCL_api.h index d3a68c4db4f..233ffc8802c 100644 --- a/intern/cycles/blender/CCL_api.h +++ b/intern/cycles/blender/CCL_api.h @@ -21,17 +21,6 @@ extern "C" { #endif -/* returns a list of devices for selection, array is empty identifier - * terminated and must not be freed */ - -typedef struct CCLDeviceInfo { - char identifier[128]; - char name[512]; - int value; -} CCLDeviceInfo; - -CCLDeviceInfo *CCL_compute_device_list(int device_type); - /* create python module _cycles used by addon */ void *CCL_python_module_init(void); diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index a8ab9100ded..27c9b922042 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -21,7 +21,8 @@ from bpy.props import (BoolProperty, EnumProperty, FloatProperty, IntProperty, - PointerProperty) + PointerProperty, + StringProperty) # enums @@ -122,6 +123,12 @@ enum_volume_interpolation = ( ('CUBIC', "Cubic", "Smoothed high quality interpolation, but slower") ) +enum_device_type = ( + ('CPU', "CPU", "CPU", 0), + ('CUDA', "CUDA", "CUDA", 1), + ('OPENCL', "OpenCL", "OpenCL", 2) + ) + class CyclesRenderSettings(bpy.types.PropertyGroup): @classmethod @@ -1130,6 +1137,103 @@ class CyclesCurveSettings(bpy.types.PropertyGroup): del bpy.types.ParticleSettings.cycles +class CyclesDeviceSettings(bpy.types.PropertyGroup): + @classmethod + def register(cls): + cls.id = StringProperty(name="ID") + cls.name = StringProperty(name="Name") + cls.use = BoolProperty(name="Use", default=True) + cls.type = EnumProperty(name="Type", items=enum_device_type, default='CUDA') + + +class CyclesPreferences(bpy.types.AddonPreferences): + bl_idname = __package__ + + def get_device_types(self, context): + import _cycles + has_cuda, has_opencl = _cycles.get_device_types() + list = [('NONE', "None", "Don't use compute device", 0)] + if has_cuda: + list.append(('CUDA', "CUDA", "Use CUDA for GPU acceleration", 1)) + if has_opencl: + list.append(('OPENCL', "OpenCL", "Use OpenCL for GPU acceleration", 2)) + return list + + compute_device_type = EnumProperty( + name="Compute Device Type", + description="Device to use for computation (rendering with Cycles)", + items=get_device_types, + ) + + devices = bpy.props.CollectionProperty(type=CyclesDeviceSettings) + + def get_devices(self): + import _cycles + # Layout of the device tuples: (Name, Type, Internal ID, Persistent ID) + device_list = _cycles.available_devices() + + cuda_devices = [] + opencl_devices = [] + for device in device_list: + if not device[1] in {'CUDA', 'OPENCL'}: + continue + + entry = None + # Try to find existing Device entry + for dev in self.devices: + if dev.id == device[2] and dev.type == device[1]: + entry = dev + break + # Create new entry if no existing one was found + if not entry: + entry = self.devices.add() + entry.id = device[2] + entry.name = device[0] + entry.type = device[1] + + # Sort entries into lists + if entry.type == 'CUDA': + cuda_devices.append(entry) + elif entry.type == 'OPENCL': + opencl_devices.append(entry) + return cuda_devices, opencl_devices + + + def has_active_device(self): + import _cycles + device_list = _cycles.available_devices() + for device in device_list: + if device[1] != self.compute_device_type: + continue + if any(dev.use and dev.id == device[2] for dev in self.devices): + return True + return False + + + def draw_impl(self, layout, context): + layout.label(text="Compute Device:") + layout.row().prop(self, "compute_device_type", expand=True) + + cuda_devices, opencl_devices = self.get_devices() + row = layout.row() + + if cuda_devices: + col = row.column(align=True) + col.label(text="CUDA devices:") + for device in cuda_devices: + col.prop(device, "use", text=device.name, toggle=True) + + if opencl_devices: + col = row.column(align=True) + col.label(text="OpenCL devices:") + for device in opencl_devices: + col.prop(device, "use", text=device.name, toggle=True) + + + def draw(self, context): + self.draw_impl(self.layout, context) + + def register(): bpy.utils.register_class(CyclesRenderSettings) bpy.utils.register_class(CyclesCameraSettings) @@ -1141,6 +1245,8 @@ def register(): bpy.utils.register_class(CyclesObjectSettings) bpy.utils.register_class(CyclesCurveRenderSettings) bpy.utils.register_class(CyclesCurveSettings) + bpy.utils.register_class(CyclesDeviceSettings) + bpy.utils.register_class(CyclesPreferences) def unregister(): @@ -1154,3 +1260,5 @@ def unregister(): bpy.utils.unregister_class(CyclesVisibilitySettings) bpy.utils.unregister_class(CyclesCurveRenderSettings) bpy.utils.unregister_class(CyclesCurveSettings) + bpy.utils.unregister_class(CyclesDeviceSettings) + bpy.utils.unregister_class(CyclesPreferences) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 4942a71ce4d..d9ad7d967a6 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -53,25 +53,26 @@ class CyclesButtonsPanel: return rd.engine in cls.COMPAT_ENGINES +def get_device_type(context): + return context.user_preferences.addons[__package__].preferences.compute_device_type + + def use_cpu(context): cscene = context.scene.cycles - device_type = context.user_preferences.system.compute_device_type - return (device_type == 'NONE' or cscene.device == 'CPU') + return (get_device_type(context) == 'NONE' or cscene.device == 'CPU') def use_opencl(context): cscene = context.scene.cycles - device_type = context.user_preferences.system.compute_device_type - return (device_type == 'OPENCL' and cscene.device == 'GPU') + return (get_device_type(context) == 'OPENCL' and cscene.device == 'GPU') def use_cuda(context): cscene = context.scene.cycles - device_type = context.user_preferences.system.compute_device_type - return (device_type == 'CUDA' and cscene.device == 'GPU') + return (get_device_type(context) == 'CUDA' and cscene.device == 'GPU') def use_branched_path(context): @@ -85,6 +86,14 @@ def use_sample_all_lights(context): return cscene.sample_all_lights_direct or cscene.sample_all_lights_indirect +def show_device_selection(context): + type = get_device_type(context) + if type == 'NETWORK': + return True + if not type in {'CUDA', 'OPENCL'}: + return False + return context.user_preferences.addons[__package__].preferences.has_active_device() + def draw_samples_info(layout, context): cscene = context.scene.cycles @@ -141,7 +150,6 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): scene = context.scene cscene = scene.cycles - device_type = context.user_preferences.system.compute_device_type row = layout.row(align=True) row.menu("CYCLES_MT_sampling_presets", text=bpy.types.CYCLES_MT_sampling_presets.bl_label) @@ -150,7 +158,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): row = layout.row() sub = row.row() - sub.active = device_type != 'OPENCL' or use_cpu(context) + sub.active = get_device_type(context) != 'OPENCL' or use_cpu(context) sub.prop(cscene, "progressive", text="") row.prop(cscene, "use_square_samples") @@ -364,6 +372,8 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): rd = scene.render cscene = scene.cycles + context.user_preferences.addons['cycles'].preferences.draw_impl(layout, context) + split = layout.split() col = split.column(align=True) @@ -1606,9 +1616,13 @@ def draw_device(self, context): layout.prop(cscene, "feature_set") - device_type = context.user_preferences.system.compute_device_type - if device_type in {'CUDA', 'OPENCL', 'NETWORK'}: - layout.prop(cscene, "device") + split = layout.split(percentage=1/3) + split.label("Device:") + row = split.row(align=True) + sub = row.split(align=True) + sub.active = show_device_selection(context) + sub.prop(cscene, "device", text="") + row.operator("wm.addon_userpref_show", text="Preferences", icon='PREFERENCES').module = __package__ if engine.with_osl() and use_cpu(context): layout.prop(cscene, "shading_system") diff --git a/intern/cycles/blender/blender_python.cpp b/intern/cycles/blender/blender_python.cpp index a50f5edb1df..438abc49f88 100644 --- a/intern/cycles/blender/blender_python.cpp +++ b/intern/cycles/blender/blender_python.cpp @@ -40,10 +40,6 @@ CCL_NAMESPACE_BEGIN namespace { -/* Device list stored static (used by compute_device_list()). */ -static ccl::vector device_list; -static ccl::DeviceType device_type = DEVICE_NONE; - /* Flag describing whether debug flags were synchronized from scene. */ bool debug_flags_set = false; @@ -195,7 +191,6 @@ static PyObject *exit_func(PyObject * /*self*/, PyObject * /*args*/) ShaderManager::free_memory(); TaskScheduler::free_memory(); Device::free_memory(); - device_list.free_memory(); Py_RETURN_NONE; } @@ -389,7 +384,12 @@ static PyObject *available_devices_func(PyObject * /*self*/, PyObject * /*args*/ for(size_t i = 0; i < devices.size(); i++) { DeviceInfo& device = devices[i]; - PyTuple_SET_ITEM(ret, i, PyUnicode_FromString(device.description.c_str())); + string type_name = Device::string_from_type(device.type); + PyObject *device_tuple = PyTuple_New(3); + PyTuple_SET_ITEM(device_tuple, 0, PyUnicode_FromString(device.description.c_str())); + PyTuple_SET_ITEM(device_tuple, 1, PyUnicode_FromString(type_name.c_str())); + PyTuple_SET_ITEM(device_tuple, 2, PyUnicode_FromString(device.id.c_str())); + PyTuple_SET_ITEM(ret, i, device_tuple); } return ret; @@ -676,6 +676,20 @@ static PyObject *set_resumable_chunks_func(PyObject * /*self*/, PyObject *args) Py_RETURN_NONE; } +static PyObject *get_device_types_func(PyObject * /*self*/, PyObject * /*args*/) +{ + vector& devices = Device::available_devices(); + bool has_cuda = false, has_opencl = false; + for(int i = 0; i < devices.size(); i++) { + has_cuda |= (devices[i].type == DEVICE_CUDA); + has_opencl |= (devices[i].type == DEVICE_OPENCL); + } + PyObject *list = PyTuple_New(2); + PyTuple_SET_ITEM(list, 0, PyBool_FromLong(has_cuda)); + PyTuple_SET_ITEM(list, 1, PyBool_FromLong(has_opencl)); + return list; +} + static PyMethodDef methods[] = { {"init", init_func, METH_VARARGS, ""}, {"exit", exit_func, METH_VARARGS, ""}, @@ -703,6 +717,9 @@ static PyMethodDef methods[] = { /* Resumable render */ {"set_resumable_chunks", set_resumable_chunks_func, METH_VARARGS, ""}, + /* Compute Device selection */ + {"get_device_types", get_device_types_func, METH_VARARGS, ""}, + {NULL, NULL, 0, NULL}, }; @@ -715,47 +732,6 @@ static struct PyModuleDef module = { NULL, NULL, NULL, NULL }; -static CCLDeviceInfo *compute_device_list(DeviceType type) -{ - /* create device list if it's not already done */ - if(type != device_type) { - ccl::vector& devices = ccl::Device::available_devices(); - - device_type = type; - device_list.clear(); - - /* add devices */ - int i = 0; - - foreach(DeviceInfo& info, devices) { - if(info.type == type || - (info.type == DEVICE_MULTI && info.multi_devices[0].type == type)) - { - CCLDeviceInfo cinfo; - - strncpy(cinfo.identifier, info.id.c_str(), sizeof(cinfo.identifier)); - cinfo.identifier[info.id.length()] = '\0'; - - strncpy(cinfo.name, info.description.c_str(), sizeof(cinfo.name)); - cinfo.name[info.description.length()] = '\0'; - - cinfo.value = i++; - - device_list.push_back(cinfo); - } - } - - /* null terminate */ - if(!device_list.empty()) { - CCLDeviceInfo cinfo = {"", "", 0}; - device_list.push_back(cinfo); - } - } - - return (device_list.empty())? NULL: &device_list[0]; -} - - CCL_NAMESPACE_END void *CCL_python_module_init() @@ -794,24 +770,3 @@ void *CCL_python_module_init() return (void*)mod; } - -CCLDeviceInfo *CCL_compute_device_list(int device_type) -{ - ccl::DeviceType type; - switch(device_type) { - case 0: - type = ccl::DEVICE_CUDA; - break; - case 1: - type = ccl::DEVICE_OPENCL; - break; - case 2: - type = ccl::DEVICE_NETWORK; - break; - default: - type = ccl::DEVICE_NONE; - break; - } - return ccl::compute_device_list(type); -} - diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index bc5c3bb8096..6e466826c35 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -531,7 +531,12 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, vector& devices = Device::available_devices(); /* device default CPU */ - params.device = devices[0]; + foreach(DeviceInfo& device, devices) { + if(device.type == DEVICE_CPU) { + params.device = device; + break; + } + } if(get_enum(cscene, "device") == 2) { /* find network device */ @@ -540,17 +545,39 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine& b_engine, params.device = info; } else if(get_enum(cscene, "device") == 1) { - /* find GPU device with given id */ - PointerRNA systemptr = b_userpref.system().ptr; - PropertyRNA *deviceprop = RNA_struct_find_property(&systemptr, "compute_device"); - int device_id = b_userpref.system().compute_device(); + PointerRNA b_preferences; - const char *id; + BL::UserPreferences::addons_iterator b_addon_iter; + for(b_userpref.addons.begin(b_addon_iter); b_addon_iter != b_userpref.addons.end(); ++b_addon_iter) { + if(b_addon_iter->module() == "cycles") { + b_preferences = b_addon_iter->preferences().ptr; + break; + } + } - if(RNA_property_enum_identifier(NULL, &systemptr, deviceprop, device_id, &id)) { - foreach(DeviceInfo& info, devices) - if(info.id == id) - params.device = info; + int compute_device = get_enum(b_preferences, "compute_device_type"); + + if(compute_device != 0) { + vector used_devices; + RNA_BEGIN(&b_preferences, device, "devices") { + if(get_enum(device, "type") == compute_device && get_boolean(device, "use")) { + string id = get_string(device, "id"); + foreach(DeviceInfo& info, devices) { + if(info.id == id) { + used_devices.push_back(info); + break; + } + } + } + } RNA_END + + if(used_devices.size() == 1) { + params.device = used_devices[0]; + } + else if(used_devices.size() > 1) { + params.device = Device::get_multi_device(used_devices); + } + /* Else keep using the CPU device that was set before. */ } } diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 909ec7a6d60..ff9387b0a8a 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -258,33 +258,33 @@ Device *Device::create(DeviceInfo& info, Stats &stats, bool background) DeviceType Device::type_from_string(const char *name) { - if(strcmp(name, "cpu") == 0) + if(strcmp(name, "CPU") == 0) return DEVICE_CPU; - else if(strcmp(name, "cuda") == 0) + else if(strcmp(name, "CUDA") == 0) return DEVICE_CUDA; - else if(strcmp(name, "opencl") == 0) + else if(strcmp(name, "OPENCL") == 0) return DEVICE_OPENCL; - else if(strcmp(name, "network") == 0) + else if(strcmp(name, "NETWORK") == 0) return DEVICE_NETWORK; - else if(strcmp(name, "multi") == 0) + else if(strcmp(name, "MULTI") == 0) return DEVICE_MULTI; - + return DEVICE_NONE; } string Device::string_from_type(DeviceType type) { if(type == DEVICE_CPU) - return "cpu"; + return "CPU"; else if(type == DEVICE_CUDA) - return "cuda"; + return "CUDA"; else if(type == DEVICE_OPENCL) - return "opencl"; + return "OPENCL"; else if(type == DEVICE_NETWORK) - return "network"; + return "NETWORK"; else if(type == DEVICE_MULTI) - return "multi"; - + return "MULTI"; + return ""; } @@ -307,9 +307,6 @@ vector& Device::available_types() #ifdef WITH_NETWORK types.push_back(DEVICE_NETWORK); #endif -#ifdef WITH_MULTI - types.push_back(DEVICE_MULTI); -#endif need_types_update = false; } @@ -331,10 +328,6 @@ vector& Device::available_devices() device_opencl_info(devices); #endif -#ifdef WITH_MULTI - device_multi_info(devices); -#endif - device_cpu_info(devices); #ifdef WITH_NETWORK @@ -368,6 +361,29 @@ string Device::device_capabilities() return capabilities; } +DeviceInfo Device::get_multi_device(vector subdevices) +{ + assert(subdevices.size() > 1); + + DeviceInfo info; + info.type = DEVICE_MULTI; + info.id = "MULTI"; + info.description = "Multi Device"; + info.multi_devices = subdevices; + info.num = 0; + + info.has_bindless_textures = true; + info.pack_images = false; + foreach(DeviceInfo &device, subdevices) { + assert(device.type == info.multi_devices[0].type); + + info.pack_images |= device.pack_images; + info.has_bindless_textures &= device.has_bindless_textures; + } + + return info; +} + void Device::tag_update() { need_types_update = true; diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 77dc1fa9713..b9bdffa2618 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -49,7 +49,7 @@ class DeviceInfo { public: DeviceType type; string description; - string id; + string id; /* used for user preferences, should stay fixed with changing hardware config */ int num; bool display_device; bool advanced_shading; @@ -69,6 +69,12 @@ public: has_bindless_textures = false; use_split_kernel = false; } + + bool operator==(const DeviceInfo &info) { + /* Multiple Devices with the same ID would be very bad. */ + assert(id != info.id || (type == info.type && num == info.num && description == info.description)); + return id == info.id; + } }; class DeviceRequestedFeatures { @@ -282,6 +288,7 @@ public: static vector& available_types(); static vector& available_devices(); static string device_capabilities(); + static DeviceInfo get_multi_device(vector subdevices); /* Tag devices lists for update. */ static void tag_update(); diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 73c9221e6a2..a4818aa3b8d 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -1408,13 +1408,18 @@ void device_cuda_info(vector& devices) info.type = DEVICE_CUDA; info.description = string(name); - info.id = string_printf("CUDA_%d", num); info.num = num; info.advanced_shading = (major >= 2); info.has_bindless_textures = (major >= 3); info.pack_images = false; + int pci_location[3] = {0, 0, 0}; + cuDeviceGetAttribute(&pci_location[0], CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID, num); + cuDeviceGetAttribute(&pci_location[1], CU_DEVICE_ATTRIBUTE_PCI_BUS_ID, num); + cuDeviceGetAttribute(&pci_location[2], CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID, num); + info.id = string_printf("CUDA_%s_%04x:%02x:%02x", name, pci_location[0], pci_location[1], pci_location[2]); + /* if device has a kernel timeout, assume it is used for display */ if(cuDeviceGetAttribute(&attr, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, num) == CUDA_SUCCESS && attr == 1) { info.description += " (Display)"; diff --git a/intern/cycles/device/device_intern.h b/intern/cycles/device/device_intern.h index 47584ae6d22..de487649045 100644 --- a/intern/cycles/device/device_intern.h +++ b/intern/cycles/device/device_intern.h @@ -33,7 +33,6 @@ void device_cpu_info(vector& devices); void device_opencl_info(vector& devices); void device_cuda_info(vector& devices); void device_network_info(vector& devices); -void device_multi_info(vector& devices); string device_cpu_capabilities(void); string device_opencl_capabilities(void); diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index ef257358b22..48fd159d508 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -350,120 +350,5 @@ Device *device_multi_create(DeviceInfo& info, Stats &stats, bool background) return new MultiDevice(info, stats, background); } -static bool device_multi_add(vector& devices, DeviceType type, bool with_display, bool with_advanced_shading, const char *id_fmt, int num) -{ - DeviceInfo info; - - /* create map to find duplicate descriptions */ - map dupli_map; - map::iterator dt; - int num_added = 0, num_display = 0; - - info.advanced_shading = with_advanced_shading; - info.pack_images = false; - info.has_bindless_textures = true; - - foreach(DeviceInfo& subinfo, devices) { - if(subinfo.type == type) { - if(subinfo.advanced_shading != info.advanced_shading) - continue; - if(subinfo.display_device) { - if(with_display) - num_display++; - else - continue; - } - - string key = subinfo.description; - - if(dupli_map.find(key) == dupli_map.end()) - dupli_map[key] = 1; - else - dupli_map[key]++; - - info.multi_devices.push_back(subinfo); - if(subinfo.display_device) - info.display_device = true; - info.pack_images = info.pack_images || subinfo.pack_images; - info.has_bindless_textures = info.has_bindless_textures && subinfo.has_bindless_textures; - num_added++; - } - } - - if(num_added <= 1 || (with_display && num_display == 0)) - return false; - - /* generate string */ - stringstream desc; - vector last_tokens; - bool first = true; - - for(dt = dupli_map.begin(); dt != dupli_map.end(); dt++) { - if(!first) desc << " + "; - first = false; - - /* get name and count */ - string name = dt->first; - int count = dt->second; - - /* strip common prefixes */ - vector tokens; - string_split(tokens, dt->first); - - if(tokens.size() > 1) { - int i; - - for(i = 0; i < tokens.size() && i < last_tokens.size(); i++) - if(tokens[i] != last_tokens[i]) - break; - - name = ""; - for(; i < tokens.size(); i++) { - name += tokens[i]; - if(i != tokens.size() - 1) - name += " "; - } - } - - last_tokens = tokens; - - /* add */ - if(count > 1) - desc << name << " (" << count << "x)"; - else - desc << name; - } - - /* add info */ - info.type = DEVICE_MULTI; - info.description = desc.str(); - info.id = string_printf(id_fmt, num); - info.display_device = with_display; - info.num = 0; - - if(with_display) - devices.push_back(info); - else - devices.insert(devices.begin(), info); - - return true; -} - -void device_multi_info(vector& devices) -{ - int num = 0; - - if(!device_multi_add(devices, DEVICE_CUDA, false, true, "CUDA_MULTI_%d", num++)) - device_multi_add(devices, DEVICE_CUDA, false, false, "CUDA_MULTI_%d", num++); - if(!device_multi_add(devices, DEVICE_CUDA, true, true, "CUDA_MULTI_%d", num++)) - device_multi_add(devices, DEVICE_CUDA, true, false, "CUDA_MULTI_%d", num++); - - num = 0; - if(!device_multi_add(devices, DEVICE_OPENCL, false, true, "OPENCL_MULTI_%d", num++)) - device_multi_add(devices, DEVICE_OPENCL, false, false, "OPENCL_MULTI_%d", num++); - if(!device_multi_add(devices, DEVICE_OPENCL, true, true, "OPENCL_MULTI_%d", num++)) - device_multi_add(devices, DEVICE_OPENCL, true, false, "OPENCL_MULTI_%d", num++); -} - CCL_NAMESPACE_END diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index 45cf6b074e9..ba94c592a5f 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -83,17 +83,22 @@ void device_opencl_info(vector& devices) const string& platform_name = platform_device.platform_name; const cl_device_type device_type = platform_device.device_type; const string& device_name = platform_device.device_name; + string hardware_id = platform_device.hardware_id; + if(hardware_id == "") { + hardware_id = string_printf("ID_%d", num_devices); + } + DeviceInfo info; info.type = DEVICE_OPENCL; info.description = string_remove_trademark(string(device_name)); info.num = num_devices; - info.id = string_printf("OPENCL_%d", info.num); /* We don't know if it's used for display, but assume it is. */ info.display_device = true; info.advanced_shading = OpenCLInfo::kernel_use_advanced_shading(platform_name); info.pack_images = true; info.use_split_kernel = OpenCLInfo::kernel_use_split(platform_name, device_type); + info.id = string("OPENCL_") + platform_name + "_" + device_name + "_" + hardware_id; devices.push_back(info); num_devices++; } diff --git a/intern/cycles/device/opencl/opencl.h b/intern/cycles/device/opencl/opencl.h index 30a35acbb2a..054ac9014f0 100644 --- a/intern/cycles/device/opencl/opencl.h +++ b/intern/cycles/device/opencl/opencl.h @@ -55,17 +55,20 @@ struct OpenCLPlatformDevice { const string& platform_name, cl_device_id device_id, cl_device_type device_type, - const string& device_name) + const string& device_name, + const string& hardware_id) : platform_id(platform_id), platform_name(platform_name), device_id(device_id), device_type(device_type), - device_name(device_name) {} + device_name(device_name), + hardware_id(hardware_id) {} cl_platform_id platform_id; string platform_name; cl_device_id device_id; cl_device_type device_type; string device_name; + string hardware_id; }; /* Contains all static OpenCL helper functions. */ @@ -83,6 +86,8 @@ public: string *error = NULL); static bool device_version_check(cl_device_id device, string *error = NULL); + static string get_hardware_id(string platform_name, + cl_device_id device_id); static void get_usable_devices(vector *usable_devices, bool force_all = false); }; diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp index e425ae8e2e8..36eb70b8c85 100644 --- a/intern/cycles/device/opencl/opencl_util.cpp +++ b/intern/cycles/device/opencl/opencl_util.cpp @@ -661,6 +661,27 @@ bool OpenCLInfo::device_version_check(cl_device_id device, return true; } +string OpenCLInfo::get_hardware_id(string platform_name, cl_device_id device_id) +{ + if(platform_name == "AMD Accelerated Parallel Processing" || platform_name == "Apple") { + /* Use cl_amd_device_topology extension. */ + cl_char topology[24]; + if(clGetDeviceInfo(device_id, 0x4037, sizeof(topology), topology, NULL) == CL_SUCCESS && topology[0] == 1) { + return string_printf("%02x:%02x.%01x", topology[21], topology[22], topology[23]); + } + } + else if(platform_name == "NVIDIA CUDA") { + /* Use two undocumented options of the cl_nv_device_attribute_query extension. */ + cl_int bus_id, slot_id; + if(clGetDeviceInfo(device_id, 0x4008, sizeof(cl_int), &bus_id, NULL) == CL_SUCCESS && + clGetDeviceInfo(device_id, 0x4009, sizeof(cl_int), &slot_id, NULL) == CL_SUCCESS) { + return string_printf("%02x:%02x.%01x", bus_id, slot_id>>3, slot_id & 0x7); + } + } + /* No general way to get a hardware ID from OpenCL => give up. */ + return ""; +} + void OpenCLInfo::get_usable_devices(vector *usable_devices, bool force_all) { @@ -773,11 +794,13 @@ void OpenCLInfo::get_usable_devices(vector *usable_devices continue; } FIRST_VLOG(2) << "Adding new device " << device_name << "."; + string hardware_id = get_hardware_id(platform_name, device_id); usable_devices->push_back(OpenCLPlatformDevice(platform_id, platform_name, device_id, device_type, - device_name)); + device_name, + hardware_id)); } else { FIRST_VLOG(2) << "Ignoring device " << device_name diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 8bff0f9ed15..1db4692e171 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -89,8 +89,7 @@ public: } bool modified(const SessionParams& params) - { return !(device.type == params.device.type - && device.id == params.device.id + { return !(device == params.device && background == params.background && progressive_refine == params.progressive_refine && output_path == params.output_path diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 1c97d213e05..343fcdb0d22 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -2163,3 +2163,32 @@ class WM_OT_addon_expand(Operator): info["show_expanded"] = not info["show_expanded"] return {'FINISHED'} + +class WM_OT_addon_userpref_show(Operator): + "Show add-on user preferences" + bl_idname = "wm.addon_userpref_show" + bl_label = "" + bl_options = {'INTERNAL'} + + module = StringProperty( + name="Module", + description="Module name of the add-on to expand", + ) + + def execute(self, context): + import addon_utils + + module_name = self.module + + modules = addon_utils.modules(refresh=False) + mod = addon_utils.addons_fake_modules.get(module_name) + if mod is not None: + info = addon_utils.module_bl_info(mod) + info["show_expanded"] = True + + bpy.context.user_preferences.active_section = 'ADDONS' + context.window_manager.addon_filter = 'All' + context.window_manager.addon_search = info["name"] + bpy.ops.screen.userpref_show('INVOKE_DEFAULT') + + return {'FINISHED'} diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index dcafac66fca..ab3ec3559e5 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -429,13 +429,6 @@ class USERPREF_PT_system(Panel): col.separator() - if hasattr(system, "compute_device_type"): - col.label(text="Compute Device:") - col.row().prop(system, "compute_device_type", expand=True) - sub = col.row() - sub.active = system.compute_device_type != 'CPU' - sub.prop(system, "compute_device", text="") - if hasattr(system, "opensubdiv_compute_type"): col.label(text="OpenSubdiv compute:") col.row().prop(system, "opensubdiv_compute_type", text="") diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 8ad016007f4..10807c32b91 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -52,15 +52,6 @@ #include "BLT_lang.h" #include "GPU_buffers.h" -#ifdef WITH_CYCLES -static EnumPropertyItem compute_device_type_items[] = { - {USER_COMPUTE_DEVICE_NONE, "NONE", 0, "None", "Don't use compute device"}, - {USER_COMPUTE_DEVICE_CUDA, "CUDA", 0, "CUDA", "Use CUDA for GPU acceleration"}, - {USER_COMPUTE_DEVICE_OPENCL, "OPENCL", 0, "OpenCL", "Use OpenCL for GPU acceleration"}, - { 0, NULL, 0, NULL, NULL} -}; -#endif - #ifdef WITH_OPENSUBDIV static EnumPropertyItem opensubdiv_compute_type_items[] = { {USER_OPENSUBDIV_COMPUTE_NONE, "NONE", 0, "None", ""}, @@ -124,8 +115,6 @@ static EnumPropertyItem rna_enum_language_default_items[] = { #include "UI_interface.h" -#include "CCL_api.h" - #ifdef WITH_OPENSUBDIV # include "opensubdiv_capi.h" #endif @@ -476,78 +465,6 @@ static PointerRNA rna_Theme_space_list_generic_get(PointerRNA *ptr) } -#ifdef WITH_CYCLES -static EnumPropertyItem *rna_userdef_compute_device_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), bool *r_free) -{ - EnumPropertyItem *item = NULL; - int totitem = 0; - - /* add supported device types */ - RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_NONE); - if (CCL_compute_device_list(0)) - RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_CUDA); - if (CCL_compute_device_list(1)) - RNA_enum_items_add_value(&item, &totitem, compute_device_type_items, USER_COMPUTE_DEVICE_OPENCL); - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; -} - -static int rna_userdef_compute_device_get(PointerRNA *UNUSED(ptr)) -{ - if (U.compute_device_type == USER_COMPUTE_DEVICE_NONE) - return 0; - - return U.compute_device_id; -} - -static EnumPropertyItem *rna_userdef_compute_device_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), bool *r_free) -{ - EnumPropertyItem tmp = {0, "", 0, "", ""}; - EnumPropertyItem *item = NULL; - int totitem = 0; - - if (U.compute_device_type == USER_COMPUTE_DEVICE_NONE) { - /* only add a single CPU device */ - tmp.value = 0; - tmp.name = "CPU"; - tmp.identifier = "CPU"; - RNA_enum_item_add(&item, &totitem, &tmp); - } - else { - /* get device list from cycles. it would be good to make this generic - * once we have more subsystems using opencl, for now this is easiest */ - int opencl = (U.compute_device_type == USER_COMPUTE_DEVICE_OPENCL); - CCLDeviceInfo *devices = CCL_compute_device_list(opencl); - int a; - - if (devices) { - for (a = 0; devices[a].identifier[0]; a++) { - tmp.value = devices[a].value; - tmp.identifier = devices[a].identifier; - tmp.name = devices[a].name; - RNA_enum_item_add(&item, &totitem, &tmp); - } - } - else { - tmp.value = 0; - tmp.name = "CPU"; - tmp.identifier = "CPU"; - RNA_enum_item_add(&item, &totitem, &tmp); - } - } - - RNA_enum_item_end(&item, &totitem); - *r_free = true; - - return item; -} -#endif - #ifdef WITH_OPENSUBDIV static EnumPropertyItem *rna_userdef_opensubdiv_compute_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) @@ -3977,13 +3894,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; -#ifdef WITH_CYCLES - static EnumPropertyItem compute_device_items[] = { - {0, "CPU", 0, "CPU", ""}, - { 0, NULL, 0, NULL, NULL} - }; -#endif - static EnumPropertyItem image_draw_methods[] = { {IMAGE_DRAW_METHOD_2DTEXTURE, "2DTEXTURE", 0, "2D Texture", "Use CPU for display transform and draw image with 2D texture"}, {IMAGE_DRAW_METHOD_GLSL, "GLSL", 0, "GLSL", "Use GLSL shaders for display transform and draw image with 2D texture"}, @@ -4275,23 +4185,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) "Draw tool/property regions over the main region, when using Triple Buffer"); RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); -#ifdef WITH_CYCLES - prop = RNA_def_property(srna, "compute_device_type", PROP_ENUM, PROP_NONE); - RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); - RNA_def_property_enum_sdna(prop, NULL, "compute_device_type"); - RNA_def_property_enum_items(prop, compute_device_type_items); - RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_userdef_compute_device_type_itemf"); - RNA_def_property_ui_text(prop, "Compute Device Type", "Device to use for computation (rendering with Cycles)"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, NULL); - - prop = RNA_def_property(srna, "compute_device", PROP_ENUM, PROP_NONE); - RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); - RNA_def_property_enum_sdna(prop, NULL, "compute_device_id"); - RNA_def_property_enum_items(prop, compute_device_items); - RNA_def_property_enum_funcs(prop, "rna_userdef_compute_device_get", NULL, "rna_userdef_compute_device_itemf"); - RNA_def_property_ui_text(prop, "Compute Device", "Device to use for computation"); -#endif - #ifdef WITH_OPENSUBDIV prop = RNA_def_property(srna, "opensubdiv_compute_type", PROP_ENUM, PROP_NONE); RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT); diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index d8a4ddc8d4f..6040dfff644 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -142,7 +142,6 @@ struct wmWindowManager; # pragma GCC diagnostic ignored "-Wunused-parameter" #endif -#include "../../intern/cycles/blender/CCL_api.h" #include "../../intern/dualcon/dualcon.h" #include "../../intern/elbeem/extern/elbeem.h" #include "../blender/blenkernel/BKE_modifier.h" @@ -770,10 +769,6 @@ void *dualcon(const DualConInput *input_mesh, float scale, int depth) RET_ZERO -/* intern/cycles */ -struct CCLDeviceInfo; -struct CCLDeviceInfo *CCL_compute_device_list(int opencl) RET_NULL - /* compositor */ void COM_execute(RenderData *rd, Scene *scene, bNodeTree *editingtree, int rendering, const ColorManagedViewSettings *viewSettings, const ColorManagedDisplaySettings *displaySettings, From c8c7414c3f6768b5cb54d56ff7999d0a0ca22bc6 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Mon, 7 Nov 2016 12:56:58 +0300 Subject: [PATCH 112/590] Expose Bullet rotational spring settings in the UI. Bullet spring constraint already supports rotational springs, but they are not exposed in blender UI, likely due to a simple oversight. Supporting them is as simple as adding a few DNA/RNA properties with appropriate UI and passing them on to Bullet. Reviewers: sergof Reviewed By: sergof Differential Revision: https://developer.blender.org/D2331 --- ...properties_physics_rigidbody_constraint.py | 48 ++++-- source/blender/blenkernel/intern/rigidbody.c | 18 +++ .../blenloader/intern/versioning_270.c | 16 ++ source/blender/makesdna/DNA_rigidbody_types.h | 12 +- .../blender/makesrna/intern/rna_rigidbody.c | 142 ++++++++++++++++++ 5 files changed, 226 insertions(+), 10 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py index 38c97746f4a..9d4f51b256b 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody_constraint.py @@ -205,30 +205,60 @@ class PHYSICS_PT_rigid_body_constraint(PHYSICS_PT_rigidbody_constraint_panel, Pa row = col.row(align=True) sub = row.row(align=True) - sub.scale_x = 0.1 - sub.prop(rbc, "use_spring_x", toggle=True, text="X") + sub.scale_x = 0.5 + sub.prop(rbc, "use_spring_x", toggle=True, text="X Axis") sub = row.row(align=True) sub.active = rbc.use_spring_x sub.prop(rbc, "spring_stiffness_x", text="Stiffness") - sub.prop(rbc, "spring_damping_x") + sub.prop(rbc, "spring_damping_x", text="Damping") row = col.row(align=True) sub = row.row(align=True) - sub.scale_x = 0.1 - sub.prop(rbc, "use_spring_y", toggle=True, text="Y") + sub.scale_x = 0.5 + sub.prop(rbc, "use_spring_y", toggle=True, text="Y Axis") sub = row.row(align=True) sub.active = rbc.use_spring_y sub.prop(rbc, "spring_stiffness_y", text="Stiffness") - sub.prop(rbc, "spring_damping_y") + sub.prop(rbc, "spring_damping_y", text="Damping") row = col.row(align=True) sub = row.row(align=True) - sub.scale_x = 0.1 - sub.prop(rbc, "use_spring_z", toggle=True, text="Z") + sub.scale_x = 0.5 + sub.prop(rbc, "use_spring_z", toggle=True, text="Z Axis") sub = row.row(align=True) sub.active = rbc.use_spring_z sub.prop(rbc, "spring_stiffness_z", text="Stiffness") - sub.prop(rbc, "spring_damping_z") + sub.prop(rbc, "spring_damping_z", text="Damping") + + col = layout.column(align=True) + + row = col.row(align=True) + sub = row.row(align=True) + sub.scale_x = 0.5 + sub.prop(rbc, "use_spring_ang_x", toggle=True, text="X Angle") + sub = row.row(align=True) + sub.active = rbc.use_spring_ang_x + sub.prop(rbc, "spring_stiffness_ang_x", text="Stiffness") + sub.prop(rbc, "spring_damping_ang_x", text="Damping") + + row = col.row(align=True) + sub = row.row(align=True) + sub.scale_x = 0.5 + sub.prop(rbc, "use_spring_ang_y", toggle=True, text="Y Angle") + sub = row.row(align=True) + sub.active = rbc.use_spring_ang_y + sub.prop(rbc, "spring_stiffness_ang_y", text="Stiffness") + sub.prop(rbc, "spring_damping_ang_y", text="Damping") + + row = col.row(align=True) + sub = row.row(align=True) + sub.scale_x = 0.5 + sub.prop(rbc, "use_spring_ang_z", toggle=True, text="Z Angle") + sub = row.row(align=True) + sub.active = rbc.use_spring_ang_z + sub.prop(rbc, "spring_stiffness_ang_z", text="Stiffness") + sub.prop(rbc, "spring_damping_ang_z", text="Damping") + if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index c3ae5736aa9..f8e96225f36 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -804,6 +804,18 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_stiffness_z); RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_LIN_Z, rbc->spring_damping_z); + RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->flag & RBC_FLAG_USE_SPRING_ANG_X); + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_stiffness_ang_x); + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, rbc->spring_damping_ang_x); + + RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y); + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_stiffness_ang_y); + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, rbc->spring_damping_ang_y); + + RB_constraint_set_spring_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z); + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_stiffness_ang_z); + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, rbc->spring_damping_ang_z); + RB_constraint_set_equilibrium_6dof_spring(rbc->physics_constraint); /* fall-through */ case RBC_TYPE_6DOF: @@ -1072,9 +1084,15 @@ RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short ty rbc->spring_damping_x = 0.5f; rbc->spring_damping_y = 0.5f; rbc->spring_damping_z = 0.5f; + rbc->spring_damping_ang_x = 0.5f; + rbc->spring_damping_ang_y = 0.5f; + rbc->spring_damping_ang_z = 0.5f; rbc->spring_stiffness_x = 10.0f; rbc->spring_stiffness_y = 10.0f; rbc->spring_stiffness_z = 10.0f; + rbc->spring_stiffness_ang_x = 10.0f; + rbc->spring_stiffness_ang_y = 10.0f; + rbc->spring_stiffness_ang_z = 10.0f; rbc->motor_lin_max_impulse = 1.0f; rbc->motor_lin_target_velocity = 1.0f; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 14e02c9ffb6..8e855eb56b8 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -53,6 +53,7 @@ #include "DNA_actuator_types.h" #include "DNA_view3d_types.h" #include "DNA_smoke_types.h" +#include "DNA_rigidbody_types.h" #include "DNA_genfile.h" @@ -1438,5 +1439,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + if (!DNA_struct_elem_find(fd->filesdna, "RigidBodyCon", "float", "spring_stiffness_ang_x")) { + Object *ob; + for (ob = main->object.first; ob; ob = ob->id.next) { + RigidBodyCon *rbc = ob->rigidbody_constraint; + if (rbc) { + rbc->spring_stiffness_ang_x = 10.0; + rbc->spring_stiffness_ang_y = 10.0; + rbc->spring_stiffness_ang_z = 10.0; + rbc->spring_damping_ang_x = 0.5; + rbc->spring_damping_ang_y = 0.5; + rbc->spring_damping_ang_z = 0.5; + } + } + } } } diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h index 5d76ffe57b5..381ee5d40e5 100644 --- a/source/blender/makesdna/DNA_rigidbody_types.h +++ b/source/blender/makesdna/DNA_rigidbody_types.h @@ -226,10 +226,16 @@ typedef struct RigidBodyCon { float spring_stiffness_x; float spring_stiffness_y; float spring_stiffness_z; + float spring_stiffness_ang_x; + float spring_stiffness_ang_y; + float spring_stiffness_ang_z; /* amount of velocity lost over time */ float spring_damping_x; float spring_damping_y; float spring_damping_z; + float spring_damping_ang_x; + float spring_damping_ang_y; + float spring_damping_ang_z; /* motor settings */ float motor_lin_target_velocity; /* linear velocity the motor tries to hold */ @@ -295,7 +301,11 @@ typedef enum eRigidBodyCon_Flag { RBC_FLAG_USE_SPRING_Z = (1 << 13), /* motors */ RBC_FLAG_USE_MOTOR_LIN = (1 << 14), - RBC_FLAG_USE_MOTOR_ANG = (1 << 15) + RBC_FLAG_USE_MOTOR_ANG = (1 << 15), + /* angular springs */ + RBC_FLAG_USE_SPRING_ANG_X = (1 << 16), + RBC_FLAG_USE_SPRING_ANG_Y = (1 << 17), + RBC_FLAG_USE_SPRING_ANG_Z = (1 << 18) } eRigidBodyCon_Flag; /* ******************************** */ diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index bdf001ed0e1..85a34a94746 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -507,6 +507,45 @@ static void rna_RigidBodyCon_spring_stiffness_z_set(PointerRNA *ptr, float value #endif } +static void rna_RigidBodyCon_spring_stiffness_ang_x_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_stiffness_ang_x = value; + +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_X)) { + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, value); + } +#endif +} + +static void rna_RigidBodyCon_spring_stiffness_ang_y_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_stiffness_ang_y = value; + +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y)) { + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, value); + } +#endif +} + +static void rna_RigidBodyCon_spring_stiffness_ang_z_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_stiffness_ang_z = value; + +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z)) { + RB_constraint_set_stiffness_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, value); + } +#endif +} + static void rna_RigidBodyCon_spring_damping_x_set(PointerRNA *ptr, float value) { RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; @@ -544,6 +583,43 @@ static void rna_RigidBodyCon_spring_damping_z_set(PointerRNA *ptr, float value) #endif } +static void rna_RigidBodyCon_spring_damping_ang_x_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_damping_ang_x = value; + +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_X)) { + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_X, value); + } +#endif +} + +static void rna_RigidBodyCon_spring_damping_ang_y_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_damping_ang_y = value; +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Y)) { + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Y, value); + } +#endif +} + +static void rna_RigidBodyCon_spring_damping_ang_z_set(PointerRNA *ptr, float value) +{ + RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; + + rbc->spring_damping_ang_z = value; +#ifdef WITH_BULLET + if (rbc->physics_constraint && rbc->type == RBC_TYPE_6DOF_SPRING && (rbc->flag & RBC_FLAG_USE_SPRING_ANG_Z)) { + RB_constraint_set_damping_6dof_spring(rbc->physics_constraint, RB_LIMIT_ANG_Z, value); + } +#endif +} + static void rna_RigidBodyCon_motor_lin_max_impulse_set(PointerRNA *ptr, float value) { RigidBodyCon *rbc = (RigidBodyCon *)ptr->data; @@ -1061,6 +1137,21 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Z Spring", "Enable spring on Z axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "use_spring_ang_x", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_X); + RNA_def_property_ui_text(prop, "X Angle Spring", "Enable spring on X rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "use_spring_ang_y", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_Y); + RNA_def_property_ui_text(prop, "Y Angle Spring", "Enable spring on Y rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "use_spring_ang_z", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_SPRING_ANG_Z); + RNA_def_property_ui_text(prop, "Z Angle Spring", "Enable spring on Z rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "use_motor_lin", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", RBC_FLAG_USE_MOTOR_LIN); RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyCon_use_motor_lin_set"); @@ -1178,6 +1269,33 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Z Axis Stiffness", "Stiffness on the Z axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "spring_stiffness_ang_x", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_x"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_float_default(prop, 10.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_x_set", NULL); + RNA_def_property_ui_text(prop, "X Angle Stiffness", "Stiffness on the X rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "spring_stiffness_ang_y", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_y"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_float_default(prop, 10.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_y_set", NULL); + RNA_def_property_ui_text(prop, "Y Angle Stiffness", "Stiffness on the Y rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "spring_stiffness_ang_z", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "spring_stiffness_ang_z"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 100.0f, 1, 3); + RNA_def_property_float_default(prop, 10.0f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_stiffness_ang_z_set", NULL); + RNA_def_property_ui_text(prop, "Z Angle Stiffness", "Stiffness on the Z rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "spring_damping_x", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "spring_damping_x"); RNA_def_property_range(prop, 0.0f, 1.0f); @@ -1202,6 +1320,30 @@ static void rna_def_rigidbody_constraint(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Damping Z", "Damping on the Z axis"); RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "spring_damping_ang_x", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_x"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_x_set", NULL); + RNA_def_property_ui_text(prop, "Damping X Angle", "Damping on the X rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "spring_damping_ang_y", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_y"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_y_set", NULL); + RNA_def_property_ui_text(prop, "Damping Y Angle", "Damping on the Y rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + + prop = RNA_def_property(srna, "spring_damping_ang_z", PROP_FLOAT, PROP_FACTOR); + RNA_def_property_float_sdna(prop, NULL, "spring_damping_ang_z"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 0.5f); + RNA_def_property_float_funcs(prop, NULL, "rna_RigidBodyCon_spring_damping_ang_z_set", NULL); + RNA_def_property_ui_text(prop, "Damping Z Angle", "Damping on the Z rotational axis"); + RNA_def_property_update(prop, NC_OBJECT, "rna_RigidBodyOb_reset"); + prop = RNA_def_property(srna, "motor_lin_target_velocity", PROP_FLOAT, PROP_UNIT_VELOCITY); RNA_def_property_float_sdna(prop, NULL, "motor_lin_target_velocity"); RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); From f64548daa6d6d863356367bb72017c511bf04953 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 11:36:35 +0100 Subject: [PATCH 113/590] Depsgraph: Remove prototype of unused and non-implemented method --- source/blender/depsgraph/intern/depsgraph.h | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index 08b264f8497..ca380d8db0e 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -100,22 +100,6 @@ struct Depsgraph { Depsgraph(); ~Depsgraph(); - /** - * Find node which matches the specified description. - * - * \param id: ID block that is associated with this - * \param subdata: identifier used for sub-ID data (e.g. bone) - * \param type: type of node we're dealing with - * \param name: custom identifier assigned to node - * - * \return A node matching the required characteristics if it exists - * or NULL if no such node exists in the graph. - */ - DepsNode *find_node(const ID *id, - eDepsNode_Type type, - const string &subdata, - const string &name); - /** * Convenience wrapper to find node given just pointer + property. * From a7f53bc5123fcc2fef8f31424aeb7fdd9aaccaa9 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 11:50:18 +0100 Subject: [PATCH 114/590] Depsgraph: Switch away form string to const char* for node names There is no real reason to have nodes storing heap-allocated name and description. Doing this increases amount of allocations during dependency graph building, which usually means somewhat slowness. We're temporarily loosing some eyecandy in the graphviz visualizer, but those we can bring back as a part of graphiz dump (which happens much less often than depsgraph build). This will happen in multiple commits for the ease of bisect in the future just in case this causes any regression. This commit contains ID creation API changes. --- source/blender/depsgraph/intern/builder/deg_builder_nodes.cc | 3 +-- source/blender/depsgraph/intern/depsgraph.cc | 2 +- source/blender/depsgraph/intern/depsgraph.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index d1469e850e6..83c9598e389 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -131,8 +131,7 @@ RootDepsNode *DepsgraphNodeBuilder::add_root_node() IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id) { - const char *idtype_name = BKE_idcode_to_name(GS(id->name)); - return m_graph->add_id_node(id, string(id->name + 2) + "[" + idtype_name + "]"); + return m_graph->add_id_node(id, id->name); } TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id) diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 2b7c63767ab..fd4956bc5a5 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -328,7 +328,7 @@ IDDepsNode *Depsgraph::find_id_node(const ID *id) const return reinterpret_cast(BLI_ghash_lookup(id_hash, id)); } -IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name) +IDDepsNode *Depsgraph::add_id_node(ID *id, const char *name) { IDDepsNode *id_node = find_id_node(id); if (!id_node) { diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h index ca380d8db0e..e668facd645 100644 --- a/source/blender/depsgraph/intern/depsgraph.h +++ b/source/blender/depsgraph/intern/depsgraph.h @@ -120,7 +120,7 @@ struct Depsgraph { void clear_subgraph_nodes(); IDDepsNode *find_id_node(const ID *id) const; - IDDepsNode *add_id_node(ID *id, const string &name = ""); + IDDepsNode *add_id_node(ID *id, const char *name = ""); void remove_id_node(const ID *id); void clear_id_nodes(); From bbd4b96fe9a1a766bb0a35a077e96f0b4e2fc5ed Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 12:01:45 +0100 Subject: [PATCH 115/590] Depsgraph: Use const char instead of string in part of drivers construction --- source/blender/depsgraph/intern/depsgraph.cc | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index fd4956bc5a5..e2fbf4374ad 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -32,8 +32,6 @@ #include "intern/depsgraph.h" /* own include */ -#include - #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -116,7 +114,7 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr, const PropertyRNA *prop, ID **id, eDepsNode_Type *type, - string *subdata) + const char **subdata) { if (!ptr->type) return false; @@ -232,7 +230,7 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr, { ID *id; eDepsNode_Type type; - string name; + const char *name; /* Get querying conditions. */ if (pointer_to_id_node_criteria(ptr, prop, &id)) { @@ -240,8 +238,9 @@ DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr, } else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) { IDDepsNode *id_node = find_id_node(id); - if (id_node) + if (id_node != NULL) { return id_node->find_component(type, name); + } } return NULL; From 4ef45ba7759880e88d93bfec44b57bbf8b9f1c1e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 12:08:47 +0100 Subject: [PATCH 116/590] Depsgraph: Remove some includes which seems unused --- source/blender/depsgraph/intern/builder/deg_builder_nodes.cc | 1 - .../blender/depsgraph/intern/builder/deg_builder_relations.cc | 1 - source/blender/depsgraph/intern/depsgraph_tag.cc | 1 - source/blender/depsgraph/intern/eval/deg_eval_debug.cc | 2 -- source/blender/depsgraph/intern/nodes/deg_node.cc | 1 - source/blender/depsgraph/intern/nodes/deg_node_component.cc | 1 - 6 files changed, 7 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 83c9598e389..8139cc3e1ae 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -34,7 +34,6 @@ #include #include -#include #include "MEM_guardedalloc.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index e506b8712e8..ba95576e790 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -34,7 +34,6 @@ #include #include -#include #include "MEM_guardedalloc.h" diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 4f27dab258d..00907e417ff 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -31,7 +31,6 @@ */ #include -#include #include extern "C" { diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc index 67d64aae8bf..cfadf74da4d 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc @@ -30,8 +30,6 @@ * Implementation of tools for debugging the depsgraph */ -#include - #include "intern/eval/deg_eval_debug.h" extern "C" { diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index eb408f293de..29221357ce8 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -31,7 +31,6 @@ #include "intern/nodes/deg_node.h" #include -#include #include "BLI_utildefines.h" #include "BLI_ghash.h" diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index 01f33b6368b..efc013b6eeb 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -31,7 +31,6 @@ #include "intern/nodes/deg_node_component.h" #include -#include extern "C" { #include "BLI_utildefines.h" From f8d9a56aa113ff67fd0b5ba4436bef71f048a802 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 12:14:47 +0100 Subject: [PATCH 117/590] Depsgraph: Use const char for component API --- .../intern/builder/deg_builder_nodes.cc | 17 +++++++++++------ .../intern/builder/deg_builder_nodes.h | 8 ++++---- .../intern/builder/deg_builder_relations.cc | 1 - 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 8139cc3e1ae..ca5ee838917 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -177,7 +177,7 @@ TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id) ComponentDepsNode *DepsgraphNodeBuilder::add_component_node( ID *id, eDepsNode_Type comp_type, - const string &comp_name) + const char *comp_name) { IDDepsNode *id_node = add_id_node(id); ComponentDepsNode *comp_node = id_node->add_component(comp_type, comp_name); @@ -198,7 +198,8 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( m_graph->operations.push_back(op_node); } else { - fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n", + fprintf(stderr, + "add_operation: Operation already exists - %s has %s at %p\n", comp_node->identifier().c_str(), op_node->identifier().c_str(), op_node); @@ -210,7 +211,7 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( ID *id, eDepsNode_Type comp_type, - const string &comp_name, + const char *comp_name, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, @@ -233,17 +234,21 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( bool DepsgraphNodeBuilder::has_operation_node(ID *id, eDepsNode_Type comp_type, - const string &comp_name, + const char *comp_name, eDepsOperation_Code opcode, const string &description) { - return find_operation_node(id, comp_type, comp_name, opcode, description) != NULL; + return find_operation_node(id, + comp_type, + comp_name, + opcode, + description) != NULL; } OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( ID *id, eDepsNode_Type comp_type, - const string &comp_name, + const char *comp_name, eDepsOperation_Code opcode, const string &description) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 09d264c4b59..20fe6c5db92 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -76,7 +76,7 @@ struct DepsgraphNodeBuilder { ComponentDepsNode *add_component_node(ID *id, eDepsNode_Type comp_type, - const string& comp_name = ""); + const char *comp_name = ""); OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, eDepsOperation_Type optype, @@ -85,7 +85,7 @@ struct DepsgraphNodeBuilder { const string& description = ""); OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, - const string& comp_name, + const char *comp_name, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, @@ -99,13 +99,13 @@ struct DepsgraphNodeBuilder { bool has_operation_node(ID *id, eDepsNode_Type comp_type, - const string& comp_name, + const char *comp_name, eDepsOperation_Code opcode, const string& description = ""); OperationDepsNode *find_operation_node(ID *id, eDepsNode_Type comp_type, - const string &comp_name, + const char *comp_name, eDepsOperation_Code opcode, const string &description = ""); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index ba95576e790..86e222075fe 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -39,7 +39,6 @@ extern "C" { #include "BLI_blenlib.h" -#include "BLI_string.h" #include "BLI_utildefines.h" #include "DNA_action_types.h" From 933193034534cd805f2b5ddf696d7c9e90badda3 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 14:18:19 +0100 Subject: [PATCH 118/590] Depsgraph: Remove unused function A residue from times where we thought to do partial graph updates, which we are not committing any time soon. --- .../depsgraph/intern/nodes/deg_node_component.cc | 10 ---------- .../depsgraph/intern/nodes/deg_node_component.h | 1 - 2 files changed, 11 deletions(-) diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index efc013b6eeb..1f32756da61 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -196,16 +196,6 @@ OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, return op_node; } -void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name) -{ - /* unregister */ - OperationIDKey key(opcode, name); - BLI_ghash_remove(operations_map, - &key, - comp_node_hash_key_free, - comp_node_hash_key_free); -} - void ComponentDepsNode::clear_operations() { if (operations_map != NULL) { diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h index 7dec8eaaa90..6c13c33dc16 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h @@ -116,7 +116,6 @@ struct ComponentDepsNode : public DepsNode { eDepsOperation_Code opcode, const string &name); - void remove_operation(eDepsOperation_Code opcode, const string &name); void clear_operations(); void tag_update(Depsgraph *graph); From d872aeaf51166554c747527e7e6d9a3ff099ce89 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 14:22:41 +0100 Subject: [PATCH 119/590] Depsgraph: Cleanup, operation has name, not description Hopefully should make things more clear here. --- .../intern/builder/deg_builder_nodes.cc | 26 +++++++++---------- .../intern/builder/deg_builder_nodes.h | 12 ++++----- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index ca5ee838917..ea319cbe8fd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -190,11 +190,11 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &description) + const string &name) { - OperationDepsNode *op_node = comp_node->has_operation(opcode, description); + OperationDepsNode *op_node = comp_node->has_operation(opcode, name); if (op_node == NULL) { - op_node = comp_node->add_operation(optype, op, opcode, description); + op_node = comp_node->add_operation(optype, op, opcode, name); m_graph->operations.push_back(op_node); } else { @@ -215,10 +215,10 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &description) + const string &name) { ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name); - return add_operation_node(comp_node, optype, op, opcode, description); + return add_operation_node(comp_node, optype, op, opcode, name); } OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( @@ -227,22 +227,22 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& description) + const string& name) { - return add_operation_node(id, comp_type, "", optype, op, opcode, description); + return add_operation_node(id, comp_type, "", optype, op, opcode, name); } bool DepsgraphNodeBuilder::has_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string &description) + const string &name) { return find_operation_node(id, comp_type, comp_name, opcode, - description) != NULL; + name) != NULL; } OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( @@ -250,19 +250,19 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string &description) + const string &name) { ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name); - return comp_node->has_operation(opcode, description); + return comp_node->has_operation(opcode, name); } OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( ID *id, eDepsNode_Type comp_type, eDepsOperation_Code opcode, - const string& description) + const string& name) { - return find_operation_node(id, comp_type, "", opcode, description); + return find_operation_node(id, comp_type, "", opcode, name); } /* **** Build functions for entity nodes **** */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 20fe6c5db92..539543cfde3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -82,37 +82,37 @@ struct DepsgraphNodeBuilder { eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& description = ""); + const string& name = ""); OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& description = ""); + const string& name = ""); OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& description = ""); + const string& name = ""); bool has_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string& description = ""); + const string& name = ""); OperationDepsNode *find_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string &description = ""); + const string &name = ""); OperationDepsNode *find_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Code opcode, - const string &description = ""); + const string &name = ""); void build_scene(Main *bmain, Scene *scene); SubgraphDepsNode *build_subgraph(Group *group); From c9eca0c6c9e710b706711872526634bdd95a3ffa Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 14:31:27 +0100 Subject: [PATCH 120/590] Depsgraph: Add extra name tag for operation nodes The idea here is to address issue that name on it's own is not always unique: for example, when adding driver operations the name used for nodes is the RNA path (and multiple drivers can write to different array indices of the path). Basically, now it's possible to pass extra integer value to distinguish operations in such cases. So now we've already switched from sprintf() to construct unique operation name to pass RNA path and array index. There should be no functional changes yet, but this work is required for further work about replacing string with const char*. --- .../intern/builder/deg_builder_nodes.cc | 55 ++++++++---- .../intern/builder/deg_builder_nodes.h | 18 ++-- .../intern/builder/deg_builder_relations.cc | 24 ++++-- .../intern/builder/deg_builder_relations.h | 85 ++++++++++++++++--- .../intern/nodes/deg_node_component.cc | 21 +++-- .../intern/nodes/deg_node_component.h | 35 +++++--- 6 files changed, 177 insertions(+), 61 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index ea319cbe8fd..63dd915b7f0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -190,11 +190,14 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &name) + const string &name, + int name_tag) { - OperationDepsNode *op_node = comp_node->has_operation(opcode, name); + OperationDepsNode *op_node = comp_node->has_operation(opcode, + name, + name_tag); if (op_node == NULL) { - op_node = comp_node->add_operation(optype, op, opcode, name); + op_node = comp_node->add_operation(optype, op, opcode, name, name_tag); m_graph->operations.push_back(op_node); } else { @@ -215,10 +218,11 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &name) + const string &name, + int name_tag) { ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name); - return add_operation_node(comp_node, optype, op, opcode, name); + return add_operation_node(comp_node, optype, op, opcode, name, name_tag); } OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( @@ -227,22 +231,32 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& name) + const string& name, + int name_tag) { - return add_operation_node(id, comp_type, "", optype, op, opcode, name); + return add_operation_node(id, + comp_type, + "", + optype, + op, + opcode, + name, + name_tag); } bool DepsgraphNodeBuilder::has_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string &name) + const string &name, + int name_tag) { return find_operation_node(id, comp_type, comp_name, opcode, - name) != NULL; + name, + name_tag) != NULL; } OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( @@ -250,19 +264,21 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string &name) + const string &name, + int name_tag) { ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name); - return comp_node->has_operation(opcode, name); + return comp_node->has_operation(opcode, name, name_tag); } OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( ID *id, eDepsNode_Type comp_type, eDepsOperation_Code opcode, - const string& name) + const string& name, + int name_tag) { - return find_operation_node(id, comp_type, "", opcode, name); + return find_operation_node(id, comp_type, "", opcode, name, name_tag); } /* **** Build functions for entity nodes **** */ @@ -620,12 +636,17 @@ OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu) OperationDepsNode *driver_op = find_operation_node(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, - deg_fcurve_id_name(fcu)); + fcu->rna_path, + fcu->array_index); if (driver_op == NULL) { - driver_op = add_operation_node(id, DEPSNODE_TYPE_PARAMETERS, - DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_driver, _1, id, fcu), - DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu)); + driver_op = add_operation_node(id, + DEPSNODE_TYPE_PARAMETERS, + DEPSOP_TYPE_EXEC, + function_bind(BKE_animsys_eval_driver, _1, id, fcu), + DEG_OPCODE_DRIVER, + fcu->rna_path, + fcu->array_index); } /* tag "scripted expression" drivers as needing Python (due to GIL issues, etc.) */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 539543cfde3..e93dedc36d5 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -82,37 +82,43 @@ struct DepsgraphNodeBuilder { eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& name = ""); + const string& name = "", + int name_tag = -1); OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& name = ""); + const string& name = "", + int name_tag = -1); OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& name = ""); + const string& name = "", + int name_tag = -1); bool has_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string& name = ""); + const string& name = "", + int name_tag = -1); OperationDepsNode *find_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string &name = ""); + const string &name = "", + int name_tag = -1); OperationDepsNode *find_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Code opcode, - const string &name = ""); + const string &name = "", + int name_tag = -1); void build_scene(Main *bmain, Scene *scene); SubgraphDepsNode *build_subgraph(Group *group); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 86e222075fe..61275ff02f2 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -209,7 +209,9 @@ OperationDepsNode *DepsgraphRelationBuilder::find_node( return NULL; } - OperationDepsNode *op_node = comp_node->find_operation(key.opcode, key.name); + OperationDepsNode *op_node = comp_node->find_operation(key.opcode, + key.name, + key.name_tag); if (!op_node) { fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n", DEG_OPNAMES[key.opcode], key.name.c_str()); @@ -234,7 +236,7 @@ OperationDepsNode *DepsgraphRelationBuilder::has_node( if (!comp_node) { return NULL; } - return comp_node->has_operation(key.opcode, key.name); + return comp_node->has_operation(key.opcode, key.name, key.name_tag); } void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc, @@ -835,7 +837,11 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) /* drivers */ for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) { - OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu)); + OperationKey driver_key(id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + fcu->rna_path, + fcu->array_index); /* create the driver's relations to targets */ build_driver(id, fcu); @@ -877,11 +883,13 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) OperationKey prev_driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, - deg_fcurve_id_name(fcu_prev)); + fcu_prev->rna_path, + fcu_prev->array_index); OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, - deg_fcurve_id_name(fcu)); + fcu->rna_path, + fcu->array_index); add_relation(prev_driver_key, driver_key, DEPSREL_TYPE_OPERATION, @@ -900,7 +908,11 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) { ChannelDriver *driver = fcu->driver; - OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu)); + OperationKey driver_key(id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_DRIVER, + fcu->rna_path, + fcu->array_index); bPoseChannel *pchan = NULL; /* create dependency between driver and data affected by it */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index d60499e9cbe..ce9f36ca092 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -125,29 +125,85 @@ struct ComponentKey struct OperationKey { - OperationKey() : - id(NULL), component_type(DEPSNODE_TYPE_UNDEFINED), component_name(""), opcode(DEG_OPCODE_OPERATION), name("") + OperationKey() + : id(NULL), + component_type(DEPSNODE_TYPE_UNDEFINED), + component_name(""), + opcode(DEG_OPCODE_OPERATION), + name(""), + name_tag(-1) {} - OperationKey(ID *id, eDepsNode_Type component_type, const string &name) : - id(id), component_type(component_type), component_name(""), opcode(DEG_OPCODE_OPERATION), name(name) + OperationKey(ID *id, + eDepsNode_Type component_type, + const string &name, + int name_tag = -1) + : id(id), + component_type(component_type), + component_name(""), + opcode(DEG_OPCODE_OPERATION), + name(name), + name_tag(name_tag) {} - OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, const string &name) : - id(id), component_type(component_type), component_name(component_name), opcode(DEG_OPCODE_OPERATION), name(name) + OperationKey(ID *id, + eDepsNode_Type component_type, + const string &component_name, + const string &name, + int name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(DEG_OPCODE_OPERATION), + name(name), + name_tag(name_tag) {} - OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode) : - id(id), component_type(component_type), component_name(""), opcode(opcode), name("") + OperationKey(ID *id, + eDepsNode_Type component_type, + eDepsOperation_Code opcode) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(""), + name_tag(-1) {} - OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode) : - id(id), component_type(component_type), component_name(component_name), opcode(opcode), name("") + OperationKey(ID *id, + eDepsNode_Type component_type, + const string &component_name, + eDepsOperation_Code opcode) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(""), + name_tag(-1) {} - OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode, const string &name) : - id(id), component_type(component_type), component_name(""), opcode(opcode), name(name) + OperationKey(ID *id, + eDepsNode_Type component_type, + eDepsOperation_Code opcode, + const string &name, + int name_tag = -1) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(name), + name_tag(name_tag) {} - OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode, const string &name) : - id(id), component_type(component_type), component_name(component_name), opcode(opcode), name(name) + OperationKey(ID *id, + eDepsNode_Type component_type, + const string &component_name, + eDepsOperation_Code opcode, + const string &name, + int name_tag = -1) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(name), + name_tag(name_tag) {} string identifier() const @@ -164,6 +220,7 @@ struct OperationKey string component_name; eDepsOperation_Code opcode; string name; + int name_tag; }; struct RNAPathKey diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index 1f32756da61..4c88b38b6f0 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -138,9 +138,11 @@ OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const } } -OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, const string &name) const +OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, + const string &name, + int name_tag) const { - OperationIDKey key(opcode, name); + OperationIDKey key(opcode, name, name_tag); return find_operation(key); } @@ -150,21 +152,26 @@ OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const } OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode, - const string &name) const + const string &name, + int name_tag) const { - OperationIDKey key(opcode, name); + OperationIDKey key(opcode, name, name_tag); return has_operation(key); } -OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name) +OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, + DepsEvalOperationCb op, + eDepsOperation_Code opcode, + const string &name, + int name_tag) { - OperationDepsNode *op_node = has_operation(opcode, name); + OperationDepsNode *op_node = has_operation(opcode, name, name_tag); if (!op_node) { DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_OPERATION); op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name); /* register opnode in this component's operation set */ - OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name); + OperationIDKey *key = OBJECT_GUARDED_NEW(OperationIDKey, opcode, name, name_tag); BLI_ghash_insert(operations_map, key, op_node); /* set as entry/exit node of component (if appropriate) */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h index 6c13c33dc16..e0d425a2c14 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h @@ -54,16 +54,24 @@ struct ComponentDepsNode : public DepsNode { { eDepsOperation_Code opcode; string name; + int name_tag; - - OperationIDKey() : - opcode(DEG_OPCODE_OPERATION), name("") + OperationIDKey() + : opcode(DEG_OPCODE_OPERATION), + name(""), + name_tag(-1) {} - OperationIDKey(eDepsOperation_Code opcode) : - opcode(opcode), name("") + OperationIDKey(eDepsOperation_Code opcode) + : opcode(opcode), + name(""), + name_tag(-1) {} - OperationIDKey(eDepsOperation_Code opcode, const string &name) : - opcode(opcode), name(name) + OperationIDKey(eDepsOperation_Code opcode, + const string &name, + int name_tag) + : opcode(opcode), + name(name), + name_tag(name_tag) {} string identifier() const @@ -76,7 +84,9 @@ struct ComponentDepsNode : public DepsNode { bool operator==(const OperationIDKey &other) const { - return (opcode == other.opcode) && (name == other.name); + return (opcode == other.opcode) && + (name == other.name) && + (name_tag == other.name_tag); } }; @@ -91,12 +101,14 @@ struct ComponentDepsNode : public DepsNode { /* Find an existing operation, will throw an assert() if it does not exist. */ OperationDepsNode *find_operation(OperationIDKey key) const; OperationDepsNode *find_operation(eDepsOperation_Code opcode, - const string &name) const; + const string &name, + int name_tag) const; /* Check operation exists and return it. */ OperationDepsNode *has_operation(OperationIDKey key) const; OperationDepsNode *has_operation(eDepsOperation_Code opcode, - const string &name) const; + const string &name, + int name_tag) const; /** * Create a new node for representing an operation and add this to graph @@ -114,7 +126,8 @@ struct ComponentDepsNode : public DepsNode { OperationDepsNode *add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &name); + const string &name, + int name_tag); void clear_operations(); From 287197c4e33ca27a02188402543af0ba0286a5f5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 14:45:47 +0100 Subject: [PATCH 121/590] Depsgraph: Fully switch from string to const char* This brings up to 10-20% depsgraph build time improvement in the layout files from the studio repository. --- .../intern/builder/deg_builder_nodes.cc | 12 ++++---- .../intern/builder/deg_builder_nodes.h | 12 ++++---- .../intern/builder/deg_builder_relations.cc | 2 +- .../intern/builder/deg_builder_relations.h | 30 +++++++++---------- .../intern/debug/deg_debug_graphviz.cc | 2 +- .../depsgraph/intern/depsgraph_intern.h | 12 ++++---- .../depsgraph/intern/eval/deg_eval_debug.cc | 15 +++++----- .../depsgraph/intern/eval/deg_eval_debug.h | 4 +-- .../depsgraph/intern/nodes/deg_node.cc | 16 +++++----- .../blender/depsgraph/intern/nodes/deg_node.h | 25 +++++++++------- .../intern/nodes/deg_node_component.cc | 16 +++++----- .../intern/nodes/deg_node_component.h | 16 +++++----- .../intern/nodes/deg_node_operation.cc | 2 +- 13 files changed, 85 insertions(+), 79 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 63dd915b7f0..445b7201aa9 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -190,7 +190,7 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag) { OperationDepsNode *op_node = comp_node->has_operation(opcode, @@ -218,7 +218,7 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag) { ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name); @@ -231,7 +231,7 @@ OperationDepsNode *DepsgraphNodeBuilder::add_operation_node( eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& name, + const char *name, int name_tag) { return add_operation_node(id, @@ -248,7 +248,7 @@ bool DepsgraphNodeBuilder::has_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag) { return find_operation_node(id, @@ -264,7 +264,7 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag) { ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name); @@ -275,7 +275,7 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( ID *id, eDepsNode_Type comp_type, eDepsOperation_Code opcode, - const string& name, + const char *name, int name_tag) { return find_operation_node(id, comp_type, "", opcode, name, name_tag); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index e93dedc36d5..72dc73357bf 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -82,7 +82,7 @@ struct DepsgraphNodeBuilder { eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& name = "", + const char *name = "", int name_tag = -1); OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, @@ -90,34 +90,34 @@ struct DepsgraphNodeBuilder { eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& name = "", + const char *name = "", int name_tag = -1); OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string& name = "", + const char *name = "", int name_tag = -1); bool has_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string& name = "", + const char *name = "", int name_tag = -1); OperationDepsNode *find_operation_node(ID *id, eDepsNode_Type comp_type, const char *comp_name, eDepsOperation_Code opcode, - const string &name = "", + const char *name = "", int name_tag = -1); OperationDepsNode *find_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Code opcode, - const string &name = "", + const char *name = "", int name_tag = -1); void build_scene(Main *bmain, Scene *scene); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 61275ff02f2..797fcd80081 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -214,7 +214,7 @@ OperationDepsNode *DepsgraphRelationBuilder::find_node( key.name_tag); if (!op_node) { fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n", - DEG_OPNAMES[key.opcode], key.name.c_str()); + DEG_OPNAMES[key.opcode], key.name); } return op_node; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index ce9f36ca092..056d4fdfe3d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -104,7 +104,7 @@ struct ComponentKey ComponentKey() : id(NULL), type(DEPSNODE_TYPE_UNDEFINED), name("") {} - ComponentKey(ID *id, eDepsNode_Type type, const string &name = "") : + ComponentKey(ID *id, eDepsNode_Type type, const char *name = "") : id(id), type(type), name(name) {} @@ -120,7 +120,7 @@ struct ComponentKey ID *id; eDepsNode_Type type; - string name; + const char *name; }; struct OperationKey @@ -136,7 +136,7 @@ struct OperationKey OperationKey(ID *id, eDepsNode_Type component_type, - const string &name, + const char *name, int name_tag = -1) : id(id), component_type(component_type), @@ -147,8 +147,8 @@ struct OperationKey {} OperationKey(ID *id, eDepsNode_Type component_type, - const string &component_name, - const string &name, + const char *component_name, + const char *name, int name_tag) : id(id), component_type(component_type), @@ -170,7 +170,7 @@ struct OperationKey {} OperationKey(ID *id, eDepsNode_Type component_type, - const string &component_name, + const char *component_name, eDepsOperation_Code opcode) : id(id), component_type(component_type), @@ -183,7 +183,7 @@ struct OperationKey OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag = -1) : id(id), component_type(component_type), @@ -194,9 +194,9 @@ struct OperationKey {} OperationKey(ID *id, eDepsNode_Type component_type, - const string &component_name, + const char *component_name, eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag = -1) : id(id), component_type(component_type), @@ -217,9 +217,9 @@ struct OperationKey ID *id; eDepsNode_Type component_type; - string component_name; + const char *component_name; eDepsOperation_Code opcode; - string name; + const char *name; int name_tag; }; @@ -327,7 +327,7 @@ protected: template DepsNodeHandle create_node_handle(const KeyType& key, - const string& default_name = ""); + const char *default_name = ""); bool needs_animdata_node(ID *id); @@ -337,7 +337,7 @@ private: struct DepsNodeHandle { - DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const string &default_name = "") : + DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const char *default_name = "") : builder(builder), node(node), default_name(default_name) @@ -347,7 +347,7 @@ struct DepsNodeHandle DepsgraphRelationBuilder *builder; OperationDepsNode *node; - const string &default_name; + const char *default_name; }; /* Utilities for Builders ----------------------------------------------------- */ @@ -441,7 +441,7 @@ void DepsgraphRelationBuilder::add_node_handle_relation( template DepsNodeHandle DepsgraphRelationBuilder::create_node_handle( const KeyType &key, - const string &default_name) + const char *default_name) { return DepsNodeHandle(this, find_node(key), default_name); } diff --git a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc index 70cd5f11a47..0d56ce71c7d 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_graphviz.cc @@ -321,7 +321,7 @@ static void deg_debug_graphviz_node_single(const DebugContext &ctx, static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx, const DepsNode *node) { - string name = node->identifier().c_str(); + string name = node->identifier(); if (node->type == DEPSNODE_TYPE_ID_REF) { IDDepsNode *id_node = (IDDepsNode *)node; char buf[256]; diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h index e5d3d1f5861..2d8e7dc841c 100644 --- a/source/blender/depsgraph/intern/depsgraph_intern.h +++ b/source/blender/depsgraph/intern/depsgraph_intern.h @@ -63,8 +63,8 @@ struct DepsNodeFactory { virtual const char *tname() const = 0; virtual DepsNode *create_node(const ID *id, - const string &subdata, - const string &name) const = 0; + const char *subdata, + const char *name) const = 0; }; template @@ -73,7 +73,7 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory { eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; } const char *tname() const { return NodeType::typeinfo.tname; } - DepsNode *create_node(const ID *id, const string &subdata, const string &name) const + DepsNode *create_node(const ID *id, const char *subdata, const char *name) const { DepsNode *node = OBJECT_GUARDED_NEW(NodeType); @@ -81,12 +81,14 @@ struct DepsNodeFactoryImpl : public DepsNodeFactory { node->type = type(); node->tclass = tclass(); - if (!name.empty()) + if (name[0] != '\0') { /* set name if provided ... */ node->name = name; - else + } + else { /* ... otherwise use default type name */ node->name = tname(); + } node->init(id, subdata); diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc index cfadf74da4d..575b9490478 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc @@ -51,10 +51,10 @@ namespace DEG { DepsgraphStats *DepsgraphDebug::stats = NULL; -static string get_component_name(eDepsNode_Type type, const string &name = "") +static string get_component_name(eDepsNode_Type type, const char *name = "") { DepsNodeFactory *factory = deg_get_node_factory(type); - if (name.empty()) { + if (name[0] != '\0') { return string(factory->tname()); } else { @@ -114,7 +114,7 @@ void DepsgraphDebug::task_started(Depsgraph *graph, */ DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, - comp->name), + comp->name).c_str(), true); times_clear(comp_stats->times); } @@ -144,7 +144,7 @@ void DepsgraphDebug::task_completed(Depsgraph *graph, DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, - comp->name), + comp->name).c_str(), true); times_add(comp_stats->times, time); } @@ -224,7 +224,7 @@ DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create) DepsgraphStatsComponent *DepsgraphDebug::get_component_stats( DepsgraphStatsID *id_stats, - const string &name, + const char *name, bool create) { DepsgraphStatsComponent *comp_stats; @@ -232,13 +232,14 @@ DepsgraphStatsComponent *DepsgraphDebug::get_component_stats( comp_stats != NULL; comp_stats = comp_stats->next) { - if (STREQ(comp_stats->name, name.c_str())) + if (STREQ(comp_stats->name, name)) { break; + } } if (!comp_stats && create) { comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent), "Depsgraph Component Stats"); - BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name)); + BLI_strncpy(comp_stats->name, name, sizeof(comp_stats->name)); BLI_addtail(&id_stats->components, comp_stats); } return comp_stats; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.h b/source/blender/depsgraph/intern/eval/deg_eval_debug.h index 9109019eb2d..0bbe88cc9ca 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_debug.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.h @@ -66,10 +66,10 @@ struct DepsgraphDebug { static DepsgraphStatsID *get_id_stats(ID *id, bool create); static DepsgraphStatsComponent *get_component_stats(DepsgraphStatsID *id_stats, - const string &name, + const char *name, bool create); static DepsgraphStatsComponent *get_component_stats(ID *id, - const string &name, + const char *name, bool create) { return get_component_stats(get_id_stats(id, create), name, create); diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index 29221357ce8..16f1243b433 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -71,7 +71,7 @@ DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname) DepsNode::DepsNode() { - name[0] = '\0'; + name = ""; } DepsNode::~DepsNode() @@ -121,7 +121,7 @@ RootDepsNode::~RootDepsNode() OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode); } -TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name) +TimeSourceDepsNode *RootDepsNode::add_time_source(const char *name) { if (!time_source) { DepsNodeFactory *factory = deg_get_node_factory(DEPSNODE_TYPE_TIMESOURCE); @@ -146,7 +146,7 @@ static unsigned int id_deps_node_hash_key(const void *key_v) const IDDepsNode::ComponentIDKey *key = reinterpret_cast(key_v); return hash_combine(BLI_ghashutil_uinthash(key->type), - BLI_ghashutil_strhash_p(key->name.c_str())); + BLI_ghashutil_strhash_p(key->name)); } static bool id_deps_node_hash_key_cmp(const void *a, const void *b) @@ -172,7 +172,7 @@ static void id_deps_node_hash_value_free(void *value_v) } /* Initialize 'id' node - from pointer data given. */ -void IDDepsNode::init(const ID *id, const string &UNUSED(subdata)) +void IDDepsNode::init(const ID *id, const char *UNUSED(subdata)) { /* Store ID-pointer. */ BLI_assert(id != NULL); @@ -203,14 +203,14 @@ IDDepsNode::~IDDepsNode() } ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type, - const string &name) const + const char *name) const { ComponentIDKey key(type, name); return reinterpret_cast(BLI_ghash_lookup(components, &key)); } ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type, - const string &name) + const char *name) { ComponentDepsNode *comp_node = find_component(type, name); if (!comp_node) { @@ -225,7 +225,7 @@ ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type, return comp_node; } -void IDDepsNode::remove_component(eDepsNode_Type type, const string &name) +void IDDepsNode::remove_component(eDepsNode_Type type, const char *name) { ComponentDepsNode *comp_node = find_component(type, name); if (comp_node) { @@ -280,7 +280,7 @@ static DepsNodeFactoryImpl DNTI_ID_REF; /* Subgraph Node ========================================== */ /* Initialize 'subgraph' node - from pointer data given. */ -void SubgraphDepsNode::init(const ID *id, const string &UNUSED(subdata)) +void SubgraphDepsNode::init(const ID *id, const char *UNUSED(subdata)) { /* Store ID-ref if provided. */ this->root_id = (ID *)id; diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h index b2262c4bd12..67b2e13d5f6 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.h +++ b/source/blender/depsgraph/intern/nodes/deg_node.h @@ -32,6 +32,8 @@ #include "intern/depsgraph_types.h" +#include "BLI_utildefines.h" + struct ID; struct GHash; struct Scene; @@ -57,7 +59,7 @@ struct DepsNode { }; /* Identifier - mainly for debugging purposes. */ - string name; + const char *name; /* Structural type of node. */ eDepsNode_Type type; @@ -90,7 +92,7 @@ struct DepsNode { string full_identifier() const; virtual void init(const ID * /*id*/, - const string &/*subdata*/) {} + const char * /*subdata*/) {} virtual void tag_update(Depsgraph * /*graph*/) {} @@ -129,7 +131,7 @@ struct RootDepsNode : public DepsNode { RootDepsNode(); ~RootDepsNode(); - TimeSourceDepsNode *add_time_source(const string &name = ""); + TimeSourceDepsNode *add_time_source(const char *name = ""); /* scene that this corresponds to */ Scene *scene; @@ -143,26 +145,27 @@ struct RootDepsNode : public DepsNode { /* ID-Block Reference */ struct IDDepsNode : public DepsNode { struct ComponentIDKey { - ComponentIDKey(eDepsNode_Type type, const string &name = "") + ComponentIDKey(eDepsNode_Type type, const char *name = "") : type(type), name(name) {} bool operator== (const ComponentIDKey &other) const { - return type == other.type && name == other.name; + return type == other.type && + STREQ(name, other.name); } eDepsNode_Type type; - string name; + const char *name; }; - void init(const ID *id, const string &subdata); + void init(const ID *id, const char *subdata); ~IDDepsNode(); ComponentDepsNode *find_component(eDepsNode_Type type, - const string &name = "") const; + const char *name = "") const; ComponentDepsNode *add_component(eDepsNode_Type type, - const string &name = ""); - void remove_component(eDepsNode_Type type, const string &name = ""); + const char *name = ""); + void remove_component(eDepsNode_Type type, const char *name = ""); void clear_components(); void tag_update(Depsgraph *graph); @@ -189,7 +192,7 @@ struct IDDepsNode : public DepsNode { /* Subgraph Reference. */ struct SubgraphDepsNode : public DepsNode { - void init(const ID *id, const string &subdata); + void init(const ID *id, const char *subdata); ~SubgraphDepsNode(); /* Instanced graph. */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index 4c88b38b6f0..9e7357be2b2 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -57,7 +57,7 @@ static unsigned int comp_node_hash_key(const void *key_v) const ComponentDepsNode::OperationIDKey *key = reinterpret_cast(key_v); return hash_combine(BLI_ghashutil_uinthash(key->opcode), - BLI_ghashutil_strhash_p(key->name.c_str())); + BLI_ghashutil_strhash_p(key->name)); } static bool comp_node_hash_key_cmp(const void *a, const void *b) @@ -94,7 +94,7 @@ ComponentDepsNode::ComponentDepsNode() : /* Initialize 'component' node - from pointer data given */ void ComponentDepsNode::init(const ID * /*id*/, - const string & /*subdata*/) + const char * /*subdata*/) { /* hook up eval context? */ // XXX: maybe this needs a special API? @@ -113,7 +113,7 @@ ComponentDepsNode::~ComponentDepsNode() string ComponentDepsNode::identifier() const { - string &idname = this->owner->name; + string idname = this->owner->name; char typebuf[16]; sprintf(typebuf, "(%d)", type); @@ -139,7 +139,7 @@ OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const } OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag) const { OperationIDKey key(opcode, name, name_tag); @@ -152,7 +152,7 @@ OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const } OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag) const { OperationIDKey key(opcode, name, name_tag); @@ -162,7 +162,7 @@ OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode, OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag) { OperationDepsNode *op_node = has_operation(opcode, name, name_tag); @@ -333,7 +333,7 @@ static DepsNodeFactoryImpl DNTI_EVAL_POSE; /* Bone Component ========================================= */ /* Initialize 'bone component' node - from pointer data given */ -void BoneComponentDepsNode::init(const ID *id, const string &subdata) +void BoneComponentDepsNode::init(const ID *id, const char *subdata) { /* generic component-node... */ ComponentDepsNode::init(id, subdata); @@ -346,7 +346,7 @@ void BoneComponentDepsNode::init(const ID *id, const string &subdata) /* bone-specific node data */ Object *ob = (Object *)id; - this->pchan = BKE_pose_channel_find_name(ob->pose, subdata.c_str()); + this->pchan = BKE_pose_channel_find_name(ob->pose, subdata); } DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEPSNODE_TYPE_BONE, "Bone Component"); diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h index e0d425a2c14..ec2674a7b13 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h @@ -53,7 +53,7 @@ struct ComponentDepsNode : public DepsNode { struct OperationIDKey { eDepsOperation_Code opcode; - string name; + const char *name; int name_tag; OperationIDKey() @@ -67,7 +67,7 @@ struct ComponentDepsNode : public DepsNode { name_tag(-1) {} OperationIDKey(eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag) : opcode(opcode), name(name), @@ -85,7 +85,7 @@ struct ComponentDepsNode : public DepsNode { bool operator==(const OperationIDKey &other) const { return (opcode == other.opcode) && - (name == other.name) && + (STREQ(name, other.name)) && (name_tag == other.name_tag); } }; @@ -94,20 +94,20 @@ struct ComponentDepsNode : public DepsNode { ComponentDepsNode(); ~ComponentDepsNode(); - void init(const ID *id, const string &subdata); + void init(const ID *id, const char *subdata); string identifier() const; /* Find an existing operation, will throw an assert() if it does not exist. */ OperationDepsNode *find_operation(OperationIDKey key) const; OperationDepsNode *find_operation(eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag) const; /* Check operation exists and return it. */ OperationDepsNode *has_operation(OperationIDKey key) const; OperationDepsNode *has_operation(eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag) const; /** @@ -126,7 +126,7 @@ struct ComponentDepsNode : public DepsNode { OperationDepsNode *add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, - const string &name, + const char *name, int name_tag); void clear_operations(); @@ -206,7 +206,7 @@ struct PoseComponentDepsNode : public ComponentDepsNode { /* Bone Component */ struct BoneComponentDepsNode : public ComponentDepsNode { - void init(const ID *id, const string &subdata); + void init(const ID *id, const char *subdata); struct bPoseChannel *pchan; /* the bone that this component represents */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc index 5847af29ac2..9eed4dfe8d8 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc @@ -68,7 +68,7 @@ string OperationDepsNode::full_identifier() const { string owner_str = ""; if (owner->type == DEPSNODE_TYPE_BONE) { - owner_str = owner->owner->name + "." + owner->name; + owner_str = string(owner->owner->name) + "." + owner->name; } else { owner_str = owner->owner->name; From 109be7ed397f7ee537b4dbc346d4af95e5c1f7ab Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 16:03:12 +0100 Subject: [PATCH 122/590] Depsgraph: Move class implementation from header to implementation files This is more proper way to go: - Avoids re-compilation of all dependent files when implementation changes without changed API, - Linker should have much simpler time now de-duplicating and getting rid of redundant implementations. --- .../depsgraph/intern/nodes/deg_node.cc | 12 ++++++ .../blender/depsgraph/intern/nodes/deg_node.h | 10 +---- .../intern/nodes/deg_node_component.cc | 38 +++++++++++++++++++ .../intern/nodes/deg_node_component.h | 34 +++-------------- 4 files changed, 57 insertions(+), 37 deletions(-) diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index 16f1243b433..62062314b88 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -141,6 +141,18 @@ static DepsNodeFactoryImpl DNTI_TIMESOURCE; /* ID Node ================================================ */ +IDDepsNode::ComponentIDKey::ComponentIDKey(eDepsNode_Type type, + const char *name) + : type(type), name(name) +{ +} + +bool IDDepsNode::ComponentIDKey::operator== (const ComponentIDKey &other) const +{ + return type == other.type && + STREQ(name, other.name); +} + static unsigned int id_deps_node_hash_key(const void *key_v) { const IDDepsNode::ComponentIDKey *key = diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h index 67b2e13d5f6..810c6eeb420 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.h +++ b/source/blender/depsgraph/intern/nodes/deg_node.h @@ -145,14 +145,8 @@ struct RootDepsNode : public DepsNode { /* ID-Block Reference */ struct IDDepsNode : public DepsNode { struct ComponentIDKey { - ComponentIDKey(eDepsNode_Type type, const char *name = "") - : type(type), name(name) {} - - bool operator== (const ComponentIDKey &other) const - { - return type == other.type && - STREQ(name, other.name); - } + ComponentIDKey(eDepsNode_Type type, const char *name = ""); + bool operator==(const ComponentIDKey &other) const; eDepsNode_Type type; const char *name; diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index 9e7357be2b2..9d2c6169e23 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -52,6 +52,44 @@ namespace DEG { /* Standard Component Methods ============================= */ +ComponentDepsNode::OperationIDKey::OperationIDKey() + : opcode(DEG_OPCODE_OPERATION), + name(""), + name_tag(-1) +{ +} + +ComponentDepsNode::OperationIDKey::OperationIDKey(eDepsOperation_Code opcode) + : opcode(opcode), + name(""), + name_tag(-1) +{ +} + +ComponentDepsNode::OperationIDKey::OperationIDKey(eDepsOperation_Code opcode, + const char *name, + int name_tag) + : opcode(opcode), + name(name), + name_tag(name_tag) +{ +} + +string ComponentDepsNode::OperationIDKey::identifier() const +{ + char codebuf[5]; + BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode); + return string("OperationIDKey(") + codebuf + ", " + name + ")"; +} + +bool ComponentDepsNode::OperationIDKey::operator==( + const OperationIDKey &other) const +{ + return (opcode == other.opcode) && + (STREQ(name, other.name)) && + (name_tag == other.name_tag); +} + static unsigned int comp_node_hash_key(const void *key_v) { const ComponentDepsNode::OperationIDKey *key = diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h index ec2674a7b13..969771a29c9 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h @@ -56,38 +56,14 @@ struct ComponentDepsNode : public DepsNode { const char *name; int name_tag; - OperationIDKey() - : opcode(DEG_OPCODE_OPERATION), - name(""), - name_tag(-1) - {} - OperationIDKey(eDepsOperation_Code opcode) - : opcode(opcode), - name(""), - name_tag(-1) - {} + OperationIDKey(); + OperationIDKey(eDepsOperation_Code opcode); OperationIDKey(eDepsOperation_Code opcode, const char *name, - int name_tag) - : opcode(opcode), - name(name), - name_tag(name_tag) - {} + int name_tag); - string identifier() const - { - char codebuf[5]; - BLI_snprintf(codebuf, sizeof(codebuf), "%d", opcode); - - return string("OperationIDKey(") + codebuf + ", " + name + ")"; - } - - bool operator==(const OperationIDKey &other) const - { - return (opcode == other.opcode) && - (STREQ(name, other.name)) && - (name_tag == other.name_tag); - } + string identifier() const; + bool operator==(const OperationIDKey &other) const; }; /* Typedef for container of operations */ From 65a1fd975cd1bcdff69ec8dadd9187ec2c214617 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 16:25:26 +0100 Subject: [PATCH 123/590] Depsgraph: Move key implementation from header to dedicated file --- source/blender/depsgraph/CMakeLists.txt | 1 + .../intern/builder/deg_builder_relations.h | 126 ++--------- .../builder/deg_builder_relations_keys.cc | 211 ++++++++++++++++++ 3 files changed, 234 insertions(+), 104 deletions(-) create mode 100644 source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index fd2a521bec5..ab12a8d5b3e 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -45,6 +45,7 @@ set(SRC intern/builder/deg_builder_nodes.cc intern/builder/deg_builder_pchanmap.cc intern/builder/deg_builder_relations.cc + intern/builder/deg_builder_relations_keys.cc intern/builder/deg_builder_transitive.cc intern/debug/deg_debug_graphviz.cc intern/eval/deg_eval.cc diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 056d4fdfe3d..8d8ad6772b8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -81,42 +81,26 @@ struct ComponentDepsNode; struct OperationDepsNode; struct RootPChanMap; -struct RootKey -{ - RootKey() {} +struct RootKey { + RootKey(); }; struct TimeSourceKey { - TimeSourceKey() : id(NULL) {} - TimeSourceKey(ID *id) : id(id) {} + TimeSourceKey(); + TimeSourceKey(ID *id); - string identifier() const - { - return string("TimeSourceKey"); - } + string identifier() const; ID *id; }; struct ComponentKey { - ComponentKey() : - id(NULL), type(DEPSNODE_TYPE_UNDEFINED), name("") - {} - ComponentKey(ID *id, eDepsNode_Type type, const char *name = "") : - id(id), type(type), name(name) - {} + ComponentKey(); + ComponentKey(ID *id, eDepsNode_Type type, const char *name = ""); - string identifier() const - { - const char *idname = (id) ? id->name : ""; - - char typebuf[5]; - BLI_snprintf(typebuf, sizeof(typebuf), "%d", type); - - return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')"; - } + string identifier() const; ID *id; eDepsNode_Type type; @@ -125,95 +109,38 @@ struct ComponentKey struct OperationKey { - OperationKey() - : id(NULL), - component_type(DEPSNODE_TYPE_UNDEFINED), - component_name(""), - opcode(DEG_OPCODE_OPERATION), - name(""), - name_tag(-1) - {} - + OperationKey(); OperationKey(ID *id, eDepsNode_Type component_type, const char *name, - int name_tag = -1) - : id(id), - component_type(component_type), - component_name(""), - opcode(DEG_OPCODE_OPERATION), - name(name), - name_tag(name_tag) - {} + int name_tag = -1); OperationKey(ID *id, eDepsNode_Type component_type, const char *component_name, const char *name, - int name_tag) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(DEG_OPCODE_OPERATION), - name(name), - name_tag(name_tag) - {} + int name_tag); OperationKey(ID *id, eDepsNode_Type component_type, - eDepsOperation_Code opcode) - : id(id), - component_type(component_type), - component_name(""), - opcode(opcode), - name(""), - name_tag(-1) - {} + eDepsOperation_Code opcode); OperationKey(ID *id, eDepsNode_Type component_type, const char *component_name, - eDepsOperation_Code opcode) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(opcode), - name(""), - name_tag(-1) - {} + eDepsOperation_Code opcode); OperationKey(ID *id, - eDepsNode_Type component_type, - eDepsOperation_Code opcode, - const char *name, - int name_tag = -1) - : id(id), - component_type(component_type), - component_name(""), - opcode(opcode), - name(name), - name_tag(name_tag) - {} + eDepsNode_Type component_type, + eDepsOperation_Code opcode, + const char *name, + int name_tag = -1); OperationKey(ID *id, eDepsNode_Type component_type, const char *component_name, eDepsOperation_Code opcode, const char *name, - int name_tag = -1) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(opcode), - name(name), - name_tag(name_tag) - {} - - string identifier() const - { - char typebuf[5]; - BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type); - - return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')"; - } + int name_tag = -1); + string identifier() const; ID *id; eDepsNode_Type component_type; @@ -225,21 +152,12 @@ struct OperationKey struct RNAPathKey { - // Note: see depsgraph_build.cpp for implementation + /* NOTE: see depsgraph_build.cpp for implementation */ RNAPathKey(ID *id, const char *path); - RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) : - id(id), ptr(ptr), prop(prop) - {} - - string identifier() const - { - const char *id_name = (id) ? id->name : ""; - const char *prop_name = (prop) ? RNA_property_identifier(prop) : ""; - - return string("RnaPathKey(") + "id: " + id_name + ", prop: " + prop_name + "')"; - } + RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop); + string identifier() const; ID *id; PointerRNA ptr; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc new file mode 100644 index 00000000000..7ada04e8f74 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc @@ -0,0 +1,211 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph + */ + +#include "intern/builder/deg_builder_relations.h" + +namespace DEG { + +///////////////////////////////////////// +// Root. + +RootKey::RootKey() +{ +} + +///////////////////////////////////////// +// Time source. + +TimeSourceKey::TimeSourceKey() + : id(NULL) +{ +} + +TimeSourceKey::TimeSourceKey(ID *id) + : id(id) +{ +} + +string TimeSourceKey::identifier() const +{ + return string("TimeSourceKey"); +} + +///////////////////////////////////////// +// Component. + +ComponentKey::ComponentKey() + : id(NULL), + type(DEPSNODE_TYPE_UNDEFINED), + name("") +{ +} + +ComponentKey::ComponentKey(ID *id, eDepsNode_Type type, const char *name) + : id(id), + type(type), + name(name) +{ +} + +string ComponentKey::identifier() const +{ + const char *idname = (id) ? id->name : ""; + char typebuf[5]; + BLI_snprintf(typebuf, sizeof(typebuf), "%d", type); + return string("ComponentKey(") + + idname + ", " + typebuf + ", '" + name + "')"; +} + +///////////////////////////////////////// +// Operation. + +OperationKey::OperationKey() + : id(NULL), + component_type(DEPSNODE_TYPE_UNDEFINED), + component_name(""), + opcode(DEG_OPCODE_OPERATION), + name(""), + name_tag(-1) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + const char *name, + int name_tag) + : id(id), + component_type(component_type), + component_name(""), + opcode(DEG_OPCODE_OPERATION), + name(name), + name_tag(name_tag) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + const char *component_name, + const char *name, + int name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(DEG_OPCODE_OPERATION), + name(name), + name_tag(name_tag) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + eDepsOperation_Code opcode) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(""), + name_tag(-1) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + const char *component_name, + eDepsOperation_Code opcode) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(""), + name_tag(-1) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + eDepsOperation_Code opcode, + const char *name, + int name_tag) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(name), + name_tag(name_tag) +{ +} + +OperationKey::OperationKey(ID *id, + eDepsNode_Type component_type, + const char *component_name, + eDepsOperation_Code opcode, + const char *name, + int name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(name), + name_tag(name_tag) +{ +} + +string OperationKey::identifier() const +{ + char typebuf[5]; + BLI_snprintf(typebuf, sizeof(typebuf), "%d", component_type); + return string("OperationKey(") + + "t: " + typebuf + + ", cn: '" + component_name + + "', c: " + DEG_OPNAMES[opcode] + + ", n: '" + name + "')"; +} + +///////////////////////////////////////// +// RNA path. + +RNAPathKey::RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) + : id(id), + ptr(ptr), + prop(prop) +{ +} + +string RNAPathKey::identifier() const +{ + const char *id_name = (id) ? id->name : ""; + const char *prop_name = (prop) ? RNA_property_identifier(prop) : ""; + return string("RnaPathKey(") + "id: " + id_name + + ", prop: " + prop_name + "')"; +} + +} // namespace DEG From 4c30a9ee42c386a0938df9f6fa4956116ffbec46 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 3 Nov 2016 17:47:38 +0100 Subject: [PATCH 124/590] Depsgraph: Speedup initial rig build time We don't need to sort bone channels, it's all taken care about by the depsgraph itself. Gives up to 30% initial rig construction time speedup. --- source/blender/blenkernel/BKE_armature.h | 1 + source/blender/blenkernel/intern/armature.c | 10 ++++++++-- .../depsgraph/intern/builder/deg_builder_nodes.cc | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index c2323100205..78d6f6c7cb9 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -97,6 +97,7 @@ void BKE_armature_where_is(struct bArmature *arm); void BKE_armature_where_is_bone(struct Bone *bone, struct Bone *prevbone, const bool use_recursion); void BKE_pose_clear_pointers(struct bPose *pose); void BKE_pose_rebuild(struct Object *ob, struct bArmature *arm); +void BKE_pose_rebuild_ex(struct Object *ob, struct bArmature *arm, const bool sort_bones); void BKE_pose_where_is(struct Scene *scene, struct Object *ob); void BKE_pose_where_is_bone(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime, bool do_extra); void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan); diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index c644fe09364..aaec3a942d4 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1916,7 +1916,7 @@ void BKE_pose_clear_pointers(bPose *pose) /* only after leave editmode, duplicating, validating older files, library syncing */ /* NOTE: pose->flag is set for it */ -void BKE_pose_rebuild(Object *ob, bArmature *arm) +void BKE_pose_rebuild_ex(Object *ob, bArmature *arm, const bool sort_bones) { Bone *bone; bPose *pose; @@ -1963,8 +1963,9 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm) #ifdef WITH_LEGACY_DEPSGRAPH /* the sorting */ /* Sorting for new dependnecy graph is done on the scene graph level. */ - if (counter > 1) + if (counter > 1 && sort_bones) { DAG_pose_sort(ob); + } #endif ob->pose->flag &= ~POSE_RECALC; @@ -1973,6 +1974,11 @@ void BKE_pose_rebuild(Object *ob, bArmature *arm) BKE_pose_channels_hash_make(ob->pose); } +void BKE_pose_rebuild(Object *ob, bArmature *arm) +{ + BKE_pose_rebuild_ex(ob, arm, true); +} + /* ********************** THE POSE SOLVER ******************* */ /* loc/rot/size to given mat4 */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 445b7201aa9..b58e1b04ea5 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -831,7 +831,7 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) /* Rebuild pose if not up to date. */ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild(ob, arm); + BKE_pose_rebuild_ex(ob, arm, false); /* XXX: Without this animation gets lost in certain circumstances * after loading file. Need to investigate further since it does * not happen with simple scenes.. From 21350b73df0ebd78accf3567269e77d6dc774557 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 4 Nov 2016 17:45:14 +0100 Subject: [PATCH 125/590] Despgraph: Optimize cycles detection algorithm The idea is simple: when falling back to one of the nodes which was partially handled we "resume" checking outgoing relations from the index which we stopped. This gives about 15-20% depsgraph construction time save. --- .../intern/builder/deg_builder_cycle.cc | 35 +++++++++++-------- .../depsgraph/intern/depsgraph_build.cc | 2 +- .../blender/depsgraph/intern/nodes/deg_node.h | 3 +- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index 225cc64ae4d..d84a590b29f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -56,12 +56,14 @@ struct StackEntry { void deg_graph_detect_cycles(Depsgraph *graph) { - /* Not is not visited at all during traversal. */ - const int NODE_NOT_VISITED = 0; - /* Node has been visited during traversal and not in current stack. */ - const int NODE_VISITED = 1; - /* Node has been visited during traversal and is in current stack. */ - const int NODE_IN_STACK = 2; + enum { + /* Not is not visited at all during traversal. */ + NODE_NOT_VISITED = 0, + /* Node has been visited during traversal and not in current stack. */ + NODE_VISITED = 1, + /* Node has been visited during traversal and is in current stack. */ + NODE_IN_STACK = 2, + }; std::stack traversal_stack; foreach (OperationDepsNode *node, graph->operations) { @@ -77,21 +79,23 @@ void deg_graph_detect_cycles(Depsgraph *graph) entry.from = NULL; entry.via_relation = NULL; traversal_stack.push(entry); - node->done = NODE_IN_STACK; + node->tag = NODE_IN_STACK; } else { - node->done = NODE_NOT_VISITED; + node->tag = NODE_NOT_VISITED; } + node->done = 0; } while (!traversal_stack.empty()) { - StackEntry &entry = traversal_stack.top(); + StackEntry entry = traversal_stack.top(); OperationDepsNode *node = entry.node; bool all_child_traversed = true; - foreach (DepsRelation *rel, node->outlinks) { + for (int i = node->done; i < node->outlinks.size(); ++i) { + DepsRelation *rel = node->outlinks[i]; if (rel->to->type == DEPSNODE_TYPE_OPERATION) { OperationDepsNode *to = (OperationDepsNode *)rel->to; - if (to->done == NODE_IN_STACK) { + if (to->tag == NODE_IN_STACK) { printf("Dependency cycle detected:\n"); printf(" '%s' depends on '%s' through '%s'\n", to->full_identifier().c_str(), @@ -107,23 +111,24 @@ void deg_graph_detect_cycles(Depsgraph *graph) current->via_relation->name); current = current->from; } - /* TODO(sergey): So called roussian rlette cycle solver. */ + /* TODO(sergey): So called russian roulette cycle solver. */ rel->flag |= DEPSREL_FLAG_CYCLIC; } - else if (to->done == NODE_NOT_VISITED) { + else if (to->tag == NODE_NOT_VISITED) { StackEntry new_entry; new_entry.node = to; new_entry.from = &entry; new_entry.via_relation = rel; traversal_stack.push(new_entry); - to->done = NODE_IN_STACK; + to->tag = NODE_IN_STACK; all_child_traversed = false; + node->done = i; break; } } } if (all_child_traversed) { - node->done = NODE_VISITED; + node->tag = NODE_VISITED; traversal_stack.pop(); } } diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 7b3922a2eaf..e21dac82346 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -32,7 +32,7 @@ #include "MEM_guardedalloc.h" -// #define DEBUG_TIME +#define DEBUG_TIME extern "C" { #include "DNA_cachefile_types.h" diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h index 810c6eeb420..7c2f53840b6 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.h +++ b/source/blender/depsgraph/intern/nodes/deg_node.h @@ -80,8 +80,9 @@ struct DepsNode { /* Nodes which depend on this one. */ Relations outlinks; - /* Generic tag for traversal algorithms */ + /* Generic tags for traversal algorithms. */ int done; + int tag; /* Methods. */ From 9b5a32cbfb8a8565202bdccd232c53f98b62eeec Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 4 Nov 2016 17:46:41 +0100 Subject: [PATCH 126/590] Proxy: Construct pchan hash when syncing armature proxy This makes bone lookup much faster (by avoiding liner string lookup) and speeds up depsgraph construction time on file open. --- source/blender/blenkernel/intern/armature.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index aaec3a942d4..cc508aa0511 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1781,6 +1781,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected BLI_duplicatelist(&pose->agroups, &frompose->agroups); pose->active_group = frompose->active_group; + BKE_pose_channels_hash_make(frompose); for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { pchanp = BKE_pose_channel_find_name(frompose, pchan->name); From 37947ed5524b9cc67bd047701c150499b53e7ed4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 7 Nov 2016 12:09:42 +0100 Subject: [PATCH 127/590] Depsgraph: Do not rely on indirectly included cstring Also add comment why exactly cstring is needed. --- .../blender/depsgraph/intern/builder/deg_builder_relations.cc | 1 + source/blender/depsgraph/intern/eval/deg_eval_debug.cc | 2 ++ source/blender/depsgraph/intern/nodes/deg_node.cc | 1 + source/blender/depsgraph/intern/nodes/deg_node_component.cc | 1 + 4 files changed, 5 insertions(+) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 797fcd80081..2f3c94802e7 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -34,6 +34,7 @@ #include #include +#include /* required for STREQ later on. */ #include "MEM_guardedalloc.h" diff --git a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc index 575b9490478..060544a4407 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_debug.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_debug.cc @@ -32,6 +32,8 @@ #include "intern/eval/deg_eval_debug.h" +#include /* required for STREQ later on. */ + extern "C" { #include "BLI_listbase.h" #include "BLI_ghash.h" diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index 62062314b88..57b25c10670 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -31,6 +31,7 @@ #include "intern/nodes/deg_node.h" #include +#include /* required for STREQ later on. */ #include "BLI_utildefines.h" #include "BLI_ghash.h" diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index 9d2c6169e23..06f91ac7fdc 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -31,6 +31,7 @@ #include "intern/nodes/deg_node_component.h" #include +#include /* required for STREQ later on. */ extern "C" { #include "BLI_utildefines.h" From f51f215bc341eb23aa5decca05962c9c03ff1f26 Mon Sep 17 00:00:00 2001 From: Martijn Berger Date: Mon, 7 Nov 2016 12:32:00 +0100 Subject: [PATCH 128/590] fix building depsgraph after recent changes --- source/blender/depsgraph/intern/depsgraph.cc | 2 ++ source/blender/depsgraph/intern/depsgraph_tag.cc | 1 + 2 files changed, 3 insertions(+) diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index e2fbf4374ad..3502267d9ca 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -51,6 +51,8 @@ extern "C" { #include "RNA_access.h" } +#include + #include "DEG_depsgraph.h" #include "intern/nodes/deg_node.h" diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 00907e417ff..e8ed03666a6 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -31,6 +31,7 @@ */ #include +#include /* required for memset */ #include extern "C" { From 1d01a1a269cba6decf6286faa7a55fadf178eafe Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 7 Nov 2016 12:50:45 +0100 Subject: [PATCH 129/590] Depsgraph: Disable timing profile --- source/blender/depsgraph/intern/depsgraph_build.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index e21dac82346..7b3922a2eaf 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -32,7 +32,7 @@ #include "MEM_guardedalloc.h" -#define DEBUG_TIME +// #define DEBUG_TIME extern "C" { #include "DNA_cachefile_types.h" From c9efcc5e4a43c48f760b06f7d7d2d634a3053c09 Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Mon, 7 Nov 2016 13:22:53 +0100 Subject: [PATCH 130/590] Cycles: Remove device settings from performance tab This was included in the commit by accident, it doesn't belong there. --- intern/cycles/blender/addon/ui.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index d9ad7d967a6..f28fa0d52ba 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -372,8 +372,6 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): rd = scene.render cscene = scene.cycles - context.user_preferences.addons['cycles'].preferences.draw_impl(layout, context) - split = layout.split() col = split.column(align=True) From 6f3f27c0ccf8801be87f0877304642d61c0d98e5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 7 Nov 2016 14:29:11 +0100 Subject: [PATCH 131/590] Buildbot: Update copy of buildbot master configuration --- build_files/buildbot/master.cfg | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build_files/buildbot/master.cfg b/build_files/buildbot/master.cfg index 8bd23357fc6..6b7191cd57b 100644 --- a/build_files/buildbot/master.cfg +++ b/build_files/buildbot/master.cfg @@ -94,6 +94,7 @@ all_repositories = { r'git://git.blender.org/blender-translations.git': 'blender-translations', r'git://git.blender.org/blender-addons.git': 'blender-addons', r'git://git.blender.org/blender-addons-contrib.git': 'blender-addons-contrib', + r'git://git.blender.org/blender-dev-tools.git': 'blender-dev-tools', r'https://svn.blender.org/svnroot/bf-blender/': 'lib svn', } @@ -128,6 +129,7 @@ def schedule_force_build(name): forcesched.CodebaseParameter(hide=True, codebase="blender-translations"), forcesched.CodebaseParameter(hide=True, codebase="blender-addons"), forcesched.CodebaseParameter(hide=True, codebase="blender-addons-contrib"), + forcesched.CodebaseParameter(hide=True, codebase="blender-dev-tools"), forcesched.CodebaseParameter(hide=True, codebase="lib svn")], properties=[])) @@ -143,6 +145,7 @@ def schedule_build(name, hour, minute=0): "blender-translations": {"repository": "", "branch": "master"}, "blender-addons": {"repository": "", "branch": "master"}, "blender-addons-contrib": {"repository": "", "branch": "master"}, + "blender-dev-tools": {"repository": "", "branch": "master"}, "lib svn": {"repository": "", "branch": "trunk"}}, branch=current_branch, builderNames=[name], @@ -264,7 +267,8 @@ def generic_builder(id, libdir='', branch='', rsync=False): for submodule in ('blender-translations', 'blender-addons', - 'blender-addons-contrib'): + 'blender-addons-contrib', + 'blender-dev-tools'): f.addStep(git_submodule_step(submodule)) f.addStep(git_step(branch)) @@ -299,7 +303,8 @@ add_builder(c, 'linux_glibc219_i686_cmake', '', generic_builder, hour=3) add_builder(c, 'linux_glibc219_x86_64_cmake', '', generic_builder, hour=4) add_builder(c, 'win32_cmake_vc2013', 'windows_vc12', generic_builder, hour=3) add_builder(c, 'win64_cmake_vc2013', 'win64_vc12', generic_builder, hour=4) -add_builder(c, 'win64_cmake_vc2015', 'win64_vc14', generic_builder, hour=5) +add_builder(c, 'win32_cmake_vc2015', 'windows_vc14', generic_builder, hour=5) +add_builder(c, 'win64_cmake_vc2015', 'win64_vc14', generic_builder, hour=6) # STATUS TARGETS # From e74e622776a53e4ab5696d4b6fd17638dc2e9210 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 11 Feb 2016 13:51:47 +0100 Subject: [PATCH 132/590] Fix compilation error when CUDA toolkit is not installed After CUDA dynload changes having CUDA toolkit became required in order to compile Cycles. This only happened due to wrong default value to the option. --- intern/cycles/cmake/external_libs.cmake | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/intern/cycles/cmake/external_libs.cmake b/intern/cycles/cmake/external_libs.cmake index 616dd940801..403a0540963 100644 --- a/intern/cycles/cmake/external_libs.cmake +++ b/intern/cycles/cmake/external_libs.cmake @@ -44,6 +44,10 @@ if(WITH_CYCLES_CUDA_BINARIES OR NOT WITH_CUDA_DYNLOAD) else() message(STATUS "CUDA compiler not found, disabling WITH_CYCLES_CUDA_BINARIES") set(WITH_CYCLES_CUDA_BINARIES OFF) + if(NOT WITH_CUDA_DYNLOAD) + message(STATUS "Additionally falling back to dynamic CUDA load") + set(WITH_CUDA_DYNLOAD ON) + endif() endif() endif() From 7a98c43f9d9794e8aef9bd1173e123c7ca0447bc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 8 Nov 2016 04:12:10 +1100 Subject: [PATCH 133/590] BMesh: minor improvement to edge-split assignment --- source/blender/bmesh/intern/bmesh_mods.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index d3c847de64e..3979374d8da 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -598,18 +598,13 @@ BMVert *BM_edge_collapse( BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) { BMVert *v_new, *v_other; + BMEdge *e_new; BMFace **oldfaces = NULL; - BMEdge *e_dummy; BLI_array_staticdeclare(oldfaces, 32); const int cd_loop_mdisp_offset = BM_edge_is_wire(e) ? -1 : CustomData_get_offset(&bm->ldata, CD_MDISPS); BLI_assert(BM_vert_in_edge(e, v) == true); - /* we need this for handling multi-res */ - if (!r_e) { - r_e = &e_dummy; - } - /* do we have a multi-res layer? */ if (cd_loop_mdisp_offset != -1) { BMLoop *l; @@ -630,17 +625,20 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) } v_other = BM_edge_other_vert(e, v); - v_new = bmesh_semv(bm, v, e, r_e); + v_new = bmesh_semv(bm, v, e, &e_new); + if (r_e != NULL) { + *r_e = e_new; + } BLI_assert(v_new != NULL); - BLI_assert(BM_vert_in_edge(*r_e, v) && BM_vert_in_edge(*r_e, v_new)); + BLI_assert(BM_vert_in_edge(e_new, v) && BM_vert_in_edge(e_new, v_new)); BLI_assert(BM_vert_in_edge(e, v_new) && BM_vert_in_edge(e, v_other)); sub_v3_v3v3(v_new->co, v_other->co, v->co); madd_v3_v3v3fl(v_new->co, v->co, v_new->co, fac); - (*r_e)->head.hflag = e->head.hflag; - BM_elem_attrs_copy(bm, bm, e, *r_e); + e_new->head.hflag = e->head.hflag; + BM_elem_attrs_copy(bm, bm, e, e_new); /* v->v_new->v2 */ BM_data_interp_face_vert_edge(bm, v_other, v, v_new, e, fac); @@ -656,7 +654,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) BM_face_calc_center_mean(oldfaces[i], f_center_old); for (j = 0; j < 2; j++) { - BMEdge *e1 = j ? *r_e : e; + BMEdge *e1 = j ? e_new : e; BMLoop *l; l = e1->l; @@ -689,7 +687,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) /* fix boundaries a bit, doesn't work too well quite yet */ #if 0 for (j = 0; j < 2; j++) { - BMEdge *e1 = j ? *r_e : e; + BMEdge *e1 = j ? e_new : e; BMLoop *l, *l2; l = e1->l; From 535914aa466b5e96ab5db6420e520459f0ddfc5f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 5 Nov 2016 07:05:20 +1100 Subject: [PATCH 134/590] BMesh: remove redundant array size Correct unhelpful comment & some comment edits. Rename 'disk_is_flagged' -> 'bm_vert_is_manifold_flagged', since the check is quite specific. --- source/blender/bmesh/intern/bmesh_core.c | 30 ++++++++++--------- source/blender/bmesh/intern/bmesh_queries.c | 2 +- source/blender/bmesh/intern/bmesh_structure.c | 6 ++-- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index d2f638fa8f8..b65307a7ab0 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -1166,7 +1166,11 @@ static int UNUSED_FUNCTION(bm_vert_systag_count_disk)(BMVert *v, const char api_ return i; } -static bool disk_is_flagged(BMVert *v, const char api_flag) +/** + * Return true when the vertex is manifold, + * attached to faces which are all flagged. + */ +static bool bm_vert_is_manifold_flagged(BMVert *v, const char api_flag) { BMEdge *e = v->e; @@ -1225,7 +1229,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) BLI_array_staticdeclare(deledges, BM_DEFAULT_NGON_STACK_SIZE); BLI_array_staticdeclare(delverts, BM_DEFAULT_NGON_STACK_SIZE); BMVert *v1 = NULL, *v2 = NULL; - int i, tote = 0; + int i; const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); if (UNLIKELY(!totface)) { @@ -1255,13 +1259,10 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) v1 = l_iter->v; v2 = BM_edge_other_vert(l_iter->e, l_iter->v); } - tote++; } else if (rlen == 2) { - int d1, d2; - - d1 = disk_is_flagged(l_iter->e->v1, _FLAG_JF); - d2 = disk_is_flagged(l_iter->e->v2, _FLAG_JF); + const bool d1 = bm_vert_is_manifold_flagged(l_iter->e->v1, _FLAG_JF); + const bool d2 = bm_vert_is_manifold_flagged(l_iter->e->v2, _FLAG_JF); if (!d1 && !d2 && !BM_ELEM_API_FLAG_TEST(l_iter->e, _FLAG_JF)) { /* don't remove an edge it makes up the side of another face @@ -1305,7 +1306,8 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) } /* create region face */ - f_new = tote ? BM_face_create_ngon(bm, v1, v2, edges, tote, faces[0], BM_CREATE_NOP) : NULL; + f_new = BLI_array_count(edges) ? + BM_face_create_ngon(bm, v1, v2, edges, BLI_array_count(edges), faces[0], BM_CREATE_NOP) : NULL; if (UNLIKELY(f_new == NULL)) { /* Invalid boundary region to join faces */ goto error; @@ -1323,10 +1325,11 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) } while (l2 != l_iter); if (l2 != l_iter) { - /* I think this is correct? */ + /* loops share an edge, shared vert depends on winding */ if (l2->v != l_iter->v) { l2 = l2->next; } + BLI_assert(l_iter->v == l2->v); BM_elem_attrs_copy(bm, bm, l2, l_iter); } @@ -1677,7 +1680,7 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l_new = bm_loop_create(bm, NULL, NULL, l->f, l, 0); l_new->prev = l; - l_new->next = (l->next); + l_new->next = l->next; l_new->prev->next = l_new; l_new->next->prev = l_new; l_new->v = v_new; @@ -1812,7 +1815,6 @@ BMEdge *bmesh_jekv( BMEdge *e_old; BMVert *v_old, *v_target; BMLoop *l_kill; - bool halt = false; #ifndef NDEBUG int radlen, i; bool edok; @@ -1833,9 +1835,9 @@ BMEdge *bmesh_jekv( e_old = bmesh_disk_edge_next(e_kill, v_kill); v_target = BM_edge_other_vert(e_kill, v_kill); v_old = BM_edge_other_vert(e_old, v_kill); - halt = BM_verts_in_edge(v_kill, v_target, e_old); /* check for double edges */ - - if (halt) { + + /* check for double edges */ + if (BM_verts_in_edge(v_kill, v_target, e_old)) { return NULL; } else { diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index b5f9575aff5..22095214133 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -910,7 +910,7 @@ bool BM_vert_is_wire(const BMVert *v) * A vertex is non-manifold if it meets the following conditions: * 1: Loose - (has no edges/faces incident upon it). * 2: Joins two distinct regions - (two pyramids joined at the tip). - * 3: Is part of a an edge with more than 2 faces. + * 3: Is part of an edge with more than 2 faces. * 4: Is part of a wire edge. */ bool BM_vert_is_manifold(const BMVert *v) diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c index edde8cb5d31..6052de421dd 100644 --- a/source/blender/bmesh/intern/bmesh_structure.c +++ b/source/blender/bmesh/intern/bmesh_structure.c @@ -264,10 +264,12 @@ bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v) { BMEdge *e_iter; - if (!BM_vert_in_edge(e, v)) + if (!BM_vert_in_edge(e, v)) { return false; - if (bmesh_disk_count_ex(v, len + 1) != len || len == 0) + } + if (len == 0 || bmesh_disk_count_ex(v, len + 1) != len) { return false; + } e_iter = e; do { From 28639a22bcba4b6f09165188446e7919bab6fe6b Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Mon, 7 Nov 2016 20:55:12 +0100 Subject: [PATCH 135/590] Fix Brick Texture GLSL, broken after Mortar Smooth addition. --- .../gpu/shaders/gpu_shader_material.glsl | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 67da8201f66..b4e6356ada5 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -2822,7 +2822,7 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c } #ifdef BIT_OPERATIONS -vec2 calc_brick_texture(vec3 p, float mortar_size, float bias, +vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bias, float brick_width, float row_height, float offset_amount, int offset_frequency, float squash_amount, int squash_frequency) @@ -2843,17 +2843,26 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float bias, x = (p.x + offset) - brick_width * bricknum; y = p.y - row_height * rownum; - return vec2(clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0), - (x < mortar_size || y < mortar_size || - x > (brick_width - mortar_size) || - y > (row_height - mortar_size)) ? 1.0 : 0.0); + float tint = clamp((integer_noise((rownum << 16) + (bricknum & 0xFFFF)) + bias), 0.0, 1.0); + + float min_dist = min(min(x, y), min(brick_width - x, row_height - y)); + if(min_dist >= mortar_size) { + return vec2(tint, 0.0); + } + else if(mortar_smooth == 0.0) { + return vec2(tint, 1.0); + } + else { + min_dist = 1.0 - min_dist/mortar_size; + return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist)); + } } #endif void node_tex_brick(vec3 co, vec4 color1, vec4 color2, vec4 mortar, float scale, - float mortar_size, float bias, + float mortar_size, float mortar_smooth, float bias, float brick_width, float row_height, float offset_amount, float offset_frequency, float squash_amount, float squash_frequency, @@ -2861,7 +2870,7 @@ void node_tex_brick(vec3 co, { #ifdef BIT_OPERATIONS vec2 f2 = calc_brick_texture(co * scale, - mortar_size, bias, + mortar_size, mortar_smooth, bias, brick_width, row_height, offset_amount, int(offset_frequency), squash_amount, int(squash_frequency)); From 99127925642baf817902821eb2c530282aed9811 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Mon, 7 Nov 2016 20:59:09 +0100 Subject: [PATCH 136/590] Forgot this in last commit. (Brick GLSL). --- source/blender/gpu/shaders/gpu_shader_material.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index b4e6356ada5..4416b6494f9 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -2880,7 +2880,7 @@ void node_tex_brick(vec3 co, float facm = 1.0 - tint; color1 = facm * color1 + tint * color2; } - color = (f == 1.0) ? mortar : color1; + color = mix(color1, mortar, f); fac = f; #else color = vec4(1.0); From f19f9be1b92157a105112ecc9c28949d34d94994 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 8 Nov 2016 07:05:29 +1100 Subject: [PATCH 137/590] BMesh: remove redundant edge-split loop initialize Would always set both first1 and first2. --- source/blender/bmesh/intern/bmesh_core.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index b65307a7ab0..c75e2649257 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -1669,7 +1669,7 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) #ifndef NDEBUG int radlen = bmesh_radial_length(l_next); #endif - int first1 = 0, first2 = 0; + bool is_first = true; /* Take the next loop. Remove it from radial. Split it. Append to appropriate radials */ while (l_next) { @@ -1691,13 +1691,8 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l->e = e_new; /* append l into e_new's rad cycle */ - if (!first1) { - first1 = 1; - l->radial_next = l->radial_prev = NULL; - } - - if (!first2) { - first2 = 1; + if (is_first) { + is_first = false; l->radial_next = l->radial_prev = NULL; } @@ -1709,13 +1704,8 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e) l->e = e; /* append l into e_new's rad cycle */ - if (!first1) { - first1 = 1; - l->radial_next = l->radial_prev = NULL; - } - - if (!first2) { - first2 = 1; + if (is_first) { + is_first = false; l->radial_next = l->radial_prev = NULL; } From 508e2f0d694812b244ffdf22325337aa32f918ad Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 8 Nov 2016 10:40:21 +0100 Subject: [PATCH 138/590] Fix T49937: Blender is crashing because of Lamp Data Node Lamp Data node requires shadow sample array which is only enabled when Shadows are enabled in the shading settings. This commit prevents crash but might not give expected render results in such a configuration. --- source/blender/render/intern/source/shadeoutput.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index 9dec2698720..3d6462e09a0 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -2064,11 +2064,13 @@ static float lamp_get_data_internal(ShadeInput *shi, GroupObject *go, float col[ if (lar->mode & LA_SHAD_TEX) do_lamp_tex(lar, lv, shi, shadow, LA_SHAD_TEX); - lamp_get_shadow(lar, shi, inp, shadfac, shi->depth); + if (R.r.mode & R_SHADOW) { + lamp_get_shadow(lar, shi, inp, shadfac, shi->depth); - shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0])); - shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1])); - shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2])); + shadow[0] = 1.0f - ((1.0f - shadfac[0] * shadfac[3]) * (1.0f - shadow[0])); + shadow[1] = 1.0f - ((1.0f - shadfac[1] * shadfac[3]) * (1.0f - shadow[1])); + shadow[2] = 1.0f - ((1.0f - shadfac[2] * shadfac[3]) * (1.0f - shadow[2])); + } } return visifac; From 93ace71bd7cd1942071773536fa755b70e596476 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 8 Nov 2016 10:54:38 +0100 Subject: [PATCH 139/590] Cycles: Only use new light sample threshold for new files This is a late follow-up commit to the light sample threshold changes which caused difference in rendering all existing .blend files which is not something we are happy about: it is fine to use new optimized defaults for new files, but existing ones should always be rendering in the same way as they used to be. Sorry for the inconveniece, but such thing should have been done to begin with. If this setting was modified it will not be reset to zero. Now all render tests should be passing again. P.S. Also really annoying to bump subversion for such reasons, but currently we don't have better way to achieve what we want. --- intern/cycles/blender/addon/version_update.py | 6 ++++++ source/blender/blenkernel/BKE_blender_version.h | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index 830723d6149..951afd37a92 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -278,3 +278,9 @@ def do_versions(self): cscene.pixel_filter_type = cscene.filter_type if cscene.filter_type == 'BLACKMAN_HARRIS': cscene.filter_type = 'GAUSSIAN' + + if bpy.data.version <= (2, 78, 2): + for scene in bpy.data.scenes: + cscene = scene.cycles + if not cscene.is_property_set("light_sampling_threshold"): + cscene.light_sampling_threshold = 0.0 diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 55142510f9e..908e6f214f9 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -28,7 +28,7 @@ * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 278 -#define BLENDER_SUBVERSION 1 +#define BLENDER_SUBVERSION 2 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 From a2d78d7a460302dc3724c8b9efd5b4921e49f762 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 8 Nov 2016 11:16:37 +0100 Subject: [PATCH 140/590] Fix T49838: Noise randomization for frame should be done per interframes as well Add subframe to the animated seed hash calculation. Should be no difference for the regular files, only for cases when scene is rendered from sequencer with a speed effect, which is not really a common thing. --- intern/cycles/blender/blender_sync.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 6e466826c35..8ec9ecfd861 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -255,8 +255,12 @@ void BlenderSync::sync_integrator() integrator->filter_glossy = get_float(cscene, "blur_glossy"); integrator->seed = get_int(cscene, "seed"); - if(get_boolean(cscene, "use_animated_seed")) - integrator->seed = hash_int_2d(b_scene.frame_current(), get_int(cscene, "seed")); + if(get_boolean(cscene, "use_animated_seed")) { + integrator->seed = hash_int_2d(b_scene.frame_current(), + get_int(cscene, "seed")) + + hash_int_2d((int)(b_scene.frame_subframe() * (float)INT_MAX), + get_int(cscene, "seed")); + } integrator->sampling_pattern = (SamplingPattern)get_enum( cscene, From 0085001eb0e375108b3a3b35197fe4788272c136 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 8 Nov 2016 11:54:04 +0100 Subject: [PATCH 141/590] Fix memory leak when Blender is build without Bullet and files with RB is opened --- source/blender/blenkernel/intern/rigidbody.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index f8e96225f36..ebf9f017731 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -65,13 +65,22 @@ #include "BKE_rigidbody.h" #include "BKE_scene.h" -#ifdef WITH_BULLET - /* ************************************** */ /* Memory Management */ /* Freeing Methods --------------------- */ +#ifndef WITH_BULLET + +static void RB_dworld_remove_constraint(void *UNUSED(world), void *UNUSED(con)) {} +static void RB_dworld_remove_body(void *UNUSED(world), void *UNUSED(body)) {} +static void RB_dworld_delete(void *UNUSED(world)) {} +static void RB_body_delete(void *UNUSED(body)) {} +static void RB_shape_delete(void *UNUSED(shape)) {} +static void RB_constraint_delete(void *UNUSED(con)) {} + +#endif + /* Free rigidbody world */ void BKE_rigidbody_free_world(RigidBodyWorld *rbw) { @@ -165,6 +174,8 @@ void BKE_rigidbody_free_constraint(Object *ob) ob->rigidbody_constraint = NULL; } +#ifdef WITH_BULLET + /* Copying Methods --------------------- */ /* These just copy the data, clearing out references to physics objects. @@ -1620,9 +1631,6 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) # pragma GCC diagnostic ignored "-Wunused-parameter" #endif -void BKE_rigidbody_free_world(RigidBodyWorld *rbw) {} -void BKE_rigidbody_free_object(Object *ob) {} -void BKE_rigidbody_free_constraint(Object *ob) {} struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; } struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; } void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) {} From 4f28dac8722a213599add020d41cb04fe262dadf Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 9 Nov 2016 00:04:58 +1100 Subject: [PATCH 142/590] BMesh: remove edge search when flipping faces Replace search with direct lookup. --- source/blender/bmesh/intern/bmesh_core.c | 30 +++++++----------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index c75e2649257..6abc52d75ef 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -1045,9 +1045,9 @@ static bool bm_loop_reverse_loop( #endif const int len = f->len; - BMLoop *l_iter, *oldprev, *oldnext; + BMLoop *l_iter; BMEdge **edar = BLI_array_alloca(edar, len); - int i, j, edok; + int i; for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { bmesh_radial_loop_remove((edar[i] = l_iter->e), l_iter); @@ -1055,8 +1055,8 @@ static bool bm_loop_reverse_loop( /* actually reverse the loop */ for (i = 0, l_iter = l_first; i < len; i++) { - oldnext = l_iter->next; - oldprev = l_iter->prev; + BMLoop *oldnext = l_iter->next; + BMLoop *oldprev = l_iter->prev; l_iter->next = oldprev; l_iter->prev = oldnext; l_iter = oldnext; @@ -1067,26 +1067,12 @@ static bool bm_loop_reverse_loop( } } - if (len == 2) { /* two edged face */ - /* do some verification here! */ - l_first->e = edar[1]; - l_first->next->e = edar[0]; - } - else { - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { - edok = 0; - for (j = 0; j < len; j++) { - edok = BM_verts_in_edge(l_iter->v, l_iter->next->v, edar[j]); - if (edok) { - l_iter->e = edar[j]; - break; - } - } - } - } /* rebuild radial */ - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) + for (i = 0, l_iter = l_first->prev; i < len; i++, l_iter = l_iter->prev) { + BLI_assert(BM_verts_in_edge(l_iter->v, l_iter->next->v, edar[i])); + l_iter->e = edar[i]; bmesh_radial_loop_append(l_iter->e, l_iter); + } #ifndef NDEBUG /* validate radial */ From 682bcb29956c0699e54b7b9200f048b30bebc4d0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 8 Nov 2016 17:11:35 +0100 Subject: [PATCH 143/590] Atomics: Add 32 bit version of fetch and AND/OR --- intern/atomic/atomic_ops.h | 2 ++ intern/atomic/intern/atomic_ops_msvc.h | 10 ++++++++++ intern/atomic/intern/atomic_ops_unix.h | 10 ++++++++++ 3 files changed, 22 insertions(+) diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h index 0bc7905aa07..f78eab7951f 100644 --- a/intern/atomic/atomic_ops.h +++ b/intern/atomic/atomic_ops.h @@ -87,6 +87,8 @@ ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x); ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new); ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x); +ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x); +ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x); ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b); ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b); diff --git a/intern/atomic/intern/atomic_ops_msvc.h b/intern/atomic/intern/atomic_ops_msvc.h index 15ddda246d9..3461719a4e7 100644 --- a/intern/atomic/intern/atomic_ops_msvc.h +++ b/intern/atomic/intern/atomic_ops_msvc.h @@ -81,6 +81,16 @@ ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x) return InterlockedExchangeAdd(p, x); } +ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x) +{ + return InterlockedOr((long *)p, x); +} + +ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x) +{ + return InterlockedAnd((long *)p, x); +} + /******************************************************************************/ /* 8-bit operations. */ diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h index 55c00024244..e63f09c76c5 100644 --- a/intern/atomic/intern/atomic_ops_unix.h +++ b/intern/atomic/intern/atomic_ops_unix.h @@ -169,6 +169,16 @@ ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x) return __sync_fetch_and_add(p, x); } +ATOMIC_INLINE uint32_t atomic_fetch_and_or_uint32(uint32_t *p, uint32_t x) +{ + return __sync_fetch_and_or(p, x); +} + +ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x) +{ + return __sync_fetch_and_and(p, x); +} + #else # error "Missing implementation for 32-bit atomic operations" #endif From 4d0f7c320c29bcb5dcf4435a0740822d00d35493 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 8 Nov 2016 17:54:14 +0100 Subject: [PATCH 144/590] Depsgraph: Use atomics to tag ID when evaluating driver This is required since new dependency graph evaluates drivers in threads so it was possible to have some partially written ID tag there. --- source/blender/blenkernel/BKE_library.h | 2 ++ source/blender/blenkernel/intern/anim_sys.c | 2 +- source/blender/blenkernel/intern/library.c | 12 ++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 79373e343a6..1cc7014765c 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -129,6 +129,8 @@ void BKE_library_make_local( struct Main *bmain, const struct Library *lib, struct GHash *old_to_new_ids, const bool untagged_only, const bool set_fake); +void BKE_id_tag_set_atomic(struct ID *id, int tag); +void BKE_id_tag_clear_atomic(struct ID *id, int tag); /* use when "" is given to new_id() */ #define ID_FALLBACK_NAME N_("Untitled") diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index e3764adb969..a5abc6beff8 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -1657,7 +1657,7 @@ static bool animsys_write_rna_setting(PathResolvedRNA *anim_rna, const float val /* for cases like duplifarmes it's only a temporary so don't * notify anyone of updates */ if (!(id->tag & LIB_TAG_ANIM_NO_RECALC)) { - id->tag |= LIB_TAG_ID_RECALC; + BKE_id_tag_set_atomic(id, LIB_TAG_ID_RECALC); DAG_id_type_tag(G.main, GS(id->name)); } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 5d28a84ef18..5d23788f6f7 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -129,6 +129,8 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" +#include "atomic_ops.h" + /* GS reads the memory pointed at in a specific ordering. * only use this definition, makes little and big endian systems * work fine, in conjunction with MAKE_ID */ @@ -1895,3 +1897,13 @@ void BKE_library_filepath_set(Library *lib, const char *filepath) BLI_path_abs(lib->filepath, basepath); } } + +void BKE_id_tag_set_atomic(ID *id, int tag) +{ + atomic_fetch_and_or_uint32((uint32_t *)&id->tag, tag); +} + +void BKE_id_tag_clear_atomic(ID *id, int tag) +{ + atomic_fetch_and_and_uint32((uint32_t *)&id->tag, ~tag); +} From e9689e1a204ee9b74fae7d0051b79649e79035f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20M=C3=BCller?= Date: Wed, 9 Nov 2016 00:06:49 +0100 Subject: [PATCH 145/590] Fix: setting an audio callback before audio device initialization. --- source/blender/blenkernel/intern/sound.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 3132a8e27e7..f20885b1e8f 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -251,7 +251,8 @@ void BKE_sound_init(struct Main *bmain) void BKE_sound_init_main(struct Main *bmain) { #ifdef WITH_JACK - AUD_setSynchronizerCallback(sound_sync_callback, bmain); + if (sound_device) + AUD_setSynchronizerCallback(sound_sync_callback, bmain); #else (void)bmain; /* unused */ #endif From 49a3eaa3dc416d7f8c96c4c01da95c52a587821b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 9 Nov 2016 22:25:31 +1100 Subject: [PATCH 146/590] BMesh: face-flip, no need for temporary edge-array Reverse loops in-place. --- source/blender/bmesh/intern/bmesh_core.c | 85 ++++++++++++++---------- source/blender/bmesh/intern/bmesh_core.h | 2 +- 2 files changed, 51 insertions(+), 36 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 6abc52d75ef..ac4eb2c33fd 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -1019,18 +1019,12 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l) * \brief Loop Reverse * * Changes the winding order of a face from CW to CCW or vice versa. - * This euler is a bit peculiar in comparison to others as it is its - * own inverse. - * - * BMESH_TODO: reinsert validation code. * * \param cd_loop_mdisp_offset: Cached result of `CustomData_get_offset(&bm->ldata, CD_MDISPS)`. * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp, * (use when flipping normals, disable when mirroring, eg: symmetrize). - * - * \return Success */ -static bool bm_loop_reverse_loop( +static void bm_loop_reverse_loop( BMesh *bm, BMFace *f, #ifdef USE_BMESH_HOLES BMLoopList *lst, @@ -1044,39 +1038,62 @@ static bool bm_loop_reverse_loop( BMLoop *l_first = f->l_first; #endif - const int len = f->len; - BMLoop *l_iter; - BMEdge **edar = BLI_array_alloca(edar, len); - int i; + /* track previous cycles radial state */ + BMEdge *e_prev = l_first->prev->e; + BMLoop *l_prev_radial_next = l_first->prev->radial_next; + BMLoop *l_prev_radial_prev = l_first->prev->radial_prev; + bool is_prev_boundary = l_prev_radial_next == l_prev_radial_next->radial_next; - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { - bmesh_radial_loop_remove((edar[i] = l_iter->e), l_iter); - } + BMLoop *l_iter = l_first; + do { + BMEdge *e_iter = l_iter->e; + BMLoop *l_iter_radial_next = l_iter->radial_next; + BMLoop *l_iter_radial_prev = l_iter->radial_prev; + bool is_iter_boundary = l_iter_radial_next == l_iter_radial_next->radial_next; + +#if 0 + bmesh_radial_loop_remove(e_curr, l_iter); + bmesh_radial_loop_append(e_prev, l_iter); +#else + /* inline loop reversal */ + if (is_prev_boundary) { + /* boundary */ + l_iter->radial_next = l_iter; + l_iter->radial_prev = l_iter; + } + else { + /* non-boundary, replace radial links */ + l_iter->radial_next = l_prev_radial_next; + l_iter->radial_prev = l_prev_radial_prev; + l_prev_radial_next->radial_prev = l_iter; + l_prev_radial_prev->radial_next = l_iter; + } + + if (e_iter->l == l_iter) { + e_iter->l = l_iter->next; + } + l_iter->e = e_prev; +#endif + + SWAP(BMLoop *, l_iter->next, l_iter->prev); - /* actually reverse the loop */ - for (i = 0, l_iter = l_first; i < len; i++) { - BMLoop *oldnext = l_iter->next; - BMLoop *oldprev = l_iter->prev; - l_iter->next = oldprev; - l_iter->prev = oldnext; - l_iter = oldnext; - if (cd_loop_mdisp_offset != -1) { MDisps *md = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_mdisp_offset); BKE_mesh_mdisp_flip(md, use_loop_mdisp_flip); } - } - /* rebuild radial */ - for (i = 0, l_iter = l_first->prev; i < len; i++, l_iter = l_iter->prev) { - BLI_assert(BM_verts_in_edge(l_iter->v, l_iter->next->v, edar[i])); - l_iter->e = edar[i]; - bmesh_radial_loop_append(l_iter->e, l_iter); - } + e_prev = e_iter; + l_prev_radial_next = l_iter_radial_next; + l_prev_radial_prev = l_iter_radial_prev; + is_prev_boundary = is_iter_boundary; + + /* step to next (now swapped) */ + } while ((l_iter = l_iter->prev) != l_first); #ifndef NDEBUG /* validate radial */ - for (i = 0, l_iter = l_first; i < len; i++, l_iter = l_iter->next) { + int i; + for (i = 0, l_iter = l_first; i < f->len; i++, l_iter = l_iter->next) { BM_CHECK_ELEMENT(l_iter); BM_CHECK_ELEMENT(l_iter->e); BM_CHECK_ELEMENT(l_iter->v); @@ -1088,21 +1105,19 @@ static bool bm_loop_reverse_loop( /* Loop indices are no more valid! */ bm->elem_index_dirty |= BM_LOOP; - - return true; } /** * \brief Flip the faces direction */ -bool bmesh_loop_reverse( +void bmesh_loop_reverse( BMesh *bm, BMFace *f, const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip) { #ifdef USE_BMESH_HOLES - return bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip); + bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip); #else - return bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip); + bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip); #endif } diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h index fb5702bc574..f72e9d7b198 100644 --- a/source/blender/bmesh/intern/bmesh_core.h +++ b/source/blender/bmesh/intern/bmesh_core.h @@ -75,7 +75,7 @@ void bmesh_vert_separate( BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select); -bool bmesh_loop_reverse( +void bmesh_loop_reverse( BMesh *bm, BMFace *f, const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip); From e72caa513aa649b43a7765093b5d30f4afd57f14 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 10 Nov 2016 01:08:12 +1100 Subject: [PATCH 147/590] BMesh: Cleanup, remove hole ifdef --- source/blender/bmesh/intern/bmesh_core.c | 26 ++---------------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index ac4eb2c33fd..93ff6f84620 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -1024,19 +1024,11 @@ static int UNUSED_FUNCTION(bm_loop_length)(BMLoop *l) * \param use_loop_mdisp_flip: When set, flip the Z-depth of the mdisp, * (use when flipping normals, disable when mirroring, eg: symmetrize). */ -static void bm_loop_reverse_loop( +void bmesh_loop_reverse( BMesh *bm, BMFace *f, -#ifdef USE_BMESH_HOLES - BMLoopList *lst, -#endif const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip) { - -#ifdef USE_BMESH_HOLES - BMLoop *l_first = lst->first; -#else BMLoop *l_first = f->l_first; -#endif /* track previous cycles radial state */ BMEdge *e_prev = l_first->prev->e; @@ -1052,7 +1044,7 @@ static void bm_loop_reverse_loop( bool is_iter_boundary = l_iter_radial_next == l_iter_radial_next->radial_next; #if 0 - bmesh_radial_loop_remove(e_curr, l_iter); + bmesh_radial_loop_remove(e_iter, l_iter); bmesh_radial_loop_append(e_prev, l_iter); #else /* inline loop reversal */ @@ -1107,20 +1099,6 @@ static void bm_loop_reverse_loop( bm->elem_index_dirty |= BM_LOOP; } -/** - * \brief Flip the faces direction - */ -void bmesh_loop_reverse( - BMesh *bm, BMFace *f, - const int cd_loop_mdisp_offset, const bool use_loop_mdisp_flip) -{ -#ifdef USE_BMESH_HOLES - bm_loop_reverse_loop(bm, f, f->loops.first, cd_loop_mdisp_offset, use_loop_mdisp_flip); -#else - bm_loop_reverse_loop(bm, f, cd_loop_mdisp_offset, use_loop_mdisp_flip); -#endif -} - static void bm_elements_systag_enable(void *veles, int tot, const char api_flag) { BMHeader **eles = veles; From 18be39ff17e995ab09bd9eef2b842f66f5270e37 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 9 Nov 2016 16:42:28 +0100 Subject: [PATCH 148/590] Fix some assert when making local (due to infamous PITA ShapeKey ID). --- source/blender/blenkernel/intern/library.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 5d23788f6f7..14804d0077a 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -264,9 +264,12 @@ void id_fake_user_clear(ID *id) } static int id_expand_local_callback( - void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag)) + void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag)) { - if (*id_pointer) { + /* Can hapen that we get unlinkable ID here, e.g. with shapekey referring to itself (through drivers)... + * Just skip it, shape key can only be either indirectly linked, or fully local, period. + * And let's curse one more time that stupid useless shapekey ID type! */ + if (*id_pointer && *id_pointer != id_self && BKE_idcode_is_linkable(GS((*id_pointer)->name))) { id_lib_extern(*id_pointer); } From 4d9562a3ae34e038b178043446c8e82f2dbd1dbd Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 9 Nov 2016 16:59:29 +0100 Subject: [PATCH 149/590] Depsgraph: Fix crash deleting bones in armature edit mode For the new dependency graph we have to rebuild graph when bones "topology" are changing. --- source/blender/editors/armature/armature_edit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c index ece0f18e96e..47e73f9b777 100644 --- a/source/blender/editors/armature/armature_edit.c +++ b/source/blender/editors/armature/armature_edit.c @@ -1328,6 +1328,7 @@ static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; ED_armature_sync_selection(arm->edbo); + BKE_pose_tag_recalc(CTX_data_main(C), obedit->pose); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); From 47759b14abdeb4aa825a5a207cdbb594d7e717ea Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 10 Nov 2016 03:19:44 +1100 Subject: [PATCH 150/590] BMesh: face-join, remove redundant face assignment Keep ifdef'd out for holes, this isn't needed currently. --- source/blender/bmesh/intern/bmesh_core.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 93ff6f84620..a7e1aa7fb07 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -1317,22 +1317,15 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) #ifdef USE_BMESH_HOLES /* add holes */ BLI_movelisttolist(&f_new->loops, &holes); -#endif /* update loop face pointer */ -#ifdef USE_BMESH_HOLES - for (lst = f_new->loops.first; lst; lst = lst->next) -#endif - { -#ifdef USE_BMESH_HOLES + for (lst = f_new->loops.first; lst; lst = lst->next) { l_iter = l_first = lst->first; -#else - l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); -#endif do { l_iter->f = f_new; } while ((l_iter = l_iter->next) != l_first); } +#endif bm_elements_systag_disable(faces, totface, _FLAG_JF); BM_ELEM_API_FLAG_DISABLE(f_new, _FLAG_JF); From afc8a4f9e2400e7208cc5a58c084912ffe196553 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 9 Nov 2016 19:27:43 +0100 Subject: [PATCH 151/590] Fix UI message. --- source/blender/makesrna/intern/rna_space.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index ffcf12edb2d..b262e6412e3 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1980,7 +1980,7 @@ static void rna_def_space_image_uv(BlenderRNA *brna) 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"}, + "Only show others' UV islands whose active image matches image of the active face"}, {0, NULL, 0, NULL, NULL} }; From 8b8e04cae68b670dda6e1cceeea7f70542113a6b Mon Sep 17 00:00:00 2001 From: Martijn Berger Date: Thu, 10 Nov 2016 10:48:54 +0100 Subject: [PATCH 152/590] let cmake handle calling msbuild for windows buildbots --- build_files/buildbot/slave_compile.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index c2bfd882fde..d66a0302be7 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -183,10 +183,8 @@ if 'cmake' in builder: print('Condifuration FAILED!') sys.exit(retcode) - if 'win32' in builder: - command = ['msbuild', 'INSTALL.vcxproj', '/Property:PlatformToolset=v120_xp', '/p:Configuration=Release'] - elif 'win64' in builder: - command = ['msbuild', 'INSTALL.vcxproj', '/p:Configuration=Release'] + if 'win32' in builder or 'win64' in builder: + command = ['cmake', '--build', '.', '--target', target_name] else: command = target_chroot_prefix + ['make', '-s', '-j2', target_name] From 2138fdb785a84c7eeed651284854ed6256198e4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Thu, 10 Nov 2016 10:42:28 +0100 Subject: [PATCH 153/590] Added bpy.types.ID.make_local() that can make a single ID block local. This new `bpy.types.ID.make_local(clear_proxies=True)` allows Python code to press the "Make Local" button on any ID block. I chose `clear_proxies=True` as the default, since it's the default behaviour of `id_make_local()` (defined in `library.c`). The caller does need to take care of ensuring that linked-in objects don't refer to local data, and that proxies aren't broken. Reviewers: sergey, mont29 Reviewed By: mont29 Subscribers: dfelinto Differential Revision: https://developer.blender.org/D2346 --- source/blender/makesrna/intern/rna_ID.c | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 280ad4aa9b1..5174c957834 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -35,6 +35,7 @@ #include "BLI_utildefines.h" #include "BKE_icons.h" +#include "BKE_object.h" #include "RNA_access.h" #include "RNA_define.h" @@ -347,6 +348,20 @@ static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id) } } +static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int clear_proxy) +{ + /* Special case, as we can't rely on id_make_local(); it clears proxies. */ + if (!clear_proxy && GS(self->name) == ID_OB) { + BKE_object_make_local_ex(bmain, (Object *)self, false, clear_proxy); + } + else { + id_make_local(bmain, self, false, false); + } + + return self->newid ? self->newid : self; +} + + static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain) { AnimData *adt = BKE_animdata_add_id(id); @@ -999,6 +1014,17 @@ static void rna_def_ID(BlenderRNA *brna) parm = RNA_def_pointer(func, "new_id", "ID", "", "New ID to use"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + func = RNA_def_function(srna, "make_local", "rna_ID_make_local"); + RNA_def_function_ui_description(func, "Make this datablock local, return local one " + "(may be a copy of the original, in case it is also indirectly used)"); + RNA_def_function_flag(func, FUNC_USE_MAIN); + RNA_def_boolean(func, "clear_proxy", true, "", + "Whether to clear proxies (the default behavior); can cause proxies to be duplicated" + " when still referred to from another library"); + RNA_def_property_flag(parm, PROP_PYFUNC_OPTIONAL); + parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied"); + RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID"); RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one"); parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages"); From 19774407700c0178f9da73f68f50ba4ba980af64 Mon Sep 17 00:00:00 2001 From: Martijn Berger Date: Thu, 10 Nov 2016 10:55:46 +0100 Subject: [PATCH 154/590] buidlbot, msbuild is slightly different in that is wants to build debug anyway even if we told cmake we want release --- build_files/buildbot/slave_compile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index d66a0302be7..634a1aca77e 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -184,7 +184,7 @@ if 'cmake' in builder: sys.exit(retcode) if 'win32' in builder or 'win64' in builder: - command = ['cmake', '--build', '.', '--target', target_name] + command = ['cmake', '--build', '.', '--target', target_name, '--config'] else: command = target_chroot_prefix + ['make', '-s', '-j2', target_name] From 63b38848a269c42f2d9b4ef6d3597864ec0ab2bf Mon Sep 17 00:00:00 2001 From: Martijn Berger Date: Thu, 10 Nov 2016 11:00:04 +0100 Subject: [PATCH 155/590] buidlbot, msbuild is slightly different in that is wants to build debug anyway even if we told cmake we want release --- build_files/buildbot/slave_compile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_files/buildbot/slave_compile.py b/build_files/buildbot/slave_compile.py index 634a1aca77e..76d538ad578 100644 --- a/build_files/buildbot/slave_compile.py +++ b/build_files/buildbot/slave_compile.py @@ -184,7 +184,7 @@ if 'cmake' in builder: sys.exit(retcode) if 'win32' in builder or 'win64' in builder: - command = ['cmake', '--build', '.', '--target', target_name, '--config'] + command = ['cmake', '--build', '.', '--target', target_name, '--config', 'Release'] else: command = target_chroot_prefix + ['make', '-s', '-j2', target_name] From 0b9b8ab2dd6283f8a9dcc72df64f9e61a75338de Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Thu, 10 Nov 2016 12:23:09 +0100 Subject: [PATCH 156/590] Fix Grease Pencil render in VSE crashes when no strips (#T49975) Solution as suggested by Sergey Sharybin. Initial debugging by Antonio Vazquez. --- source/blender/editors/render/render_opengl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 9d9ccf2f3ba..ea53c8764f2 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -315,6 +315,12 @@ static void screen_opengl_render_doit(OGLRender *oglrender, RenderResult *rr) RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id); IMB_freeImBuf(out); } + else if (gpd){ + /* If there are no strips, Grease Pencil still needs a buffer to draw on */ + ImBuf *out = IMB_allocImBuf(oglrender->sizex, oglrender->sizey, 32, IB_rect); + RE_render_result_rect_from_ibuf(rr, &scene->r, out, oglrender->view_id); + IMB_freeImBuf(out); + } if (gpd) { int i; From aef66a6be00b83f0869f1c33ae0580ea4e43e15d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 10 Nov 2016 15:46:22 +0100 Subject: [PATCH 157/590] Depsgraph: Fix wrong relation from IK solver to pole target Copy paste error... How to avoid those? --- .../blender/depsgraph/intern/builder/deg_builder_relations.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 2f3c94802e7..b2d7de071f8 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1416,7 +1416,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob, if (data->poletar != NULL) { if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { // XXX: same armature issues - ready vs done? - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->subtarget); + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget); add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); } else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) { From f0d53ac10966ea15500ccd75ecabce00bbfd0c56 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 10 Nov 2016 15:49:33 +0100 Subject: [PATCH 158/590] Depsgraph: Fix another issue which seems to be a bug Similar to a previous commit. Doing separately for an easy of bisect. --- .../blender/depsgraph/intern/builder/deg_builder_relations.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index b2d7de071f8..ac5287d5138 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1419,7 +1419,7 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob, ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget); add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); } - else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) { + else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) { /* vertex group target */ /* NOTE: for now, we don't need to represent vertex groups separately... */ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY); From e316636fa84974fcfd989a8b4787535c4d250001 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 10 Nov 2016 17:05:36 +0100 Subject: [PATCH 159/590] Fix `BKE_library_make_local()` trying to also make local proxified objects. Proxified objects can never be local, we can totally ignore them here. This 'fixes' the asserts related to usercount when trying to remap poselib of localized proxified objects (not sure what exactly was going on wrong here, but proxies are a giant can of worms for sane data-blocks handling anyway :/). --- source/blender/blenkernel/intern/library.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 14804d0077a..fc87dade891 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1672,9 +1672,10 @@ void BKE_library_make_local( /* The check on the second line (LIB_TAG_PRE_EXISTING) is done so its * possible to tag data you don't want to be made local, used for * appending data, so any libdata already linked wont become local - * (very nasty to discover all your links are lost after appending) - * */ + * (very nasty to discover all your links are lost after appending). + * Also, never ever make proxified objects local, would not make any sense. */ if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) && + !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) && ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING))) { if (lib == NULL || id->lib == lib) { From 80aae2b6feddfe44d47c7fc6541b6326527a44fd Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 10 Nov 2016 17:18:57 +0100 Subject: [PATCH 160/590] Consider Numpad Enter in pose slide operators It was annoying to only have regular Enter confirming input there. --- source/blender/editors/armature/pose_slide.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index cd0ea23e2d3..8e8345d34c9 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -685,6 +685,7 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event) switch (event->type) { case LEFTMOUSE: /* confirm */ case RETKEY: + case PADENTER: { /* return to normal cursor and header status */ ED_area_headerprint(pso->sa, NULL); From a1aa3a8b75758124a93ddd67ca39dd8c6f7d18a1 Mon Sep 17 00:00:00 2001 From: Mai Lavelle Date: Thu, 6 Oct 2016 14:55:56 +0200 Subject: [PATCH 161/590] Cycles: Add comments to endif directives `kernel_path.h` and `kernel_path_branched.h` have a lot of conditional code and it was kind of hard to tell what code belonged to which directive. Should be easier to read now. --- intern/cycles/kernel/kernel_path.h | 56 ++++++++++----------- intern/cycles/kernel/kernel_path_branched.h | 42 ++++++++-------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 4237fdb32ff..6d89a89ed5b 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -84,7 +84,7 @@ ccl_device_noinline void kernel_path_ao(KernelGlobals *kg, light_ray.t = kernel_data.background.ao_distance; #ifdef __OBJECT_MOTION__ light_ray.time = ccl_fetch(sd, time); -#endif +#endif /* __OBJECT_MOTION__ */ light_ray.dP = ccl_fetch(sd, dP); light_ray.dD = differential3_zero(); @@ -138,7 +138,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, state->bounce); } } -#endif +#endif /* __LAMP_MIS__ */ #ifdef __VOLUME__ /* volume attenuation, emission, scatter */ @@ -239,7 +239,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, } } else -# endif +# endif /* __VOLUME_DECOUPLED__ */ { /* integrate along volume segment with distance sampling */ VolumeIntegrateResult result = kernel_volume_integrate( @@ -271,10 +271,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, break; } } -# endif +# endif /* __VOLUME_SCATTER__ */ } } -#endif +#endif /* __VOLUME__ */ if(!hit) { #ifdef __BACKGROUND__ @@ -284,7 +284,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, throughput, L_background, state->bounce); -#endif +#endif /* __BACKGROUND__ */ break; } @@ -298,7 +298,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); #ifdef __BRANCHED_PATH__ shader_merge_closures(sd); -#endif +#endif /* __BRANCHED_PATH__ */ /* blurring of bsdf after bounces, for rays that have a small likelihood * of following this particular path (diffuse, rough glossy) */ @@ -321,7 +321,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, state->ray_pdf); path_radiance_accum_emission(L, throughput, emission, state->bounce); } -#endif +#endif /* __EMISSION__ */ /* path termination. this is a strange place to put the termination, it's * mainly due to the mixed in MIS that we use. gives too many unneeded @@ -348,7 +348,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, if(kernel_data.integrator.use_ambient_occlusion || (sd->flag & SD_AO)) { kernel_path_ao(kg, sd, emission_sd, L, state, rng, throughput, make_float3(0.0f, 0.0f, 0.0f)); } -#endif +#endif /* __AO__ */ #ifdef __SUBSURFACE__ /* bssrdf scatter to a different location on the same object, replacing @@ -380,7 +380,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, false); } } -#endif +#endif /* __SUBSURFACE__ */ #if defined(__EMISSION__) && defined(__BRANCHED_PATH__) if(kernel_data.integrator.use_direct_light) { @@ -395,7 +395,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, L, all); } -#endif +#endif /* defined(__EMISSION__) && defined(__BRANCHED_PATH__) */ if(!kernel_path_surface_bounce(kg, rng, sd, &throughput, state, L, ray)) break; @@ -449,7 +449,7 @@ bool kernel_path_subsurface_scatter( ss_indirect->need_update_volume_stack = kernel_data.integrator.use_volumes && ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME; -# endif +# endif /* __VOLUME__ */ /* compute lighting with the BSDF closure */ for(int hit = 0; hit < num_hits; hit++) { @@ -492,7 +492,7 @@ bool kernel_path_subsurface_scatter( { # ifdef __LAMP_MIS__ hit_state->ray_t = 0.0f; -# endif +# endif /* __LAMP_MIS__ */ # ifdef __VOLUME__ if(ss_indirect->need_update_volume_stack) { @@ -507,7 +507,7 @@ bool kernel_path_subsurface_scatter( &volume_ray, hit_state->volume_stack); } -# endif +# endif /* __VOLUME__ */ path_radiance_reset_indirect(L); ss_indirect->num_rays++; } @@ -593,14 +593,14 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, #ifdef __KERNEL_DEBUG__ DebugData debug_data; debug_data_init(&debug_data); -#endif +#endif /* __KERNEL_DEBUG__ */ #ifdef __SUBSURFACE__ SubsurfaceIndirectRays ss_indirect; kernel_path_subsurface_init_indirect(&ss_indirect); for(;;) { -#endif +#endif /* __SUBSURFACE__ */ /* path iteration */ for(;;) { @@ -626,7 +626,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax); #else bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f); -#endif +#endif /* __HAIR__ */ #ifdef __KERNEL_DEBUG__ if(state.flag & PATH_RAY_CAMERA) { @@ -634,7 +634,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, debug_data.num_bvh_traversed_instances += isect.num_traversed_instances; } debug_data.num_ray_bounces++; -#endif +#endif /* __KERNEL_DEBUG__ */ #ifdef __LAMP_MIS__ if(kernel_data.integrator.use_lamp_mis && !(state.flag & PATH_RAY_CAMERA)) { @@ -655,7 +655,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, if(indirect_lamp_emission(kg, &emission_sd, &state, &light_ray, &emission)) path_radiance_accum_emission(&L, throughput, emission, state.bounce); } -#endif +#endif /* __LAMP_MIS__ */ #ifdef __VOLUME__ /* volume attenuation, emission, scatter */ @@ -719,7 +719,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, } } else -# endif +# endif /* __VOLUME_DECOUPLED__ */ { /* integrate along volume segment with distance sampling */ VolumeIntegrateResult result = kernel_volume_integrate( @@ -736,10 +736,10 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, else break; } -# endif +# endif /* __VOLUME_SCATTER__ */ } } -#endif +#endif /* __VOLUME__ */ if(!hit) { /* eval background shader if nothing hit */ @@ -748,7 +748,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, #ifdef __PASSES__ if(!(kernel_data.film.pass_flag & PASS_BACKGROUND)) -#endif +#endif /* __PASSES__ */ break; } @@ -756,7 +756,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, /* sample background shader */ float3 L_background = indirect_background(kg, &emission_sd, &state, &ray); path_radiance_accum_background(&L, throughput, L_background, state.bounce); -#endif +#endif /* __BACKGROUND__ */ break; } @@ -784,7 +784,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, if(sd.flag & SD_HOLDOUT_MASK) break; } -#endif +#endif /* __HOLDOUT__ */ /* holdout mask objects do not write data passes */ kernel_write_data_passes(kg, buffer, &L, &sd, sample, &state, throughput); @@ -807,7 +807,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf); path_radiance_accum_emission(&L, throughput, emission, state.bounce); } -#endif +#endif /* __EMISSION__ */ /* path termination. this is a strange place to put the termination, it's * mainly due to the mixed in MIS that we use. gives too many unneeded @@ -830,7 +830,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { kernel_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput, shader_bsdf_alpha(kg, &sd)); } -#endif +#endif /* __AO__ */ #ifdef __SUBSURFACE__ /* bssrdf scatter to a different location on the same object, replacing @@ -885,7 +885,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, #ifdef __KERNEL_DEBUG__ kernel_write_debug_passes(kg, buffer, &state, &debug_data, sample); -#endif +#endif /* __KERNEL_DEBUG__ */ return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent); } diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index cdb07db587a..c84727ace99 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -51,7 +51,7 @@ ccl_device_inline void kernel_branched_path_ao(KernelGlobals *kg, light_ray.t = kernel_data.background.ao_distance; #ifdef __OBJECT_MOTION__ light_ray.time = ccl_fetch(sd, time); -#endif +#endif /* __OBJECT_MOTION__ */ light_ray.dP = ccl_fetch(sd, dP); light_ray.dD = differential3_zero(); @@ -169,7 +169,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, Ray volume_ray = *ray; bool need_update_volume_stack = kernel_data.integrator.use_volumes && ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME; -#endif +#endif /* __VOLUME__ */ /* compute lighting with the BSDF closure */ for(int hit = 0; hit < num_hits; hit++) { @@ -200,7 +200,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, &volume_ray, hit_state.volume_stack); } -#endif +#endif /* __VOLUME__ */ #ifdef __EMISSION__ /* direct light */ @@ -217,7 +217,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, L, all); } -#endif +#endif /* __EMISSION__ */ /* indirect light */ kernel_branched_path_surface_indirect_light( @@ -234,7 +234,7 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, } } } -#endif +#endif /* __SUBSURFACE__ */ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, int sample, Ray ray, ccl_global float *buffer) { @@ -256,7 +256,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __KERNEL_DEBUG__ DebugData debug_data; debug_data_init(&debug_data); -#endif +#endif /* __KERNEL_DEBUG__ */ /* Main Loop * Here we only handle transparency intersections from the camera ray. @@ -285,13 +285,13 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in bool hit = scene_intersect(kg, ray, visibility, &isect, &lcg_state, difl, extmax); #else bool hit = scene_intersect(kg, ray, visibility, &isect, NULL, 0.0f, 0.0f); -#endif +#endif /* __HAIR__ */ #ifdef __KERNEL_DEBUG__ debug_data.num_bvh_traversal_steps += isect.num_traversal_steps; debug_data.num_bvh_traversed_instances += isect.num_traversed_instances; debug_data.num_ray_bounces++; -#endif +#endif /* __KERNEL_DEBUG__ */ #ifdef __VOLUME__ /* volume attenuation, emission, scatter */ @@ -432,14 +432,14 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in path_radiance_reset_indirect(&L); } } -#endif +#endif /* __VOLUME_SCATTER__ */ } /* todo: avoid this calculation using decoupled ray marching */ kernel_volume_shadow(kg, &emission_sd, &state, &volume_ray, &throughput); -#endif +#endif /* __VOLUME_DECOUPLED__ */ } -#endif +#endif /* __VOLUME__ */ if(!hit) { /* eval background shader if nothing hit */ @@ -448,7 +448,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __PASSES__ if(!(kernel_data.film.pass_flag & PASS_BACKGROUND)) -#endif +#endif /* __PASSES__ */ break; } @@ -456,7 +456,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* sample background shader */ float3 L_background = indirect_background(kg, &emission_sd, &state, &ray); path_radiance_accum_background(&L, throughput, L_background, state.bounce); -#endif +#endif /* __BACKGROUND__ */ break; } @@ -484,7 +484,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in if(sd.flag & SD_HOLDOUT_MASK) break; } -#endif +#endif /* __HOLDOUT__ */ /* holdout mask objects do not write data passes */ kernel_write_data_passes(kg, buffer, &L, &sd, sample, &state, throughput); @@ -495,7 +495,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in float3 emission = indirect_primitive_emission(kg, &sd, isect.t, state.flag, state.ray_pdf); path_radiance_accum_emission(&L, throughput, emission, state.bounce); } -#endif +#endif /* __EMISSION__ */ /* transparency termination */ if(state.flag & PATH_RAY_TRANSPARENT) { @@ -522,7 +522,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in if(kernel_data.integrator.use_ambient_occlusion || (sd.flag & SD_AO)) { kernel_branched_path_ao(kg, &sd, &emission_sd, &L, &state, rng, throughput); } -#endif +#endif /* __AO__ */ #ifdef __SUBSURFACE__ /* bssrdf scatter to a different location on the same object */ @@ -530,7 +530,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in kernel_branched_path_subsurface_scatter(kg, &sd, &indirect_sd, &emission_sd, &L, &state, rng, &ray, throughput); } -#endif +#endif /* __SUBSURFACE__ */ if(!(sd.flag & SD_HAS_ONLY_VOLUME)) { PathState hit_state = state; @@ -542,7 +542,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in kernel_branched_path_surface_connect_light(kg, rng, &sd, &emission_sd, &hit_state, throughput, 1.0f, &L, all); } -#endif +#endif /* __EMISSION__ */ /* indirect light */ kernel_branched_path_surface_indirect_light(kg, rng, @@ -567,12 +567,12 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in ray.dP = sd.dP; ray.dD.dx = -sd.dI.dx; ray.dD.dy = -sd.dI.dy; -#endif +#endif /* __RAY_DIFFERENTIALS__ */ #ifdef __VOLUME__ /* enter/exit volume */ kernel_volume_stack_enter_exit(kg, &sd, state.volume_stack); -#endif +#endif /* __VOLUME__ */ } float3 L_sum = path_radiance_clamp_and_sum(kg, &L); @@ -581,7 +581,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #ifdef __KERNEL_DEBUG__ kernel_write_debug_passes(kg, buffer, &state, &debug_data, sample); -#endif +#endif /* __KERNEL_DEBUG__ */ return make_float4(L_sum.x, L_sum.y, L_sum.z, 1.0f - L_transparent); } From 4710fa700c8f82455dd6ccb38798a598962e460b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 11:41:33 +0100 Subject: [PATCH 162/590] Depsgraph: Fix wrong relations in array modifier --- source/blender/modifiers/intern/MOD_array.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index ecbc3891e8c..2699c99f4dd 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -149,7 +149,7 @@ static void updateDepsgraph(ModifierData *md, DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier End Cap"); } if (amd->curve_ob) { - DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve"); + DEG_add_object_relation(node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve"); DEG_add_special_eval_flag(scene->depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH); } if (amd->offset_ob != NULL) { From 48971da4c8e20b723fe51a70b27b5cf18d318668 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 11:42:43 +0100 Subject: [PATCH 163/590] Depsgraph: Fix wrong relation names --- source/blender/modifiers/intern/MOD_array.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 2699c99f4dd..b049457e640 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -143,17 +143,17 @@ static void updateDepsgraph(ModifierData *md, { ArrayModifierData *amd = (ArrayModifierData *)md; if (amd->start_cap != NULL) { - DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier Start Cap"); + DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier Start Cap"); } if (amd->end_cap != NULL) { - DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier End Cap"); + DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Array Modifier End Cap"); } if (amd->curve_ob) { - DEG_add_object_relation(node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve"); + DEG_add_object_relation(node, amd->curve_ob, DEG_OB_COMP_GEOMETRY, "Array Modifier Curve"); DEG_add_special_eval_flag(scene->depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH); } if (amd->offset_ob != NULL) { - DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier Offset"); + DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Array Modifier Offset"); } } From 9eeca9e7cd37bc792592e72e6671a73b97563b73 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 13:52:22 +0100 Subject: [PATCH 164/590] Depsgraph: cleanup, no functional changes --- .../blender/depsgraph/DEG_depsgraph_build.h | 102 ++++++++++++++---- .../depsgraph/intern/depsgraph_build.cc | 42 ++++++-- 2 files changed, 115 insertions(+), 29 deletions(-) diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index 0945da439ef..fdc86540171 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -51,8 +51,12 @@ extern "C" { /* Graph Building -------------------------------- */ -/* Build depsgraph for the given scene, and dump results in given graph container */ -void DEG_graph_build_from_scene(struct Depsgraph *graph, struct Main *bmain, struct Scene *scene); +/* Build depsgraph for the given scene, and dump results in given + * graph container. + */ +void DEG_graph_build_from_scene(struct Depsgraph *graph, + struct Main *bmain, + struct Scene *scene); /* Tag relations from the given graph for update. */ void DEG_graph_tag_relations_update(struct Depsgraph *graph); @@ -85,31 +89,69 @@ struct CacheFile; struct Object; typedef enum eDepsSceneComponentType { - DEG_SCENE_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */ - DEG_SCENE_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters? - DEG_SCENE_COMP_SEQUENCER, /* Sequencer Component (Scene Only) */ + /* Parameters Component - Default when nothing else fits + * (i.e. just SDNA property setting). + */ + DEG_SCENE_COMP_PARAMETERS, + /* Animation Component + * TODO(sergey): merge in with parameters? + */ + DEG_SCENE_COMP_ANIMATION, + /* Sequencer Component (Scene Only). */ + DEG_SCENE_COMP_SEQUENCER, } eDepsSceneComponentType; typedef enum eDepsObjectComponentType { - DEG_OB_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */ - DEG_OB_COMP_PROXY, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs? - DEG_OB_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters? - DEG_OB_COMP_TRANSFORM, /* Transform Component (Parenting/Constraints) */ - DEG_OB_COMP_GEOMETRY, /* Geometry Component (DerivedMesh/Displist) */ - + /* Parameters Component - Default when nothing else fits + * (i.e. just SDNA property setting). + */ + DEG_OB_COMP_PARAMETERS, + /* Generic "Proxy-Inherit" Component. + * TODO(sergey): Also for instancing of subgraphs? + */ + DEG_OB_COMP_PROXY, + /* Animation Component. + * + * TODO(sergey): merge in with parameters? + */ + DEG_OB_COMP_ANIMATION, + /* Transform Component (Parenting/Constraints) */ + DEG_OB_COMP_TRANSFORM, + /* Geometry Component (DerivedMesh/Displist) */ + DEG_OB_COMP_GEOMETRY, + /* Evaluation-Related Outer Types (with Subdata) */ - DEG_OB_COMP_EVAL_POSE, /* Pose Component - Owner/Container of Bones Eval */ - DEG_OB_COMP_BONE, /* Bone Component - Child/Subcomponent of Pose */ - - DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */ - DEG_OB_COMP_SHADING, /* Material Shading Component */ - DEG_OB_COMP_CACHE, /* Cache Component */ + + /* Pose Component - Owner/Container of Bones Eval */ + DEG_OB_COMP_EVAL_POSE, + /* Bone Component - Child/Subcomponent of Pose */ + DEG_OB_COMP_BONE, + + /* Particle Systems Component */ + DEG_OB_COMP_EVAL_PARTICLES, + /* Material Shading Component */ + DEG_OB_COMP_SHADING, + /* Cache Component */ + DEG_OB_COMP_CACHE, } eDepsObjectComponentType; -void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description); -void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description); -void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description); -void DEG_add_object_cache_relation(struct DepsNodeHandle *handle, struct CacheFile *cache_file, eDepsObjectComponentType component, const char *description); +void DEG_add_scene_relation(struct DepsNodeHandle *node, + struct Scene *scene, + eDepsSceneComponentType component, + const char *description); +void DEG_add_object_relation(struct DepsNodeHandle *node, struct + Object *ob, + eDepsObjectComponentType component, + const char *description); +void DEG_add_bone_relation(struct DepsNodeHandle *handle, + struct Object *ob, + const char *bone_name, + eDepsObjectComponentType component, + const char *description); +void DEG_add_object_cache_relation(struct DepsNodeHandle *handle, + struct CacheFile *cache_file, + eDepsObjectComponentType component, + const char *description); /* TODO(sergey): Remove once all geometry update is granular. */ void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag); @@ -117,8 +159,22 @@ void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short fla /* Utility functions for physics modifiers */ typedef bool (*DEG_CollobjFilterFunction)(struct Object *obj, struct ModifierData *md); -void DEG_add_collision_relations(struct DepsNodeHandle *handle, struct Scene *scene, Object *ob, struct Group *group, int layer, unsigned int modifier_type, DEG_CollobjFilterFunction fn, bool dupli, const char *name); -void DEG_add_forcefield_relations(struct DepsNodeHandle *handle, struct Scene *scene, Object *ob, struct EffectorWeights *eff, bool add_absorption, int skip_forcefield, const char *name); +void DEG_add_collision_relations(struct DepsNodeHandle *handle, + struct Scene *scene, + Object *ob, + struct Group *group, + int layer, + unsigned int modifier_type, + DEG_CollobjFilterFunction fn, + bool dupli, + const char *name); +void DEG_add_forcefield_relations(struct DepsNodeHandle *handle, + struct Scene *scene, + Object *ob, + struct EffectorWeights *eff, + bool add_absorption, + int skip_forcefield, + const char *name); /* ************************************************ */ diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index 7b3922a2eaf..9952f714145 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -324,7 +324,15 @@ void DEG_scene_graph_free(Scene *scene) } } -void DEG_add_collision_relations(DepsNodeHandle *handle, Scene *scene, Object *ob, Group *group, int layer, unsigned int modifier_type, DEG_CollobjFilterFunction fn, bool dupli, const char *name) +void DEG_add_collision_relations(DepsNodeHandle *handle, + Scene *scene, + Object *ob, + Group *group, + int layer, + unsigned int modifier_type, + DEG_CollobjFilterFunction fn, + bool dupli, + const char *name) { unsigned int numcollobj; Object **collobjs = get_collisionobjects_ext(scene, ob, group, layer, &numcollobj, modifier_type, dupli); @@ -342,7 +350,13 @@ void DEG_add_collision_relations(DepsNodeHandle *handle, Scene *scene, Object *o MEM_freeN(collobjs); } -void DEG_add_forcefield_relations(DepsNodeHandle *handle, Scene *scene, Object *ob, EffectorWeights *effector_weights, bool add_absorption, int skip_forcefield, const char *name) +void DEG_add_forcefield_relations(DepsNodeHandle *handle, + Scene *scene, + Object *ob, + EffectorWeights *effector_weights, + bool add_absorption, + int skip_forcefield, + const char *name) { ListBase *effectors = pdInitEffectors(scene, ob, NULL, effector_weights, false); @@ -354,17 +368,33 @@ void DEG_add_forcefield_relations(DepsNodeHandle *handle, Scene *scene, Object * if (eff->psys) { DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_EVAL_PARTICLES, name); - /* TODO: remove this when/if EVAL_PARTICLES is sufficient for up to date particles */ + /* TODO: remove this when/if EVAL_PARTICLES is sufficient + * for up to date particles. + */ DEG_add_object_relation(handle, eff->ob, DEG_OB_COMP_GEOMETRY, name); } if (eff->pd->forcefield == PFIELD_SMOKEFLOW && eff->pd->f_source) { - DEG_add_object_relation(handle, eff->pd->f_source, DEG_OB_COMP_TRANSFORM, "Smoke Force Domain"); - DEG_add_object_relation(handle, eff->pd->f_source, DEG_OB_COMP_GEOMETRY, "Smoke Force Domain"); + DEG_add_object_relation(handle, + eff->pd->f_source, + DEG_OB_COMP_TRANSFORM, + "Smoke Force Domain"); + DEG_add_object_relation(handle, + eff->pd->f_source, + DEG_OB_COMP_GEOMETRY, + "Smoke Force Domain"); } if (add_absorption && (eff->pd->flag & PFIELD_VISIBILITY)) { - DEG_add_collision_relations(handle, scene, ob, NULL, eff->ob->lay, eModifierType_Collision, NULL, true, "Force Absorption"); + DEG_add_collision_relations(handle, + scene, + ob, + NULL, + eff->ob->lay, + eModifierType_Collision, + NULL, + true, + "Force Absorption"); } } } From 89c1f9db37cc1becdd437fcfdb1877306cc2b329 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 14:04:04 +0100 Subject: [PATCH 165/590] Grease Pencil: Fix python errors opening N panel -> GP with empty VSE Solves errors, but not sure interface is indeed what users will expect. Will ask GP team to check on this. --- .../scripts/startup/bl_ui/properties_grease_pencil_common.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index bc40932018d..08e07b8ed93 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -61,6 +61,9 @@ def gpencil_stroke_placement_settings(context, layout): def gpencil_active_brush_settings_simple(context, layout): brush = context.active_gpencil_brush + if brush is None: + layout.label("No Active Brush") + return col = layout.column() col.label("Active Brush: ") From 915c74a33b4141c3c1ad43b7440b7ad561032493 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 14:24:47 +0100 Subject: [PATCH 166/590] Depsgraph: Add some data builder logic to corresponding function --- .../intern/builder/deg_builder_nodes.cc | 148 ++++++++++++------ 1 file changed, 96 insertions(+), 52 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index b58e1b04ea5..422146da5a3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -447,15 +447,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) case OB_SURF: case OB_MBALL: case OB_LATTICE: - { - /* TODO(sergey): This way using this object's - * properties as driver target works fine. - * - * Does this depend on other nodes? - */ - add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_POST, NULL, - DEG_OPCODE_PLACEHOLDER, "Parameters Eval"); - build_obdata_geom(scene, ob); /* TODO(sergey): Only for until we support granular * update of curves. @@ -467,7 +458,6 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) } } break; - } case OB_ARMATURE: /* Pose */ if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) { @@ -996,6 +986,18 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) { ID *obdata = (ID *)ob->data; + /* TODO(sergey): This way using this object's properties as driver target + * works fine. + * + * Does this depend on other nodes? + */ + add_operation_node(&ob->id, + DEPSNODE_TYPE_PARAMETERS, + DEPSOP_TYPE_POST, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Parameters Eval"); + /* Temporary uber-update node, which does everything. * It is for the being we're porting old dependencies into the new system. * We'll get rid of this node as soon as all the granular update functions @@ -1003,35 +1005,45 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) * * TODO(sergey): Get rid of this node. */ - add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_POST, function_bind(BKE_object_eval_uber_data, _1, scene, ob), + add_operation_node(&ob->id, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_POST, + function_bind(BKE_object_eval_uber_data, _1, scene, ob), DEG_OPCODE_GEOMETRY_UBEREVAL); - add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, NULL, - DEG_OPCODE_PLACEHOLDER, "Eval Init"); + add_operation_node(&ob->id, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Eval Init"); // TODO: "Done" operation /* Modifiers */ if (ob->modifiers.first) { - ModifierData *md; - - for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) { - add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_modifier, _1, scene, ob, md), - DEG_OPCODE_GEOMETRY_MODIFIER, md->name); + for (ModifierData *md = (ModifierData *)ob->modifiers.first; + md != NULL; + md = md->next) + { + add_operation_node(&ob->id, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_EXEC, + function_bind(BKE_object_eval_modifier, + _1, + scene, + ob, + md), + DEG_OPCODE_GEOMETRY_MODIFIER, + md->name); } } /* materials */ if (ob->totcol) { - int a; - - for (a = 1; a <= ob->totcol; a++) { + for (int a = 1; a <= ob->totcol; a++) { Material *ma = give_current_material(ob, a); - - if (ma) { + if (ma != NULL) { // XXX?! ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY); build_material(geom_node, ma); @@ -1056,16 +1068,23 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) build_animdata(obdata); - /* nodes for result of obdata's evaluation, and geometry evaluation on object */ + /* Nodes for result of obdata's evaluation, and geometry + * evaluation on object. + */ switch (ob->type) { case OB_MESH: { //Mesh *me = (Mesh *)ob->data; /* evaluation operations */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, function_bind(BKE_mesh_eval_geometry, _1, (Mesh *)obdata), - DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + function_bind(BKE_mesh_eval_geometry, + _1, + (Mesh *)obdata), + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); break; } @@ -1073,13 +1092,18 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) { Object *mom = BKE_mball_basis_find(scene, ob); - /* motherball - mom depends on children! */ + /* Motherball - mom depends on children! */ if (mom == ob) { /* metaball evaluation operations */ /* NOTE: only the motherball gets evaluated! */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, function_bind(BKE_mball_eval_geometry, _1, (MetaBall *)obdata), - DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + function_bind(BKE_mball_eval_geometry, + _1, + (MetaBall *)obdata), + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); } break; } @@ -1087,34 +1111,54 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) case OB_CURVE: case OB_FONT: { - /* curve evaluation operations */ + /* Curve evaluation operations. */ /* - calculate curve geometry (including path) */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata), - DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + function_bind(BKE_curve_eval_geometry, + _1, + (Curve *)obdata), + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); - /* - calculate curve path - this is used by constraints, etc. */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_EXEC, function_bind(BKE_curve_eval_path, _1, (Curve *)obdata), - DEG_OPCODE_GEOMETRY_PATH, "Path"); + /* Calculate curve path - this is used by constraints, etc. */ + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_EXEC, + function_bind(BKE_curve_eval_path, + _1, + (Curve *)obdata), + DEG_OPCODE_GEOMETRY_PATH, + "Path"); break; } - case OB_SURF: /* Nurbs Surface */ + case OB_SURF: { - /* nurbs evaluation operations */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata), - DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); + /* Nurbs evaluation operations. */ + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + function_bind(BKE_curve_eval_geometry, + _1, + (Curve *)obdata), + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); break; } - case OB_LATTICE: /* Lattice */ + case OB_LATTICE: { - /* lattice evaluation operations */ - add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, function_bind(BKE_lattice_eval_geometry, _1, (Lattice *)obdata), - DEG_OPCODE_PLACEHOLDER, "Geometry Eval"); + /* Lattice evaluation operations. */ + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_INIT, + function_bind(BKE_lattice_eval_geometry, + _1, + (Lattice *)obdata), + DEG_OPCODE_PLACEHOLDER, + "Geometry Eval"); break; } } From 653541ea781002af55ebf4ae9e55e062f41dbb63 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 14:25:26 +0100 Subject: [PATCH 167/590] Depsgraph: Fix missing ID node tag Might have caused nodes created multiple times for the same object. --- source/blender/depsgraph/intern/builder/deg_builder_nodes.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 422146da5a3..7808a12ec53 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -429,6 +429,7 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) id_node->layers |= base->lay; return; } + ob->id.tag |= LIB_TAG_DOIT; IDDepsNode *id_node = add_id_node(&ob->id); id_node->layers |= base->lay; From b1743cda5a4249beafea462288df3cd9556d2cd7 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 14:41:02 +0100 Subject: [PATCH 168/590] Depsgraph: Fix typo in text on curve relation builder --- .../blender/depsgraph/intern/builder/deg_builder_relations.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index ac5287d5138..49ae82390ea 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1916,7 +1916,7 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje } if (ob->type == OB_FONT) { if (cu->textoncurve) { - ComponentKey textoncurve_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY); + ComponentKey textoncurve_key(&cu->textoncurve->id, DEPSNODE_TYPE_GEOMETRY); add_relation(textoncurve_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Text on Curve"); } } From 7dda3cf830a38ebdcc30502a3b1b0cea3885e949 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 14:46:19 +0100 Subject: [PATCH 169/590] Fix T49993: Indirectly used taper/bevel crashes new dependency graph New dependency graph expects strict separation between nodes and relations builder, meaning, if we try to create relation with an object which is not in the graph yet we'll have an error in depsgraph. Now, so far object nodes were created from bases of the current scene, which caused missing objects in graph in certain cases. Didn't find better approach than to simply ensure object nodes exists when we know they'll be used by relation builder. --- .../intern/builder/deg_builder_nodes.cc | 123 +++++++++++++----- .../intern/builder/deg_builder_relations.cc | 3 + 2 files changed, 94 insertions(+), 32 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 7808a12ec53..8cf0fdff915 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -108,6 +108,40 @@ extern "C" { namespace DEG { +namespace { + +struct BuilderWalkUserData { + DepsgraphNodeBuilder *builder; + Scene *scene; +}; + +static void modifier_walk(void *user_data, + struct Object * /*ob*/, + struct Object **obpoin, + int /*cd_flag*/) +{ + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + if (*obpoin) { + data->builder->build_object(data->scene, NULL, *obpoin); + } +} + +void constraint_walk(bConstraint * /*con*/, + ID **idpoin, + bool /*is_reference*/, + void *user_data) +{ + BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; + if (*idpoin) { + ID *id = *idpoin; + if (GS(id) == ID_OB) { + data->builder->build_object(data->scene, NULL, (Object *)id); + } + } +} + +} /* namespace */ + /* ************ */ /* Node Builder */ @@ -405,19 +439,22 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group) { /*Object *ob = go->ob;*/ - /* Each "group object" is effectively a separate instance of the underlying - * object data. When the group is evaluated, the transform results and/or - * some other attributes end up getting overridden by the group + /* Each "group object" is effectively a separate instance of the + * underlying object data. When the group is evaluated, the transform + * results and/or some other attributes end up getting overridden by + * the group. */ } - /* create a node for representing subgraph */ + /* Create a node for representing subgraph. */ SubgraphDepsNode *subgraph_node = m_graph->add_subgraph_node(&group->id); subgraph_node->graph = subgraph; - /* make a copy of the data this node will need? */ - // XXX: do we do this now, or later? - // TODO: need API function which queries graph's ID's hash, and duplicates those blocks thoroughly with all outside links removed... + /* Make a copy of the data this node will need? */ + /* XXX: do we do this now, or later? */ + /* TODO: need API function which queries graph's ID's hash, and duplicates + * those blocks thoroughly with all outside links removed. + */ return subgraph_node; } @@ -432,13 +469,32 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) ob->id.tag |= LIB_TAG_DOIT; IDDepsNode *id_node = add_id_node(&ob->id); - id_node->layers |= base->lay; + if (base != NULL) { + id_node->layers |= base->lay; + } ob->customdata_mask = 0; - /* standard components */ + /* Standard components. */ build_object_transform(scene, ob); - /* object data */ + if (ob->parent != NULL) { + build_object(scene, NULL, ob->parent); + } + if (ob->modifiers.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.scene = scene; + modifiers_foreachObjectLink(ob, modifier_walk, &data); + } + if (ob->constraints.first != NULL) { + BuilderWalkUserData data; + data.builder = this; + data.scene = scene; + modifiers_foreachObjectLink(ob, modifier_walk, &data); + BKE_constraints_id_loop(&ob->constraints, constraint_walk, &data); + } + + /* Object data. */ if (ob->data) { /* type-specific data... */ switch (ob->type) { @@ -1110,9 +1166,10 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) } case OB_CURVE: + case OB_SURF: case OB_FONT: { - /* Curve evaluation operations. */ + /* Curve/nurms evaluation operations. */ /* - calculate curve geometry (including path) */ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY, @@ -1124,28 +1181,30 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) "Geometry Eval"); /* Calculate curve path - this is used by constraints, etc. */ - add_operation_node(obdata, - DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_EXEC, - function_bind(BKE_curve_eval_path, - _1, - (Curve *)obdata), - DEG_OPCODE_GEOMETRY_PATH, - "Path"); - break; - } + if (ELEM(ob->type, OB_CURVE, OB_FONT)) { + add_operation_node(obdata, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_EXEC, + function_bind(BKE_curve_eval_path, + _1, + (Curve *)obdata), + DEG_OPCODE_GEOMETRY_PATH, + "Path"); + } - case OB_SURF: - { - /* Nurbs evaluation operations. */ - add_operation_node(obdata, - DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_INIT, - function_bind(BKE_curve_eval_geometry, - _1, - (Curve *)obdata), - DEG_OPCODE_PLACEHOLDER, - "Geometry Eval"); + /* Make sure objects used for bevel.taper are in the graph. + * NOTE: This objects might be not linked to the scene. + */ + Curve *cu = (Curve *)obdata; + if (cu->bevobj != NULL) { + build_object(scene, NULL, cu->bevobj); + } + if (cu->taperobj != NULL) { + build_object(scene, NULL, cu->bevobj); + } + if (ob->type == OB_FONT && cu->textoncurve != NULL) { + build_object(scene, NULL, cu->textoncurve); + } break; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 49ae82390ea..30b31864414 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1908,15 +1908,18 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje // XXX: these needs geom data, but where is geom stored? if (cu->bevobj) { ComponentKey bevob_key(&cu->bevobj->id, DEPSNODE_TYPE_GEOMETRY); + build_object(bmain, scene, cu->bevobj); add_relation(bevob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Bevel"); } if (cu->taperobj) { ComponentKey taperob_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY); + build_object(bmain, scene, cu->taperobj); add_relation(taperob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Taper"); } if (ob->type == OB_FONT) { if (cu->textoncurve) { ComponentKey textoncurve_key(&cu->textoncurve->id, DEPSNODE_TYPE_GEOMETRY); + build_object(bmain, scene, cu->textoncurve); add_relation(textoncurve_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Text on Curve"); } } From 24d89a1f77277c02a918ba0deb0499080ff55d09 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 15:20:17 +0100 Subject: [PATCH 170/590] Depsgraph: Fix missing DONE flag in relations builder Was causing relations be build twice in certain cases. --- source/blender/depsgraph/intern/builder/deg_builder_relations.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 30b31864414..fe75de5e350 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -450,6 +450,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o if (ob->id.tag & LIB_TAG_DOIT) { return; } + ob->id.tag |= LIB_TAG_DOIT; /* Object Transforms */ eDepsOperation_Code base_op = (ob->parent) ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL; From 2a838c71d9ceba30bb2ec00f303f2d3484b37314 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 15:28:34 +0100 Subject: [PATCH 171/590] Depsgraph: Add missing NULL pointer check --- source/blender/depsgraph/intern/builder/deg_builder_nodes.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 8cf0fdff915..9eeff9f79f6 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -463,7 +463,9 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) { if (ob->id.tag & LIB_TAG_DOIT) { IDDepsNode *id_node = m_graph->find_id_node(&ob->id); - id_node->layers |= base->lay; + if (base != NULL) { + id_node->layers |= base->lay; + } return; } ob->id.tag |= LIB_TAG_DOIT; From 7d33d4439f5cdfebab03b2fc1f71e056b0f536f3 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 11 Nov 2016 16:15:34 +0100 Subject: [PATCH 172/590] Fix T49994: Setting dupligroup which uses indirect relation will crash Did similar trick to old dependency graph: tag invisible relations for update. Might need some re-consideration, see the comment. This should solve our issues with powerlib addon here in the studio. --- .../depsgraph/intern/builder/deg_builder.cc | 53 +++++++++++++++++-- .../intern/builder/deg_builder_nodes.cc | 2 +- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 6169100d574..8939e4cc93a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -34,6 +34,8 @@ #include #include "DNA_anim_types.h" +#include "DNA_object_types.h" +#include "DNA_ID.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" @@ -56,10 +58,46 @@ string deg_fcurve_id_name(const FCurve *fcu) return string(fcu->rna_path) + index_buf; } +static bool check_object_needs_evaluation(Object *object) +{ + if (object->recalc & OB_RECALC_ALL) { + /* Object is tagged for update anyway, no need to re-tag it. */ + return false; + } + if (object->type == OB_MESH) { + return object->derivedFinal == NULL; + } + else if (ELEM(object->type, + OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) + { + return object->curve_cache == NULL; + } + return false; +} + void deg_graph_build_finalize(Depsgraph *graph) { + /* STEP 1: Make sure new invisible dependencies are ready for use. + * + * TODO(sergey): This might do a bit of extra tagging, but it's kinda nice + * to do it ahead of a time and don't spend time on flushing updates on + * every frame change. + */ + GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash) + { + if (id_node->layers == 0 || 1) { + ID *id = id_node->id; + if (GS(id->name) == ID_OB) { + Object *object = (Object *)id; + if (check_object_needs_evaluation(object)) { + id_node->tag_update(graph); + } + } + } + } + GHASH_FOREACH_END(); + /* STEP 2: Flush visibility layers from children to parent. */ std::stack stack; - foreach (OperationDepsNode *node, graph->operations) { IDDepsNode *id_node = node->owner->owner; node->done = 0; @@ -78,7 +116,6 @@ void deg_graph_build_finalize(Depsgraph *graph) node->owner->layers = id_node->layers; id_node->id->tag |= LIB_TAG_DOIT; } - while (!stack.empty()) { OperationDepsNode *node = stack.top(); stack.pop(); @@ -104,8 +141,9 @@ void deg_graph_build_finalize(Depsgraph *graph) } } } - - /* Re-tag IDs for update if it was tagged before the relations update tag. */ + /* STEP 3: Re-tag IDs for update if it was tagged before the relations + * update tag. + */ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash) { GHASH_FOREACH_BEGIN(ComponentDepsNode *, comp, id_node->components) @@ -121,6 +159,13 @@ void deg_graph_build_finalize(Depsgraph *graph) id_node->tag_update(graph); id->tag &= ~LIB_TAG_DOIT; } + else if (GS(id->name) == ID_OB) { + Object *object = (Object *)id; + if (object->recalc & OB_RECALC_ALL) { + id_node->tag_update(graph); + id->tag &= ~LIB_TAG_DOIT; + } + } id_node->finalize_build(); } GHASH_FOREACH_END(); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 9eeff9f79f6..12050e3e003 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -134,7 +134,7 @@ void constraint_walk(bConstraint * /*con*/, BuilderWalkUserData *data = (BuilderWalkUserData *)user_data; if (*idpoin) { ID *id = *idpoin; - if (GS(id) == ID_OB) { + if (GS(id->name) == ID_OB) { data->builder->build_object(data->scene, NULL, (Object *)id); } } From ed957768a06788f2a0586870c34e032f43cfc311 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 11 Nov 2016 18:05:01 +0100 Subject: [PATCH 173/590] Fix crash happening in some cases with MakeLocal operator. Culprit here was once more proxies. Think what was happening here was: 1) Both proxy and proxified armatures' PoseChannels were cleared (needed after remapping due to Bone pointers being stored in pchans). 2) Proxy PoseChannels got rebuilt in `BKE_pose_rebuild_ex()`, which ends, in proxy cases, by actually replacing rebuilt pchans by those from the proxified object... which has not yet been rebuilt. Fixed the issue by merely adding bone pointer to data copied from original pchan into new 'from proxy' one... Sounds much, much safer and sanier anyway, that way we can be sure bone pointer is actually pointing to a bone of the object's armature (this is supposed to be the same Armature datablock between proxy and proxified objects, but that may not be always true especially during makelocal process). --- source/blender/blenkernel/intern/armature.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index cc508aa0511..badfeaee6bd 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1795,6 +1795,7 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected /* copy posechannel to temp, but restore important pointers */ pchanw = *pchanp; + pchanw.bone = pchan->bone; pchanw.prev = pchan->prev; pchanw.next = pchan->next; pchanw.parent = pchan->parent; From cdeaec3b0d151e020f532e0b2cc46742b41a379f Mon Sep 17 00:00:00 2001 From: Antonioya Date: Fri, 11 Nov 2016 20:04:30 +0100 Subject: [PATCH 174/590] GPencil: Create brush set when create new datablock or layer Before this commit, the brush set was created with the first stroke drawing, but if the user creates the datablock or the layer manually (not drawing) the brush list was empty. This commit complement the python fix by Sergey: https://developer.blender.org/rB89c1f9db37cc1becdd437fcfdb1877306cc2b329 --- source/blender/editors/gpencil/gpencil_data.c | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index 7dcbe2cc24c..ae83e899649 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -84,7 +84,8 @@ static int gp_data_add_exec(bContext *C, wmOperator *op) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + ToolSettings *ts = CTX_data_tool_settings(C); + if (gpd_ptr == NULL) { BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); return OPERATOR_CANCELLED; @@ -95,6 +96,15 @@ static int gp_data_add_exec(bContext *C, wmOperator *op) id_us_min(&gpd->id); *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); + + /* if not exist brushes, create a new set */ + if (ts) { + if (BLI_listbase_is_empty(&ts->gp_brushes)) { + /* create new brushes */ + BKE_gpencil_brush_init_presets(ts); + } + } + } /* notifiers */ @@ -174,7 +184,8 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot) static int gp_layer_add_exec(bContext *C, wmOperator *op) { bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL); - + ToolSettings *ts = CTX_data_tool_settings(C); + /* if there's no existing Grease-Pencil data there, add some */ if (gpd_ptr == NULL) { BKE_report(op->reports, RPT_ERROR, "Nowhere for grease pencil data to go"); @@ -183,6 +194,14 @@ static int gp_layer_add_exec(bContext *C, wmOperator *op) if (*gpd_ptr == NULL) *gpd_ptr = BKE_gpencil_data_addnew(DATA_("GPencil")); + /* if not exist brushes, create a new set */ + if (ts) { + if (BLI_listbase_is_empty(&ts->gp_brushes)) { + /* create new brushes */ + BKE_gpencil_brush_init_presets(ts); + } + } + /* add new layer now */ BKE_gpencil_layer_addnew(*gpd_ptr, DATA_("GP_Layer"), true); From 674c3bf89480a3278b3637d1dcfe37532f00711e Mon Sep 17 00:00:00 2001 From: Antonioya Date: Fri, 11 Nov 2016 22:27:10 +0100 Subject: [PATCH 175/590] Fix T49996: VSE opengl render crash with grease pencil if current frame is empty If the opengl render with grease pencil is run from VSE with the current frame outside visible frames, the render pass is wrong and the render must be canceled because nothing to render. Related to #T49975 --- source/blender/editors/render/render_opengl.c | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index ea53c8764f2..16842efb436 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -485,23 +485,24 @@ static void add_gpencil_renderpass(OGLRender *oglrender, RenderResult *rr, Rende /* copy image data from rectf */ // XXX: Needs conversion. unsigned char *src = (unsigned char *)RE_RenderViewGetById(rr, oglrender->view_id)->rect32; - float *dest = rp->rect; + if (src != NULL) { + float *dest = rp->rect; - int x, y, rectx, recty; - rectx = rr->rectx; - recty = rr->recty; - for (y = 0; y < recty; y++) { - for (x = 0; x < rectx; x++) { - unsigned char *pixSrc = src + 4 * (rectx * y + x); - if (pixSrc[3] > 0) { - float *pixDest = dest + 4 * (rectx * y + x); - float float_src[4]; - srgb_to_linearrgb_uchar4(float_src, pixSrc); - addAlphaOverFloat(pixDest, float_src); + int x, y, rectx, recty; + rectx = rr->rectx; + recty = rr->recty; + for (y = 0; y < recty; y++) { + for (x = 0; x < rectx; x++) { + unsigned char *pixSrc = src + 4 * (rectx * y + x); + if (pixSrc[3] > 0) { + float *pixDest = dest + 4 * (rectx * y + x); + float float_src[4]; + srgb_to_linearrgb_uchar4(float_src, pixSrc); + addAlphaOverFloat(pixDest, float_src); + } } } } - /* back layer status */ i = 0; for (bGPDlayer *gph = gpd->layers.first; gph; gph = gph->next) { From 8e4066b9d335d9e38d0f77e3cf69cd7b8f03a606 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 11 Nov 2016 18:58:00 +0100 Subject: [PATCH 176/590] Switch to unsafe but quick freeing of archipelagos of linked data. This *should* work, but do not hesitate to revert in case it creates new crashes in append or makelocal processes. --- source/blender/blenkernel/intern/library.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index fc87dade891..8d7c7d81bd4 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1822,7 +1822,7 @@ void BKE_library_make_local( * 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 +#if 1 BKE_libblock_free_ex(bmain, id, false); #else BKE_libblock_unlink(bmain, id, false, false); From f1ad2ab85f6fc800a1d250d9f43a844c7da145eb Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 11 Nov 2016 19:32:59 +0100 Subject: [PATCH 177/590] Minor optimization to BKE_library_tag_unused_linked_data(). --- source/blender/blenkernel/intern/library_query.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index cec7fbacd80..d286c0af8c5 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -1232,6 +1232,10 @@ void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag) while (i--) { for (ID *id = lb_array[i]->first; id; id = id->next) { + if (id->tag & LIB_TAG_DOIT) { + /* Unused ID (so far), no need to check it further. */ + continue; + } BKE_library_foreach_ID_link(id, foreach_libblock_tag_unused_linked_data_callback, &do_loop, IDWALK_NOP); } } From f6ab97c1ae0f4605a15dd486cfd6388c75cc2e86 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 11 Nov 2016 22:29:54 +0100 Subject: [PATCH 178/590] Enhance BKE_library_make_local() to make it much quicker in complex cases. Basic idea is to split first loop in two, and run checks before making anything actually local, to detect data-blocks that we can directly make local (because we are sure they are only used by already/future local datablocks). This allows to avoid a lot of overhead in later 'cleanup' steps of this function, here with barbershop shot it's four times quicker (from 190s to 48s). We are still far from the instantaneous results of MakeLocal in 2.77, but in that version main characters lose their connection to their armature and remain static after makelocal, so guess new code is still better. ;) There are probably more optimizations possible here, but would rather polish this area of code once we get rid of proxies, those really make it a nightmare to work on. --- source/blender/blenkernel/BKE_library_query.h | 1 + source/blender/blenkernel/intern/library.c | 122 +++++++++++------- .../blender/blenkernel/intern/library_query.c | 34 ++++- 3 files changed, 104 insertions(+), 53 deletions(-) diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index c6b63754b57..1fd671953c2 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -89,5 +89,6 @@ 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); +void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain); #endif /* __BKE_LIBRARY_QUERY_H__ */ diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 8d7c7d81bd4..d0610cd1cb3 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1632,31 +1632,28 @@ void BKE_main_id_clear_newpoins(Main *bmain) * \param untagged_only If true, only make local datablocks not tagged with LIB_TAG_PRE_EXISTING. * \param set_fake If true, set fake user on all localized datablocks (except group and objects ones). */ -/* XXX TODO This function should probably be reworked. - * - * Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether +/* Note: Old (2.77) version was simply making (tagging) datablocks as local, without actually making any check whether * they were also indirectly used or not... * - * Current version uses regular id_make_local callback, but this is not super-efficient since this ends up + * Current version uses regular id_make_local callback, which is not super-efficient since this ends up * duplicating some IDs and then removing original ones (due to missing knowledge of which ID uses some other ID). * - * We could first check all IDs and detect those to be made local that are only used by other local or future-local - * datablocks, and directly tag those as local (instead of going through id_make_local) maybe... - * - * We'll probably need at some point a true dependency graph between datablocks, but for now this should work - * good enough (performances is not a critical point here anyway). + * However, we now have a first check that allows us to use 'direct localization' of a lot of IDs, so performances + * are now *reasonably* OK. */ void BKE_library_make_local( Main *bmain, const Library *lib, GHash *old_to_new_ids, const bool untagged_only, const bool set_fake) { ListBase *lbarray[MAX_LIBARRAY]; - ID *id, *id_next; + ID *id; int a; + LinkNode *todo_ids = NULL; LinkNode *copied_ids = NULL; LinkNode *linked_loop_candidates = NULL; - MemArena *linklist_mem = BLI_memarena_new(256 * sizeof(copied_ids), __func__); + MemArena *linklist_mem = BLI_memarena_new(512 * sizeof(*todo_ids), __func__); + /* Step 1: Detect datablocks to make local. */ for (a = set_listbasepointers(bmain, lbarray); a--; ) { id = lbarray[a]->first; @@ -1664,55 +1661,80 @@ void BKE_library_make_local( * by real datablocks responsible of them. */ const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name))); - for (; id; id = id_next) { + 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 + if (id->lib == NULL) { + id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW); + } + /* The check on the fourth line (LIB_TAG_PRE_EXISTING) is done so its * possible to tag data you don't want to be made local, used for * appending data, so any libdata already linked wont become local * (very nasty to discover all your links are lost after appending). * Also, never ever make proxified objects local, would not make any sense. */ - if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) && - !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) && - ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING))) + else if (!do_skip && id->tag & (LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW) && + ELEM(lib, NULL, id->lib) && + !(GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) && + ((untagged_only == false) || !(id->tag & LIB_TAG_PRE_EXISTING))) { - if (lib == NULL || id->lib == lib) { - if (id->lib) { - /* In this specific case, we do want to make ID local even if it has no local usage yet... */ - if (GS(id->name) == ID_OB) { - /* Special case for objects because we don't want proxy pointers to be - * cleared yet. This will happen down the road in this function. - */ - BKE_object_make_local_ex(bmain, (Object*)id, true, false); - } - 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); - } - } - - if (set_fake) { - if (!ELEM(GS(id->name), ID_OB, ID_GR)) { - /* do not set fake user on objects, groups (instancing) */ - id_fake_user_set(id); - } - } + BLI_linklist_prepend_arena(&todo_ids, id, linklist_mem); + id->tag |= LIB_TAG_DOIT; } } } - /* 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. */ + /* Step 2: Check which datablocks we can directly make local (because they are only used by already, or future, + * local data), others will need to be duplicated and further processed later. */ + BKE_library_indirectly_used_data_tag_clear(bmain); + + /* Step 3: Make IDs local, either directly (quick and simple), or using generic process, + * which involves more complex checks and might instead create a local copy of original linked ID. */ + for (LinkNode *it = todo_ids, *it_next; it; it = it_next) { + it_next = it->next; + id = it->link; + + if (id->tag & LIB_TAG_DOIT) { + /* We know all users of this object are local or will be made fully local, even if currently there are + * some indirect usages. So instead of making a copy that se'll likely get rid of later, directly make + * that data block local. Saves a tremendous amount of time with complex scenes... */ + id_clear_lib_data_ex(bmain, id, true); + BKE_id_expand_local(id); + id->tag &= ~LIB_TAG_DOIT; + } + else { + /* In this specific case, we do want to make ID local even if it has no local usage yet... */ + if (GS(id->name) == ID_OB) { + /* Special case for objects because we don't want proxy pointers to be + * cleared yet. This will happen down the road in this function. + */ + BKE_object_make_local_ex(bmain, (Object*)id, true, false); + } + else { + id_make_local(bmain, id, false, true); + } + + if (id->newid) { + /* Reuse already allocated LinkNode (transferring it from todo_ids to copied_ids). */ + BLI_linklist_prepend_nlink(&copied_ids, id, it); + } + } + + if (set_fake) { + if (!ELEM(GS(id->name), ID_OB, ID_GR)) { + /* do not set fake user on objects, groups (instancing) */ + id_fake_user_set(id); + } + } + } + + /* At this point, we are done with directly made local IDs. Now we have to handle duplicated ones, since their + * remaining linked original counterpart may not be needed anymore... */ + todo_ids = NULL; + + /* Step 4: We have to remap local usages of old (linked) ID to new (local) id in a separated 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 (LinkNode *it = copied_ids; it; it = it->next) { id = it->link; @@ -1725,7 +1747,7 @@ void BKE_library_make_local( } } - /* Third step: remove datablocks that have been copied to be localized and are no more used in the end... + /* Step 5: remove datablocks that have been copied to be localized and are no more used in the end... * Note that we may have to loop more than once here, to tackle dependencies between linked objects... */ bool do_loop = true; while (do_loop) { @@ -1803,7 +1825,7 @@ void BKE_library_make_local( } } - /* Fourth step: Try to find circle dependencies between indirectly-linked-only datablocks. + /* Step 6: 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) { diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index d286c0af8c5..05ca6f8b077 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -1170,8 +1170,9 @@ void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, boo *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)) +/* ***** IDs usages.checking/tagging. ***** */ +static int foreach_libblock_used_linked_data_tag_clear_cb( + void *user_data, ID *self_id, ID **id_p, int UNUSED(cb_flag)) { bool *is_changed = user_data; @@ -1236,7 +1237,34 @@ void BKE_library_tag_unused_linked_data(Main *bmain, const bool do_init_tag) /* Unused ID (so far), no need to check it further. */ continue; } - BKE_library_foreach_ID_link(id, foreach_libblock_tag_unused_linked_data_callback, &do_loop, IDWALK_NOP); + BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP); + } + } + } +} + +/** + * Untag linked data blocks used by other untagged linked datablocks. + * Used to detect datablocks that we can forcefully make local (instead of copying them to later get rid of original): + * All datablocks we want to make local are tagged by caller, after this function has ran caller knows datablocks still + * tagged can directly be made local, since they are only used by other datablocks that will also be made fully local. + */ +void BKE_library_indirectly_used_data_tag_clear(Main *bmain) +{ + ListBase *lb_array[MAX_LIBARRAY]; + + 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) { + if (id->lib == NULL || id->tag & LIB_TAG_DOIT) { + /* Local or non-indirectly-used ID (so far), no need to check it further. */ + continue; + } + BKE_library_foreach_ID_link(id, foreach_libblock_used_linked_data_tag_clear_cb, &do_loop, IDWALK_NOP); } } } From 2dbcb75ed592ee5c821e8512a92b9d083d0c357d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 11 Nov 2016 22:56:47 +0100 Subject: [PATCH 179/590] Minor naming cleanup. --- source/blender/blenkernel/BKE_library_query.h | 2 +- source/blender/blenkernel/intern/library.c | 2 +- source/blender/blenkernel/intern/library_query.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index 1fd671953c2..b17eab6e7c3 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -88,7 +88,7 @@ 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); +void BKE_library_unused_linked_data_tag(struct Main *bmain, const bool do_init_tag); void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain); #endif /* __BKE_LIBRARY_QUERY_H__ */ diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index d0610cd1cb3..d8d700d296c 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1827,7 +1827,7 @@ void BKE_library_make_local( /* Step 6: 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); + BKE_library_unused_linked_data_tag(bmain, false); for (LinkNode *it = linked_loop_candidates; it; it = it->next) { if (it->link == NULL) { continue; diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index 05ca6f8b077..fa75c906fb1 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -1207,7 +1207,7 @@ static int foreach_libblock_used_linked_data_tag_clear_cb( * \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) +void BKE_library_unused_linked_data_set_tag(Main *bmain, const bool do_init_tag) { ListBase *lb_array[MAX_LIBARRAY]; From 8b01a6e0f1ea057f52658ab33a4582d51cea031c Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 11 Nov 2016 23:15:55 +0100 Subject: [PATCH 180/590] BKE_library_make_local(): some minor improvements. Do not set 'real user' to groups every time we run the first clearing loop. And do fully clear properly LIB_TAG_DOIT (this is not yet enforced in existing code, but would love to get to that stage in future, so let's do it at least with new code!). --- source/blender/blenkernel/intern/library.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index d8d700d296c..823901d286f 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1745,6 +1745,12 @@ void BKE_library_make_local( if (old_to_new_ids) { BLI_ghash_insert(old_to_new_ids, id, id->newid); } + + /* 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. */ + if (GS(id->name) == ID_GR && (id->tag & LIB_TAG_INDIRECT) != 0) { + id_us_ensure_real(id->newid); + } } /* Step 5: remove datablocks that have been copied to be localized and are no more used in the end... @@ -1794,11 +1800,6 @@ void BKE_library_make_local( 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! */ @@ -1852,6 +1853,7 @@ void BKE_library_make_local( #endif ((LinkNode *)it->link)->link = NULL; /* Not strictly necessary, but safer (see T49903)... */ it->link = NULL; + id->tag &= ~LIB_TAG_DOIT; } } From dad0c31ceb40e2142b432427cbba7d86cabcf300 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 12 Nov 2016 10:29:38 +1100 Subject: [PATCH 181/590] Fix renaming error in last commit --- source/blender/blenkernel/BKE_library_query.h | 2 +- source/blender/blenkernel/intern/library.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index b17eab6e7c3..a7470107c24 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -88,7 +88,7 @@ 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_unused_linked_data_tag(struct Main *bmain, const bool do_init_tag); +void BKE_library_unused_linked_data_set_tag(struct Main *bmain, const bool do_init_tag); void BKE_library_indirectly_used_data_tag_clear(struct Main *bmain); #endif /* __BKE_LIBRARY_QUERY_H__ */ diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 823901d286f..024fa3b5952 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1828,7 +1828,7 @@ void BKE_library_make_local( /* Step 6: 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_unused_linked_data_tag(bmain, false); + BKE_library_unused_linked_data_set_tag(bmain, false); for (LinkNode *it = linked_loop_candidates; it; it = it->next) { if (it->link == NULL) { continue; From 7fd2efa50765cf101e2ec24d06a96a21b2c91791 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 12 Nov 2016 10:06:53 +1100 Subject: [PATCH 182/590] BMesh: Minor improvement to face-join Pass in loops instead of edge & faces. Nearly all callers have the loop-pairs to pass in. --- source/blender/bmesh/intern/bmesh_mods.c | 39 +++++++------------ source/blender/bmesh/intern/bmesh_mods.h | 2 +- source/blender/bmesh/intern/bmesh_queries.c | 3 +- source/blender/bmesh/operators/bmo_dissolve.c | 12 +++--- .../bmesh/operators/bmo_join_triangles.c | 10 ++--- .../blender/bmesh/operators/bmo_triangulate.c | 5 +-- .../bmesh/tools/bmesh_decimate_dissolve.c | 4 +- 7 files changed, 31 insertions(+), 44 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 3979374d8da..33adfd458b1 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -104,7 +104,6 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v) */ bool BM_disk_dissolve(BMesh *bm, BMVert *v) { - BMFace *f, *f2; BMEdge *e, *keepedge = NULL, *baseedge = NULL; int len = 0; @@ -141,7 +140,7 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) return false; } #else - if (UNLIKELY(!BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true))) { + if (UNLIKELY(!BM_faces_join_pair(bm, e->l, e->l->radial_next, true))) { return false; } else if (UNLIKELY(!BM_vert_collapse_faces(bm, v->e, v, 1.0, true, false, true))) { @@ -159,11 +158,10 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) } /* handle two-valence */ - f = e->l->f; - f2 = e->l->radial_next->f; - - if (f != f2 && !BM_faces_join_pair(bm, f, f2, e, true)) { - return false; + if (e->l != e->l->radial_next) { + if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) { + return false; + } } return true; @@ -176,9 +174,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) done = true; e = v->e; do { - f = NULL; + BMFace *f = NULL; if (BM_edge_is_manifold(e) && (e != baseedge) && (e != keepedge)) { - f = BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true); + f = BM_faces_join_pair(bm, e->l, e->l->radial_next, true); /* return if couldn't join faces in manifold * conditions */ /* !disabled for testing why bad things happen */ @@ -204,12 +202,9 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) if (e->l) { /* get remaining two faces */ - f = e->l->f; - f2 = e->l->radial_next->f; - - if (f != f2) { + if (e->l != e->l->radial_next) { /* join two remaining faces */ - if (!BM_faces_join_pair(bm, f, f2, e, true)) { + if (!BM_faces_join_pair(bm, e->l, e->l->radial_next, true)) { return false; } } @@ -234,20 +229,16 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) * * \return pointer to the combined face */ -BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const bool do_del) +BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del) { - BMFace *faces[2] = {f_a, f_b}; - - BMLoop *l_a = BM_face_edge_share_loop(f_a, e); - BMLoop *l_b = BM_face_edge_share_loop(f_b, e); - - BLI_assert(l_a && l_b); + BLI_assert((l_a != l_b) && (l_a->e == l_b->e)); if (l_a->v == l_b->v) { const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); - bmesh_loop_reverse(bm, f_b, cd_loop_mdisp_offset, true); + bmesh_loop_reverse(bm, l_b->f, cd_loop_mdisp_offset, true); } - + + BMFace *faces[2] = {l_a->f, l_b->f}; return BM_faces_join(bm, faces, 2, do_del); } @@ -1040,7 +1031,7 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f f_hflag_prev_2 = l2->f->head.hflag; /* don't delete the edge, manually remove the edge after so we can copy its attributes */ - f = BM_faces_join_pair(bm, l1->f, l2->f, e, true); + f = BM_faces_join_pair(bm, BM_face_edge_share_loop(l1->f, e), BM_face_edge_share_loop(l2->f, e), true); if (f == NULL) { return NULL; diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h index 2e557e3b606..5e95e9a2cc7 100644 --- a/source/blender/bmesh/intern/bmesh_mods.h +++ b/source/blender/bmesh/intern/bmesh_mods.h @@ -31,7 +31,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v); bool BM_disk_dissolve(BMesh *bm, BMVert *v); -BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e, const bool do_del); +BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del); /** see: bmesh_polygon_edgenet.h for #BM_face_split_edgenet */ diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 22095214133..0287498482a 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -926,7 +926,8 @@ bool BM_vert_is_manifold(const BMVert *v) /* count edges while looking for non-manifold edges */ e_first = e_iter = v->e; - l_first = e_iter->l ? e_iter->l : NULL; + /* may be null */ + l_first = e_iter->l; do { /* loose edge or edge shared by more than two faces, * edges with 1 face user are OK, otherwise we could diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index 05efb14a699..6e3a8a1473d 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -322,12 +322,12 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) } BMO_ITER (e, &eiter, op->slots_in, "edges", BM_EDGE) { - BMFace *fa, *fb; - if (BM_edge_face_pair(e, &fa, &fb)) { + BMLoop *l_a, *l_b; + if (BM_edge_loop_pair(e, &l_a, &l_b)) { BMFace *f_new; /* join faces */ - f_new = BM_faces_join_pair(bm, fa, fb, e, false); + f_new = BM_faces_join_pair(bm, l_a, l_b, false); if (f_new) { /* maintain active face */ @@ -437,12 +437,12 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) { BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { - BMFace *fa, *fb; - if (BM_edge_face_pair(e, &fa, &fb)) { + BMLoop *l_a, *l_b; + if (BM_edge_loop_pair(e, &l_a, &l_b)) { BMFace *f_new; /* join faces */ - f_new = BM_faces_join_pair(bm, fa, fb, e, false); + f_new = BM_faces_join_pair(bm, l_a, l_b, false); /* maintain active face */ if (act_face && bm->act_face == NULL) { diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c index bc620e4a020..655fb346976 100644 --- a/source/blender/bmesh/operators/bmo_join_triangles.c +++ b/source/blender/bmesh/operators/bmo_join_triangles.c @@ -361,16 +361,16 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) qsort(jedges, totedge, sizeof(*jedges), BLI_sortutil_cmp_float); for (i = 0; i < totedge; i++) { - BMFace *f_a, *f_b; + BMLoop *l_a, *l_b; e = jedges[i].data; - f_a = e->l->f; - f_b = e->l->radial_next->f; + l_a = e->l; + l_b = e->l->radial_next; /* check if another edge already claimed this face */ - if ((f_a->len == 3) && (f_b->len == 3)) { + if ((l_a->f->len == 3) && (l_b->f->len == 3)) { BMFace *f_new; - f_new = BM_faces_join_pair(bm, f_a, f_b, e, true); + f_new = BM_faces_join_pair(bm, l_a, l_b, true); if (f_new) { BMO_face_flag_enable(bm, f_new, FACE_OUT); } diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c index 8938d086c1a..6bd3174d27a 100644 --- a/source/blender/bmesh/operators/bmo_triangulate.c +++ b/source/blender/bmesh/operators/bmo_triangulate.c @@ -253,10 +253,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) if (BMO_edge_flag_test(bm, e, ELE_NEW)) { /* in rare cases the edges face will have already been removed from the edge */ if (LIKELY(e->l)) { - BMFace *f_new = BM_faces_join_pair( - bm, e->l->f, - e->l->radial_next->f, e, - false); /* join faces */ + BMFace *f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false); if (f_new) { BMO_face_flag_enable(bm, f_new, ELE_NEW); BM_edge_kill(bm, e); diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c index 978cceee37c..e2c36299ddf 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c +++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c @@ -322,9 +322,7 @@ void BM_mesh_decimate_dissolve_ex( i = BM_elem_index_get(e); if (BM_edge_is_manifold(e)) { - f_new = BM_faces_join_pair(bm, e->l->f, - e->l->radial_next->f, e, - false); /* join faces */ + f_new = BM_faces_join_pair(bm, e->l, e->l->radial_next, false); if (f_new) { BMLoop *l_first, *l_iter; From e00c3ab13fb7121f8a9b1db2fe0ab6b3eb9ab48b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 13 Nov 2016 01:35:22 +1100 Subject: [PATCH 183/590] BMesh: update comments, ifdef'd code --- source/blender/bmesh/intern/bmesh_mods.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 33adfd458b1..bd2bc54d85f 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -131,9 +131,10 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) #if 0 /* handle specific case for three-valence. solve it by * increasing valence to four. this may be hackish. . */ - BMLoop *loop = e->l; - if (loop->v == v) loop = loop->next; - if (!BM_face_split(bm, loop->f, v, loop->v, NULL, NULL, false)) + BMLoop *l_a = BM_face_vert_share_loop(e->l->f, v); + BMLoop *l_b = (e->l->v == v) ? e->l->next : e->l; + + if (!BM_face_split(bm, e->l->f, l_a, l_b, NULL, NULL, false)) return false; if (!BM_disk_dissolve(bm, v)) { @@ -219,15 +220,13 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v) * * Joins two adjacent faces together. * - * Because this method calls to #BM_faces_join to do its work, if a pair - * of faces share multiple edges, the pair of faces will be joined at - * every edge (not just edge \a e). This part of the functionality might need - * to be reconsidered. + * \note This method calls to #BM_faces_join to do its work. + * This means connected edges which also share the two faces will be joined. * * If the windings do not match the winding of the new face will follow - * \a f_a's winding (i.e. \a f_b will be reversed before the join). + * \a l_a's winding (i.e. \a l_b will be reversed before the join). * - * \return pointer to the combined face + * \return The combined face or NULL on failure. */ BMFace *BM_faces_join_pair(BMesh *bm, BMLoop *l_a, BMLoop *l_b, const bool do_del) { @@ -542,7 +541,7 @@ BMEdge *BM_vert_collapse_edge( BMVert *tv2 = BM_edge_other_vert(e2, v_kill); if (tv2) { /* only action, other calls here only get the edge to return */ - e_new = bmesh_jekv(bm, e_kill, v_kill, do_del); + e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true, kill_degenerate_faces); } } } From 627141082b12f266adb43478402edd1900240765 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Sat, 12 Nov 2016 16:14:09 +0100 Subject: [PATCH 184/590] Sculpt UI: Make DynTopo constant detail a resolution value This should make it easier to sculpt in high resolutions, downside is that the new way to calculate maximum edge length is a bit less intuitive. Maximum edge length used to be calculated as blender_unit * percentage_value, now it's blender_unit / value. Reused old DNA struct member, but had to bump subversion to ensure correct compatibility conversion. Also changed default value slightly (would have had to set to 3.333... otherwise). Was Requested by @monio (see https://rightclickselect.com/p/sculpting/zpbbbc/dyntopo-better-scale-input-in-constant-detail-mode) and I think it's worth testing. --- .../scripts/startup/bl_ui/space_view3d_toolbar.py | 2 +- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenloader/intern/versioning_270.c | 13 ++++++++++++- source/blender/editors/interface/resources.c | 14 +++++++++----- source/blender/editors/sculpt_paint/sculpt.c | 9 +++++---- source/blender/makesdna/DNA_scene_types.h | 2 +- source/blender/makesrna/intern/rna_sculpt_paint.c | 10 ++++++---- 7 files changed, 35 insertions(+), 17 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index f97e2d5b2d1..3eb76a3b0f9 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1560,7 +1560,7 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): sub.active = (brush and brush.sculpt_tool != 'MASK') if (sculpt.detail_type_method == 'CONSTANT'): row = sub.row(align=True) - row.prop(sculpt, "constant_detail") + row.prop(sculpt, "constant_detail_resolution") row.operator("sculpt.sample_detail_size", text="", icon='EYEDROPPER') elif (sculpt.detail_type_method == 'BRUSH'): sub.prop(sculpt, "detail_percent") diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 908e6f214f9..baf8510dd0d 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -28,7 +28,7 @@ * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 278 -#define BLENDER_SUBVERSION 2 +#define BLENDER_SUBVERSION 3 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 8e855eb56b8..8133d0496fa 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1427,7 +1427,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } - { + if (!MAIN_VERSION_ATLEAST(main, 278, 3)) { for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) { if (scene->toolsettings != NULL) { ToolSettings *ts = scene->toolsettings; @@ -1454,5 +1454,16 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + /* constant detail for sculpting is now a resolution value instead of + * a percentage, we reuse old DNA struct member but convert it */ + for (Scene *scene = main->scene.first; scene != NULL; scene = scene->id.next) { + if (scene->toolsettings != NULL) { + ToolSettings *ts = scene->toolsettings; + if (ts->sculpt && ts->sculpt->constant_detail != 0.0f) { + ts->sculpt->constant_detail = 100.0f / ts->sculpt->constant_detail; + } + } + } } } diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 5e24dc96255..539284030c2 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -2750,17 +2750,21 @@ void init_userdef_do_versions(void) } } + if (!USER_VERSION_ATLEAST(278, 3)) { + for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) { + /* Keyframe Indicators (were using wrong alpha) */ + btheme->tv3d.time_keyframe[3] = btheme->tv3d.time_gp_keyframe[3] = 255; + btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255; + } + } + /** * Include next version bump. * * (keep this block even if it becomes empty). */ { - for (bTheme *btheme = U.themes.first; btheme; btheme = btheme->next) { - /* Keyframe Indicators (were using wrong alpha) */ - btheme->tv3d.time_keyframe[3] = btheme->tv3d.time_gp_keyframe[3] = 255; - btheme->ttime.time_keyframe[3] = btheme->ttime.time_gp_keyframe[3] = 255; - } + } if (U.pixelsize == 0.0f) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index fe0fb3f5035..53434b18d06 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4688,7 +4688,7 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st sculpt_restore_mesh(sd, ob); if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) { - BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f); + BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail); } else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) { BKE_pbvh_bmesh_detail_size_set(ss->pbvh, ss->cache->radius * sd->detail_percent / 100.0f); @@ -5406,7 +5406,7 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) if (!ts->sculpt->detail_percent) ts->sculpt->detail_percent = 25; if (ts->sculpt->constant_detail == 0.0f) - ts->sculpt->constant_detail = 30.0f; + ts->sculpt->constant_detail = 3.0f; /* Set sane default tiling offsets */ if (!ts->sculpt->paint.tile_offset[0]) ts->sculpt->paint.tile_offset[0] = 1.0f; @@ -5543,7 +5543,7 @@ static int sculpt_detail_flood_fill_exec(bContext *C, wmOperator *UNUSED(op)) size = max_fff(bb_max[0], bb_max[1], bb_max[2]); /* update topology size */ - BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f); + BKE_pbvh_bmesh_detail_size_set(ss->pbvh, 1.0f / sd->constant_detail); sculpt_undo_push_begin("Dynamic topology flood fill"); sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_COORDS); @@ -5608,7 +5608,8 @@ static void sample_detail(bContext *C, int ss_co[2]) ray_start, ray_normal, false); if (srd.hit) { - sd->constant_detail = srd.detail * 100.0f; + /* convert edge length to detail resolution */ + sd->constant_detail = 1.0f / srd.detail; } } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 9b0781ebe70..f5e71ae59a9 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1103,7 +1103,7 @@ typedef struct Sculpt { float gravity_factor; /* scale for constant detail size */ - float constant_detail; + float constant_detail; /* Constant detail resolution (Blender unit / constant_detail) */ float detail_percent; float pad; diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index e169ef0d822..7f405f0fb1f 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -600,10 +600,12 @@ static void rna_def_sculpt(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Detail Percentage", "Maximum edge length for dynamic topology sculpting (in brush percenage)"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "constant_detail", PROP_FLOAT, PROP_PERCENTAGE); - RNA_def_property_range(prop, 0.001, 10000.0); - RNA_def_property_ui_range(prop, 0.1, 100.0, 10, 2); - RNA_def_property_ui_text(prop, "Detail Size", "Maximum edge length for dynamic topology sculpting (as percentage of blender unit)"); + prop = RNA_def_property(srna, "constant_detail_resolution", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "constant_detail"); + RNA_def_property_range(prop, 0.0001, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001, 1000.0, 10, 2); + RNA_def_property_ui_text(prop, "Resolution", "Maximum edge length for dynamic topology sculpting (as divisor " + "of blender unit - higher value means smaller edge length)"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "use_smooth_shading", PROP_BOOLEAN, PROP_NONE); From 188ecee6424f0eae1cf94ca9256795d068aa4200 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 12 Nov 2016 15:26:24 +0100 Subject: [PATCH 185/590] Fix T49985: cycles standalone using wrong socket names for XML reading. --- intern/cycles/app/cycles_xml.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 8a3eb98a5a0..b3be07fce48 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -210,17 +210,6 @@ static void xml_read_camera(XMLReadState& state, pugi::xml_node node) /* Shader */ -static string xml_socket_name(const char *name) -{ - string sname = name; - size_t i; - - while((i = sname.find(" ")) != string::npos) - sname.replace(i, 1, ""); - - return sname; -} - static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml_node graph_node) { xml_read_node(state, shader, graph_node); @@ -255,7 +244,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml ShaderNode *fromnode = (ShaderNode*)graph_reader.node_map[from_node_name]; foreach(ShaderOutput *out, fromnode->outputs) - if(string_iequals(xml_socket_name(out->name().c_str()), from_socket_name.c_str())) + if(string_iequals(out->socket_type.name.string(), from_socket_name.string())) output = out; if(!output) @@ -268,7 +257,7 @@ static void xml_read_shader_graph(XMLReadState& state, Shader *shader, pugi::xml ShaderNode *tonode = (ShaderNode*)graph_reader.node_map[to_node_name]; foreach(ShaderInput *in, tonode->inputs) - if(string_iequals(xml_socket_name(in->name().c_str()), to_socket_name.c_str())) + if(string_iequals(in->socket_type.name.string(), to_socket_name.string())) input = in; if(!input) From 478e59a04ec8eec36217fbc0302e0fbe5ed519a9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 12 Nov 2016 15:26:51 +0100 Subject: [PATCH 186/590] Fix T49985: cycles standalone XML missing distant lights. --- intern/cycles/render/light.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/intern/cycles/render/light.cpp b/intern/cycles/render/light.cpp index c43d646f515..2245c861d5a 100644 --- a/intern/cycles/render/light.cpp +++ b/intern/cycles/render/light.cpp @@ -106,6 +106,7 @@ NODE_DEFINE(Light) static NodeEnum type_enum; type_enum.insert("point", LIGHT_POINT); + type_enum.insert("distant", LIGHT_DISTANT); type_enum.insert("background", LIGHT_BACKGROUND); type_enum.insert("area", LIGHT_AREA); type_enum.insert("spot", LIGHT_SPOT); From 69288737caf4fab6c90558129772b0acaecf8863 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 12 Nov 2016 15:41:42 +0100 Subject: [PATCH 187/590] Fix Cycles standalone not finding CPU device after recent changes. --- intern/cycles/app/cycles_standalone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp index e8168bc15ff..b21e8630cdb 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -337,7 +337,7 @@ static void options_parse(int argc, const char **argv) /* device names */ string device_names = ""; - string devicename = "cpu"; + string devicename = "CPU"; bool list = false; vector& types = Device::available_types(); From b5a58507f2b01be86af63815f6e784b7952903c3 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 12 Nov 2016 17:20:40 +0100 Subject: [PATCH 188/590] Fix Cycles OSL compilation based on modified time not working. --- intern/cycles/util/util_path.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/cycles/util/util_path.cpp b/intern/cycles/util/util_path.cpp index 62ef8fc0b48..5df262fcbbb 100644 --- a/intern/cycles/util/util_path.cpp +++ b/intern/cycles/util/util_path.cpp @@ -757,9 +757,9 @@ uint64_t path_modified_time(const string& path) { path_stat_t st; if(path_stat(path, &st) != 0) { - return st.st_mtime; + return 0; } - return 0; + return st.st_mtime; } bool path_remove(const string& path) From 111e2f5abacc0d93b83de66d1cde8f37e60f1395 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 12 Nov 2016 17:21:21 +0100 Subject: [PATCH 189/590] Fix T49904: Cycles standalone missing default generated texture coordinates. --- intern/cycles/app/cycles_xml.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index b3be07fce48..29a68bf272e 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -395,7 +395,7 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node) int shader = 0; bool smooth = state.smooth; - /* read vertices and polygons, RIB style */ + /* read vertices and polygons */ vector P; vector UV; vector verts, nverts; @@ -521,8 +521,12 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node) sdparams.objecttoworld = state.tfm; } - /* temporary for test compatibility */ - mesh->attributes.remove(ATTR_STD_VERTEX_NORMAL); + /* we don't yet support arbitrary attributes, for now add vertex + * coordinates as generated coordinates if requested */ + if (mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) { + Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); + memcpy(attr->data_float3(), mesh->verts.data(), sizeof(float3)*mesh->verts.size()); + } } /* Light */ From 4151f12713ce38b779e87afffdaf2ab30f9248fd Mon Sep 17 00:00:00 2001 From: Geoffroy Krantz Date: Sat, 12 Nov 2016 18:57:40 +0100 Subject: [PATCH 190/590] Fix Make Vertex Parent operator missing from vertex/curve/lattice menus. Reviewed By: brecht Differential Revision: https://developer.blender.org/D2346 --- release/scripts/startup/bl_ui/space_view3d.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 8a3a5d3b7e8..bb5eb05c4e9 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2477,6 +2477,10 @@ class VIEW3D_MT_edit_mesh_vertices(Menu): layout.menu("VIEW3D_MT_vertex_group") layout.menu("VIEW3D_MT_hook") + layout.separator() + + layout.operator("object.vertex_parent_set") + class VIEW3D_MT_edit_mesh_edges(Menu): bl_label = "Edges" @@ -2731,6 +2735,10 @@ class VIEW3D_MT_edit_curve_ctrlpoints(Menu): layout.menu("VIEW3D_MT_hook") + layout.separator() + + layout.operator("object.vertex_parent_set") + class VIEW3D_MT_edit_curve_segments(Menu): bl_label = "Segments" @@ -2893,6 +2901,10 @@ class VIEW3D_MT_edit_lattice(Menu): layout.separator() + layout.operator("object.vertex_parent_set") + + layout.separator() + layout.menu("VIEW3D_MT_edit_proportional") From 447fc7c4ce3e2c7ddc0590a0373b5831304745e2 Mon Sep 17 00:00:00 2001 From: Gaia Clary Date: Sat, 12 Nov 2016 22:20:07 +0100 Subject: [PATCH 191/590] fix T50004: Removed check for empty mesh and adjusted the vertex import function to accept meshes without vertices as well --- source/blender/collada/MeshImporter.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 6ff6de33d56..8f3bf88af65 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -317,11 +317,6 @@ bool MeshImporter::is_nice_mesh(COLLADAFW::Mesh *mesh) // checks if mesh has su } } - if (mesh->getPositions().empty()) { - fprintf(stderr, "ERROR: Mesh %s has no vertices.\n", name.c_str()); - return false; - } - return true; } @@ -329,11 +324,15 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me) { // vertices COLLADAFW::MeshVertexData& pos = mesh->getPositions(); + if (pos.empty()) { + return; + } + int stride = pos.getStride(0); if (stride == 0) stride = 3; - - me->totvert = mesh->getPositions().getFloatValues()->getCount() / stride; - me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); + + me->totvert = pos.getFloatValues()->getCount() / stride; + me->mvert = (MVert *)CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert); MVert *mvert; int i; From 43703fa4bf446c5726a7dd435c1eaa589431b573 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 12 Nov 2016 22:29:49 +0100 Subject: [PATCH 192/590] Fix T50008: camera DOF Distance picking from W key menu not working. --- source/blender/editors/interface/interface_eyedropper.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 31598a44b09..d7f06b7db13 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -1083,6 +1083,15 @@ static int depthdropper_poll(bContext *C) return 1; } } + else { + RegionView3D *rv3d = CTX_wm_region_view3d(C); + if (rv3d && rv3d->persp == RV3D_CAMOB) { + View3D *v3d = CTX_wm_view3d(C); + if (v3d->camera && v3d->camera->data && !ID_IS_LINKED_DATABLOCK(v3d->camera->data)) { + return 1; + } + } + } return 0; } From cc8132b0c83e60d46e24ecec93744f0dd2b5db90 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 13 Nov 2016 02:27:45 +0100 Subject: [PATCH 193/590] Fix T49997: don't flip texture users menu in texture properties. --- source/blender/editors/space_buttons/buttons_texture.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 58c538c4ee5..72de7e5c81c 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -587,6 +587,8 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUS last_category = user->category; } + + UI_block_flag_enable(block, UI_BLOCK_NO_FLIP); } void uiTemplateTextureUser(uiLayout *layout, bContext *C) From 7e8bf9dbd6836bf71a87c787a92768f78cb68e89 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sun, 13 Nov 2016 12:03:28 +0100 Subject: [PATCH 194/590] Fix T50007: blender offline python documentation in zipped HTML files, not shown correctly. Stupid mistake, os.scandir is not recursive... Patch by @brecht, thanks. --- doc/python_api/sphinx_doc_update.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/doc/python_api/sphinx_doc_update.py b/doc/python_api/sphinx_doc_update.py index 5301f39b2e3..c7f0367a2a0 100755 --- a/doc/python_api/sphinx_doc_update.py +++ b/doc/python_api/sphinx_doc_update.py @@ -142,8 +142,11 @@ def main(): zip_name = "blender_python_reference_%s" % blenver_zip # We can't use 'release' postfix here... zip_path = os.path.join(args.mirror_dir, zip_name) with zipfile.ZipFile(zip_path, 'w') as zf: - for de in os.scandir(api_dir): - zf.write(de.path, arcname=os.path.join(zip_name, de.name)) + for dirname, _, filenames in os.walk(api_dir): + for filename in filenames: + filepath = os.path.join(dirname, filename) + zip_filepath = os.path.join(zip_name, os.path.relpath(filepath, api_dir)) + zf.write(filepath, arcname=zip_filepath) os.rename(zip_path, os.path.join(api_dir, "%s.zip" % zip_name)) # VII) Create symlinks and html redirects. From 1b1d6ce131c93b8a770c873460dce429796849a3 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sun, 13 Nov 2016 15:49:41 +0100 Subject: [PATCH 195/590] Fix T50013: Blender 2.78a Link/Append Crash. Object freeing may in some kind access its obdata (in case it has some caches e.g.), since here obdata may have already been freed, let's set object's data pointer to NULL (probably not ideal solution, but we don't care much, those form archipelagos of unused linked datablocks, we nuke'em all anyway). Also fix stupid mistake in one of own recent commits (using ID we just freed, tsst...). --- source/blender/blenkernel/intern/library.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 024fa3b5952..e5b066a3c26 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1841,6 +1841,12 @@ void BKE_library_make_local( /* 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) { + /* Object's deletion rely on valid ob->data, but ob->data may have already been freed here... + * Setting it to NULL may not be 100% correct, but should be safe and do the work. */ + if (GS(id->name) == ID_OB) { + ((Object *)id)->data = NULL; + } + /* 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. @@ -1853,7 +1859,6 @@ void BKE_library_make_local( #endif ((LinkNode *)it->link)->link = NULL; /* Not strictly necessary, but safer (see T49903)... */ it->link = NULL; - id->tag &= ~LIB_TAG_DOIT; } } From fc9fa07c0e177bda4c5ae2233616081ed48f2c8c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 14 Nov 2016 04:10:47 +1100 Subject: [PATCH 196/590] BMesh: BM_face_exists no longer uses return arg Just return the face or NULL, like BM_edge_exists(), Also for BM_face_exists_overlap & bm_face_exists_tri_from_loop_vert. No functional changes. Old code did some partial overlap checks where this made some sense, but it's since been removed. --- source/blender/blenkernel/intern/pbvh_bmesh.c | 17 ++++------ source/blender/bmesh/intern/bmesh_core.c | 7 ++-- source/blender/bmesh/intern/bmesh_queries.c | 32 ++++++------------- source/blender/bmesh/intern/bmesh_queries.h | 4 +-- source/blender/bmesh/operators/bmo_bridge.c | 6 ++-- .../bmesh/operators/bmo_fill_edgeloop.c | 2 +- source/blender/bmesh/operators/bmo_hull.c | 3 +- .../bmesh/operators/bmo_removedoubles.c | 2 +- .../bmesh/tools/bmesh_decimate_unsubdivide.c | 2 +- source/blender/editors/mesh/editmesh_rip.c | 2 +- source/blender/editors/mesh/editmesh_utils.c | 4 +-- source/blender/python/bmesh/bmesh_py_types.c | 5 +-- 12 files changed, 34 insertions(+), 52 deletions(-) diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 55f9f384081..a821578db1a 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -148,8 +148,7 @@ BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3]) * * Its assumed that \a l_radial_first is never forming the target face. */ -static bool bm_face_exists_tri_from_loop_vert( - BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing) +static BMFace *bm_face_exists_tri_from_loop_vert(BMLoop *l_radial_first, BMVert *v_opposite) { BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v)); if (l_radial_first->radial_next != l_radial_first) { @@ -157,12 +156,11 @@ static bool bm_face_exists_tri_from_loop_vert( do { BLI_assert(l_radial_iter->f->len == 3); if (l_radial_iter->prev->v == v_opposite) { - *r_face_existing = l_radial_iter->f; - return true; + return l_radial_iter->f; } } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first); } - return false; + return NULL; } /** @@ -519,7 +517,7 @@ static BMFace *pbvh_bmesh_face_create( PBVHNode *node = &bvh->nodes[node_index]; /* ensure we never add existing face */ - BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); + BLI_assert(!BM_face_exists(v_tri, 3)); BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); f->head.hflag = f_example->head.hflag; @@ -1313,18 +1311,17 @@ static void pbvh_bmesh_collapse_edge( * deletion as well. Prevents extraneous "flaps" from being * created. */ #if 0 - if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face))) + if (UNLIKELY(existing_face = BM_face_exists(v_tri, 3))) #else - if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face))) + if (UNLIKELY(existing_face = bm_face_exists_tri_from_loop_vert(l->next, v_conn))) #endif { - BLI_assert(existing_face); BLI_buffer_append(deleted_faces, BMFace *, existing_face); } else { BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v}; - BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); + BLI_assert(!BM_face_exists(v_tri, 3)); BMEdge *e_tri[3]; PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f); int ni = n - bvh->nodes; diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index a7e1aa7fb07..0460a33494c 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -444,13 +444,10 @@ BMFace *BM_face_create( if (create_flag & BM_CREATE_NO_DOUBLE) { /* Check if face already exists */ - const bool is_overlap = BM_face_exists(verts, len, &f); - if (is_overlap) { + f = BM_face_exists(verts, len); + if (f != NULL) { return f; } - else { - BLI_assert(f == NULL); - } } f = bm_face_create__internal(bm); diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 0287498482a..87671805ef2 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -1925,7 +1925,7 @@ BMEdge *BM_edge_find_double(BMEdge *e) * * \note there used to be a BM_face_exists_overlap function that checks for partial overlap. */ -bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) +BMFace *BM_face_exists(BMVert **varr, int len) { if (varr[0]->e) { BMEdge *e_iter, *e_first; @@ -1964,10 +1964,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) } if (i_walk == len) { - if (r_existface) { - *r_existface = l_iter_radial->f; - } - return true; + return l_iter_radial->f; } } } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial); @@ -1976,10 +1973,7 @@ bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, varr[0])) != e_first); } - if (r_existface) { - *r_existface = NULL; - } - return false; + return NULL; } @@ -2122,26 +2116,21 @@ bool BM_face_exists_multi_edge(BMEdge **earr, int len) * \note The face may contain other verts \b not in \a varr. * * \note Its possible there are more than one overlapping faces, - * in this case the first one found will be assigned to \a r_f_overlap. + * in this case the first one found will be returned. * * \param varr Array of unordered verts. * \param len \a varr array length. - * \param r_f_overlap The overlapping face to return. - * \return Success + * \return The face or NULL. */ -bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) +BMFace *BM_face_exists_overlap(BMVert **varr, const int len) { BMIter viter; BMFace *f; int i; - bool is_overlap = false; + BMFace *f_overlap = NULL; LinkNode *f_lnk = NULL; - if (r_f_overlap) { - *r_f_overlap = NULL; - } - #ifdef DEBUG /* check flag isn't already set */ for (i = 0; i < len; i++) { @@ -2155,10 +2144,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) BM_ITER_ELEM (f, &viter, varr[i], BM_FACES_OF_VERT) { if (BM_ELEM_API_FLAG_TEST(f, _FLAG_OVERLAP) == 0) { if (len <= BM_verts_in_face_count(varr, len, f)) { - if (r_f_overlap) - *r_f_overlap = f; - - is_overlap = true; + f_overlap = f; break; } @@ -2172,7 +2158,7 @@ bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) BM_ELEM_API_FLAG_DISABLE((BMFace *)f_lnk->link, _FLAG_OVERLAP); } - return is_overlap; + return f_overlap; } /** diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 10e4b9a15aa..282050bf8a0 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -135,12 +135,12 @@ BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNUL BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) ATTR_NONNULL(1); +BMFace* BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1); bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +BMFace *BM_face_exists_overlap(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT; bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index 6ef0fd6b084..61179d7be70 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -398,7 +398,8 @@ static void bridge_loop_pair( if (v_b != v_b_next) { BMVert *v_arr[4] = {v_a, v_b, v_b_next, v_a_next}; - if (BM_face_exists(v_arr, 4, &f) == false) { + f = BM_face_exists(v_arr, 4); + if (f == NULL) { /* copy if loop data if its is missing on one ring */ f = BM_face_create_verts(bm, v_arr, 4, NULL, BM_CREATE_NOP, true); @@ -411,7 +412,8 @@ static void bridge_loop_pair( } else { BMVert *v_arr[3] = {v_a, v_b, v_a_next}; - if (BM_face_exists(v_arr, 3, &f) == false) { + f = BM_face_exists(v_arr, 3); + if (f == NULL) { /* fan-fill a triangle */ f = BM_face_create_verts(bm, v_arr, 3, NULL, BM_CREATE_NOP, true); diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c index c68130bc11d..f33a60ccc5c 100644 --- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c +++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c @@ -136,7 +136,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) i++; } while ((v != f_verts[0])); - if (BM_face_exists(f_verts, i, NULL) == false) { + if (!BM_face_exists(f_verts, i)) { BMFace *f; /* don't use calc_edges option because we already have the edges */ diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index 9c41e4f2115..81ec2860cf7 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -119,7 +119,8 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles) }; BMFace *f, *example = NULL; - if (BM_face_exists(t->v, 3, &f)) { + f = BM_face_exists(t->v, 3); + if (f != NULL) { /* If the operator is run with "use_existing_faces" * disabled, but an output face in the hull is the * same as a face in the existing mesh, it should not diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index 6da591b23a0..0ad8247e539 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -160,7 +160,7 @@ finally: } if (STACK_SIZE(edges) >= 3) { - if (!BM_face_exists(verts, STACK_SIZE(edges), NULL)) { + if (!BM_face_exists(verts, STACK_SIZE(edges))) { BMFace *f_new = BM_face_create(bm, verts, edges, STACK_SIZE(edges), f, BM_CREATE_NOP); BLI_assert(f_new != f); diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c index 0fc571bc0a8..92300ae66a2 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c +++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c @@ -74,7 +74,7 @@ static bool bm_vert_dissolve_fan_test(BMVert *v) ((tot_edge == 3) && (tot_edge_boundary == 0) && (tot_edge_manifold == 3)) || ((tot_edge == 3) && (tot_edge_boundary == 2) && (tot_edge_manifold == 1))) { - if (!BM_face_exists(varr, tot_edge, NULL)) { + if (!BM_face_exists(varr, tot_edge)) { return true; } } diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index e31e4096ded..e05ce727e22 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -496,7 +496,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u } /* face should never exist */ - BLI_assert(BM_face_exists(f_verts, f_verts[3] ? 4 : 3, &f) == false); + BLI_assert(!BM_face_exists(f_verts, f_verts[3] ? 4 : 3)); f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true); diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 4fc61e0912e..438c3acdb11 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -1139,7 +1139,6 @@ BMEdge *EDBM_verts_mirror_get_edge(BMEditMesh *em, BMEdge *e) BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f) { - BMFace *f_mirr = NULL; BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len); BMLoop *l_iter, *l_first; @@ -1152,8 +1151,7 @@ BMFace *EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f) } } while ((l_iter = l_iter->next) != l_first); - BM_face_exists(v_mirr_arr, f->len, &f_mirr); - return f_mirr; + return BM_face_exists(v_mirr_arr, f->len); } void EDBM_verts_mirror_cache_clear(BMEditMesh *em, BMVert *v) diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index 1d951bae48b..b20c03bee28 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -2233,7 +2233,7 @@ static PyObject *bpy_bmfaceseq_new(BPy_BMElemSeq *self, PyObject *args) } /* check if the face exists */ - if (BM_face_exists(vert_array, vert_seq_len, NULL)) { + if (BM_face_exists(vert_array, vert_seq_len) != NULL) { PyErr_SetString(PyExc_ValueError, "faces.new(verts): face already exists"); goto cleanup; @@ -2426,7 +2426,8 @@ static PyObject *bpy_bmfaceseq_get__method(BPy_BMElemSeq *self, PyObject *args) return NULL; } - if (BM_face_exists(vert_array, vert_seq_len, &f)) { + f = BM_face_exists(vert_array, vert_seq_len); + if (f != NULL) { ret = BPy_BMFace_CreatePyObject(bm, f); } else { From 7a4a2ed5f4086b488e9bc03ab32a79f6f8322c02 Mon Sep 17 00:00:00 2001 From: Martijn Berger Date: Mon, 14 Nov 2016 09:59:30 +0100 Subject: [PATCH 197/590] intsall_deps / OSL use c++11 ABI when install_deps is asking for c++11 --- build_files/build_environment/install_deps.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 7844ff5ffda..5a02a96bdff 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -1858,6 +1858,9 @@ compile_OSL() { cmake_d="$cmake_d -D OSL_BUILD_PLUGINS=OFF" cmake_d="$cmake_d -D OSL_BUILD_TESTS=OFF" cmake_d="$cmake_d -D USE_SIMD=sse2" + if [ "$USE_CXX11" = true ]; then + cmake_d="$cmake_d -D OSL_BUILD_CPP11=1" + fi #~ cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION" From b047d79871ce7ad366b166de2a872f93508bbc9f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 14 Nov 2016 14:03:17 +0100 Subject: [PATCH 198/590] Cycles: De-duplicate image loading functions The code was templated already, so don't see big reason to have 3 versions of templated functions. It was giving some extra code to maintain and in fact already had divergency for support of huge image resolution (missing size_t cast in byte image loading). There should be no changes visible by artists. --- intern/cycles/render/image.cpp | 302 +++++++-------------------------- intern/cycles/render/image.h | 14 +- 2 files changed, 67 insertions(+), 249 deletions(-) diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 073a0aa2ac9..7465fbd43a7 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -471,48 +471,79 @@ bool ImageManager::file_load_image_generic(Image *img, ImageInput **in, int &wid return true; } -template -bool ImageManager::file_load_byte_image(Image *img, ImageDataType type, device_vector& tex_img) +template +bool ImageManager::file_load_image(Image *img, + ImageDataType type, + device_vector& tex_img) { + const StorageType alpha_one = (FileFormat == TypeDesc::UINT8)? 255 : 1; ImageInput *in = NULL; int width, height, depth, components; - - if(!file_load_image_generic(img, &in, width, height, depth, components)) + if(!file_load_image_generic(img, &in, width, height, depth, components)) { return false; - - /* read RGBA pixels */ - uchar *pixels = (uchar*)tex_img.resize(width, height, depth); + } + /* Read RGBA pixels. */ + StorageType *pixels = (StorageType*)tex_img.resize(width, height, depth); if(pixels == NULL) { return false; } bool cmyk = false; - if(in) { + StorageType *readpixels = pixels; + vector tmppixels; + if(components > 4) { + tmppixels.resize(((size_t)width)*height*components); + readpixels = &tmppixels[0]; + } if(depth <= 1) { - int scanlinesize = width*components*sizeof(uchar); - - in->read_image(TypeDesc::UINT8, - (uchar*)pixels + (((size_t)height)-1)*scanlinesize, + size_t scanlinesize = ((size_t)width)*components*sizeof(StorageType); + in->read_image(FileFormat, + (uchar*)readpixels + (height-1)*scanlinesize, AutoStride, -scanlinesize, AutoStride); } else { - in->read_image(TypeDesc::UINT8, (uchar*)pixels); + in->read_image(FileFormat, (uchar*)readpixels); + } + if(components > 4) { + size_t dimensions = ((size_t)width)*height; + for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) { + pixels[i*4+3] = tmppixels[i*components+3]; + pixels[i*4+2] = tmppixels[i*components+2]; + pixels[i*4+1] = tmppixels[i*components+1]; + pixels[i*4+0] = tmppixels[i*components+0]; + } + tmppixels.clear(); } - cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4; - in->close(); delete in; } else { - builtin_image_pixels_cb(img->filename, img->builtin_data, pixels); + if(FileFormat == TypeDesc::FLOAT) { + builtin_image_float_pixels_cb(img->filename, + img->builtin_data, + (float*)pixels); + } + else if(FileFormat == TypeDesc::UINT8) { + builtin_image_pixels_cb(img->filename, + img->builtin_data, + (uchar*)pixels); + } + else { + /* TODO(dingto): Support half for ImBuf. */ + } } - - /* Check if we actually have a byte4 slot, in case components == 1, but device - * doesn't support single channel textures. */ - if(type == IMAGE_DATA_TYPE_BYTE4) { + /* Check if we actually have a float4 slot, in case components == 1, + * but device doesn't support single channel textures. + */ + if(type == IMAGE_DATA_TYPE_FLOAT4 || + type == IMAGE_DATA_TYPE_HALF4 || + type == IMAGE_DATA_TYPE_BYTE4) + { size_t num_pixels = ((size_t)width) * height * depth; if(cmyk) { /* CMYK */ @@ -520,7 +551,7 @@ bool ImageManager::file_load_byte_image(Image *img, ImageDataType type, device_v pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255; pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255; pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255; - pixels[i*4+3] = 255; + pixels[i*4+3] = alpha_one; } } else if(components == 2) { @@ -535,7 +566,7 @@ bool ImageManager::file_load_byte_image(Image *img, ImageDataType type, device_v else if(components == 3) { /* RGB */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = 255; + pixels[i*4+3] = alpha_one; pixels[i*4+2] = pixels[i*3+2]; pixels[i*4+1] = pixels[i*3+1]; pixels[i*4+0] = pixels[i*3+0]; @@ -544,229 +575,18 @@ bool ImageManager::file_load_byte_image(Image *img, ImageDataType type, device_v else if(components == 1) { /* grayscale */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = 255; + pixels[i*4+3] = alpha_one; pixels[i*4+2] = pixels[i]; pixels[i*4+1] = pixels[i]; pixels[i*4+0] = pixels[i]; } } - if(img->use_alpha == false) { for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = 255; + pixels[i*4+3] = alpha_one; } } } - - return true; -} - -template -bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_vector& tex_img) -{ - ImageInput *in = NULL; - int width, height, depth, components; - - if(!file_load_image_generic(img, &in, width, height, depth, components)) - return false; - - /* read RGBA pixels */ - float *pixels = (float*)tex_img.resize(width, height, depth); - if(pixels == NULL) { - return false; - } - bool cmyk = false; - - if(in) { - float *readpixels = pixels; - vector tmppixels; - - if(components > 4) { - tmppixels.resize(((size_t)width)*height*components); - readpixels = &tmppixels[0]; - } - - if(depth <= 1) { - size_t scanlinesize = ((size_t)width)*components*sizeof(float); - in->read_image(TypeDesc::FLOAT, - (uchar*)readpixels + (height-1)*scanlinesize, - AutoStride, - -scanlinesize, - AutoStride); - } - else { - in->read_image(TypeDesc::FLOAT, (uchar*)readpixels); - } - - if(components > 4) { - size_t dimensions = ((size_t)width)*height; - for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) { - pixels[i*4+3] = tmppixels[i*components+3]; - pixels[i*4+2] = tmppixels[i*components+2]; - pixels[i*4+1] = tmppixels[i*components+1]; - pixels[i*4+0] = tmppixels[i*components+0]; - } - - tmppixels.clear(); - } - - cmyk = strcmp(in->format_name(), "jpeg") == 0 && components == 4; - - in->close(); - delete in; - } - else { - builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels); - } - - /* Check if we actually have a float4 slot, in case components == 1, but device - * doesn't support single channel textures. */ - if(type == IMAGE_DATA_TYPE_FLOAT4) { - size_t num_pixels = ((size_t)width) * height * depth; - if(cmyk) { - /* CMYK */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = 255; - pixels[i*4+2] = (pixels[i*4+2]*pixels[i*4+3])/255; - pixels[i*4+1] = (pixels[i*4+1]*pixels[i*4+3])/255; - pixels[i*4+0] = (pixels[i*4+0]*pixels[i*4+3])/255; - } - } - else if(components == 2) { - /* grayscale + alpha */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = pixels[i*2+1]; - pixels[i*4+2] = pixels[i*2+0]; - pixels[i*4+1] = pixels[i*2+0]; - pixels[i*4+0] = pixels[i*2+0]; - } - } - else if(components == 3) { - /* RGB */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = 1.0f; - pixels[i*4+2] = pixels[i*3+2]; - pixels[i*4+1] = pixels[i*3+1]; - pixels[i*4+0] = pixels[i*3+0]; - } - } - else if(components == 1) { - /* grayscale */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = 1.0f; - pixels[i*4+2] = pixels[i]; - pixels[i*4+1] = pixels[i]; - pixels[i*4+0] = pixels[i]; - } - } - - if(img->use_alpha == false) { - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = 1.0f; - } - } - } - - return true; -} - -template -bool ImageManager::file_load_half_image(Image *img, ImageDataType type, device_vector& tex_img) -{ - ImageInput *in = NULL; - int width, height, depth, components; - - if(!file_load_image_generic(img, &in, width, height, depth, components)) - return false; - - /* read RGBA pixels */ - half *pixels = (half*)tex_img.resize(width, height, depth); - if(pixels == NULL) { - return false; - } - - if(in) { - half *readpixels = pixels; - vector tmppixels; - - if(components > 4) { - tmppixels.resize(((size_t)width)*height*components); - readpixels = &tmppixels[0]; - } - - if(depth <= 1) { - size_t scanlinesize = ((size_t)width)*components*sizeof(half); - in->read_image(TypeDesc::HALF, - (uchar*)readpixels + (height-1)*scanlinesize, - AutoStride, - -scanlinesize, - AutoStride); - } - else { - in->read_image(TypeDesc::HALF, (uchar*)readpixels); - } - - if(components > 4) { - size_t dimensions = ((size_t)width)*height; - for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) { - pixels[i*4+3] = tmppixels[i*components+3]; - pixels[i*4+2] = tmppixels[i*components+2]; - pixels[i*4+1] = tmppixels[i*components+1]; - pixels[i*4+0] = tmppixels[i*components+0]; - } - - tmppixels.clear(); - } - - in->close(); - delete in; - } -#if 0 - /* TODO(dingto): Support half for ImBuf. */ - else { - builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels); - } -#endif - - /* Check if we actually have a half4 slot, in case components == 1, but device - * doesn't support single channel textures. */ - if(type == IMAGE_DATA_TYPE_HALF4) { - size_t num_pixels = ((size_t)width) * height * depth; - if(components == 2) { - /* grayscale + alpha */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = pixels[i*2+1]; - pixels[i*4+2] = pixels[i*2+0]; - pixels[i*4+1] = pixels[i*2+0]; - pixels[i*4+0] = pixels[i*2+0]; - } - } - else if(components == 3) { - /* RGB */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = 1.0f; - pixels[i*4+2] = pixels[i*3+2]; - pixels[i*4+1] = pixels[i*3+1]; - pixels[i*4+0] = pixels[i*3+0]; - } - } - else if(components == 1) { - /* grayscale */ - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = 1.0f; - pixels[i*4+2] = pixels[i]; - pixels[i*4+1] = pixels[i]; - pixels[i*4+0] = pixels[i]; - } - } - - if(img->use_alpha == false) { - for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { - pixels[i*4+3] = 1.0f; - } - } - } - return true; } @@ -802,7 +622,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_float_image(img, type, tex_img)) { + if(!file_load_image(img, type, tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ float *pixels = (float*)tex_img.resize(1, 1); @@ -828,7 +648,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_float_image(img, type, tex_img)) { + if(!file_load_image(img, type, tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ float *pixels = (float*)tex_img.resize(1, 1); @@ -851,7 +671,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_byte_image(img, type, tex_img)) { + if(!file_load_image(img, type, tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ uchar *pixels = (uchar*)tex_img.resize(1, 1); @@ -877,7 +697,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_byte_image(img, type, tex_img)) { + if(!file_load_image(img, type, tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ uchar *pixels = (uchar*)tex_img.resize(1, 1); @@ -900,7 +720,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_half_image(img, type, tex_img)) { + if(!file_load_image(img, type, tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ half *pixels = (half*)tex_img.resize(1, 1); @@ -926,7 +746,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_half_image(img, type, tex_img)) { + if(!file_load_image(img, type, tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ half *pixels = (half*)tex_img.resize(1, 1); diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index cca71a6bb93..1dc4bf180f8 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -109,14 +109,12 @@ private: bool file_load_image_generic(Image *img, ImageInput **in, int &width, int &height, int &depth, int &components); - template - bool file_load_byte_image(Image *img, ImageDataType type, device_vector& tex_img); - - template - bool file_load_float_image(Image *img, ImageDataType type, device_vector& tex_img); - - template - bool file_load_half_image(Image *img, ImageDataType type, device_vector& tex_img); + template + bool file_load_image(Image *img, + ImageDataType type, + device_vector& tex_img); int type_index_to_flattened_slot(int slot, ImageDataType type); int flattened_slot_to_type_index(int flat_slot, ImageDataType *type); From dc0a9e65352ff893de8e1f2e70e00636ec4492eb Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 14 Nov 2016 14:21:15 +1100 Subject: [PATCH 199/590] BMesh: remove redundant argument --- source/blender/bmesh/intern/bmesh_construct.c | 2 +- source/blender/bmesh/intern/bmesh_construct.h | 2 +- source/blender/bmesh/intern/bmesh_core.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 4d92baab6eb..132a7ccd4fa 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -626,7 +626,7 @@ void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void BM_elem_attrs_copy_ex(bm_src, bm_dst, ele_src, ele_dst, BM_ELEM_SELECT); } -void BM_elem_select_copy(BMesh *bm_dst, BMesh *UNUSED(bm_src), void *ele_dst_v, const void *ele_src_v) +void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v) { BMHeader *ele_dst = ele_dst_v; const BMHeader *ele_src = ele_src_v; diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h index 06bc5465a19..9c6483de42b 100644 --- a/source/blender/bmesh/intern/bmesh_construct.h +++ b/source/blender/bmesh/intern/bmesh_construct.h @@ -58,7 +58,7 @@ void BM_elem_attrs_copy_ex( BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v, const char hflag_mask); void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v); -void BM_elem_select_copy(BMesh *bm_dst, BMesh *bm_src, void *ele_dst_v, const void *ele_src_v); +void BM_elem_select_copy(BMesh *bm_dst, void *ele_dst_v, const void *ele_src_v); void BM_mesh_copy_init_customdata(BMesh *bm_dst, BMesh *bm_src, const struct BMAllocTemplate *allocsize); BMesh *BM_mesh_copy(BMesh *bm_old); diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 0460a33494c..c71afc7a2ab 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -2347,7 +2347,7 @@ void bmesh_vert_separate( v_new = BM_vert_create(bm, v->co, v, BM_CREATE_NOP); if (copy_select) { - BM_elem_select_copy(bm, bm, v_new, v); + BM_elem_select_copy(bm, v_new, v); } while ((e = BLI_SMALLSTACK_POP(edges))) { @@ -2606,7 +2606,7 @@ void bmesh_edge_separate( l_sep->e = e_new; if (copy_select) { - BM_elem_select_copy(bm, bm, e_new, e); + BM_elem_select_copy(bm, e_new, e); } BLI_assert(bmesh_radial_length(e->l) == radlen - 1); From 6a2b95e1cac09480cd5ce1649383f83c2e6373ff Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Nov 2016 02:41:23 +1100 Subject: [PATCH 200/590] BMesh: replace iterator with BM_face_vert_share_loop --- source/blender/bmesh/intern/bmesh_queries.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index 87671805ef2..cd7a1c365b2 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -102,17 +102,10 @@ BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v) */ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) { - BMIter liter; - BMLoop *l_iter; + BMLoop *l_iter = BM_face_vert_share_loop(f, v); BLI_assert(BM_edge_exists(v_prev, v) != NULL); - BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) { - if (l_iter->f == f) { - break; - } - } - if (l_iter) { if (l_iter->prev->v == v_prev) { return l_iter->next; @@ -149,7 +142,6 @@ BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) * The faces loop direction is ignored. * */ - BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) { #if 0 /* works but slow */ @@ -178,9 +170,6 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) return l->next->next; } } - - - #endif } From d3919c22b04e7e93ded2c45cdc924897ebd4631a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Nov 2016 03:26:19 +1100 Subject: [PATCH 201/590] BMesh: fix edge-rotation selection state bug Failed edge rotation could leave unselected edge between selected faces, also report warning when edges fail to be rotated. --- source/blender/editors/mesh/editmesh_tools.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 7e31deba2c7..c57b0215d46 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -1561,6 +1561,18 @@ static int edbm_edge_rotate_selected_exec(bContext *C, wmOperator *op) /* edges may rotate into hidden vertices, if this does _not_ run we get an ilogical state */ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, true); BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); + + const int tot_rotate = BMO_slot_buffer_count(bmop.slots_out, "edges.out"); + const int tot_failed = tot - tot_rotate; + if (tot_failed != 0) { + /* If some edges fail to rotate, we need to re-select them, + * otherwise we can end up with invalid selection + * (unselected edge between 2 selected faces). */ + BM_mesh_elem_hflag_enable_test(em->bm, BM_EDGE, BM_ELEM_SELECT, true, false, BM_ELEM_TAG); + + BKE_reportf(op->reports, RPT_WARNING, "Unable to rotate %d edge(s)", tot_failed); + } + EDBM_selectmode_flush(em); if (!EDBM_op_finish(em, &bmop, op, true)) { From 77ba1ed5db4754af6788e5ac4e3110d4b81cad0e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Nov 2016 03:57:44 +1100 Subject: [PATCH 202/590] BMesh: fix edge-rotate with w/ flipped faces Edge-rotate would randomly flip one of the faces to match the other. Also maintain active-face when rotating the edge. --- source/blender/bmesh/intern/bmesh_mods.c | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index bd2bc54d85f..03165beb329 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -979,6 +979,7 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f BMLoop *l1, *l2; BMFace *f; BMEdge *e_new = NULL; + char f_active_prev = 0; char f_hflag_prev_1; char f_hflag_prev_2; @@ -1029,6 +1030,16 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f f_hflag_prev_1 = l1->f->head.hflag; f_hflag_prev_2 = l2->f->head.hflag; + /* maintain active face */ + if (bm->act_face == l1->f) { + f_active_prev = 1; + } + else if (bm->act_face == l2->f) { + f_active_prev = 2; + } + + const bool is_flipped = !BM_edge_is_contiguous(e); + /* don't delete the edge, manually remove the edge after so we can copy its attributes */ f = BM_faces_join_pair(bm, BM_face_edge_share_loop(l1->f, e), BM_face_edge_share_loop(l2->f, e), true); @@ -1050,6 +1061,22 @@ BMEdge *BM_edge_rotate(BMesh *bm, BMEdge *e, const bool ccw, const short check_f if (BM_edge_face_pair(e_new, &fa, &fb)) { fa->head.hflag = f_hflag_prev_1; fb->head.hflag = f_hflag_prev_2; + + if (f_active_prev == 1) { + bm->act_face = fa; + } + else if (f_active_prev == 2) { + bm->act_face = fb; + } + + if (is_flipped) { + BM_face_normal_flip(bm, fb); + + if (ccw) { + /* needed otherwise ccw toggles direction */ + e_new->l = e_new->l->radial_next; + } + } } } else { From e6ad6ff082ce301caae12f3f73a1bdfb379a1561 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Nov 2016 06:50:33 +1100 Subject: [PATCH 203/590] BMesh: minor improvement to BM_vert_face_check No need to perform edge-of-vert then loop-of-edge check. Any vertex that has an edge with a face will be connected to a face. --- source/blender/bmesh/intern/bmesh_queries.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index cd7a1c365b2..de8b994ba4c 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -869,7 +869,16 @@ int BM_vert_face_count_ex(const BMVert *v, int count_max) */ bool BM_vert_face_check(BMVert *v) { - return v->e && (bmesh_disk_faceedge_find_first(v->e, v) != NULL); + if (v->e != NULL) { + BMEdge *e_iter, *e_first; + e_first = e_iter = v->e; + do { + if (e_iter->l != NULL) { + return true; + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first); + } + return false; } /** From a3b61f0639eb7f5c533267809f7b232b522ebf16 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Nov 2016 07:30:18 +1100 Subject: [PATCH 204/590] BMesh: use const for BM_vert_face_check --- source/blender/bmesh/intern/bmesh_queries.c | 4 ++-- source/blender/bmesh/intern/bmesh_queries.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index de8b994ba4c..c7ba04ba7fd 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -867,10 +867,10 @@ int BM_vert_face_count_ex(const BMVert *v, int count_max) * * same as ``BM_vert_face_count(v) != 0`` or ``BM_vert_find_first_loop(v) == NULL`` */ -bool BM_vert_face_check(BMVert *v) +bool BM_vert_face_check(const BMVert *v) { if (v->e != NULL) { - BMEdge *e_iter, *e_first; + const BMEdge *e_iter, *e_first; e_first = e_iter = v->e; do { if (e_iter->l != NULL) { diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index 282050bf8a0..a6a37767ee9 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -86,7 +86,7 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT AT bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_edge_pair(BMVert *v, BMEdge **r_e_a, BMEdge **r_e_b); -bool BM_vert_face_check(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +bool BM_vert_face_check(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_vert_is_wire(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); From d9597ce3ba777a6a13d55aaab6b94ed277843ccc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Nov 2016 07:30:36 +1100 Subject: [PATCH 205/590] BMesh: avoid extra calls per faces-of-vert iterator - `bmesh_radial_faceloop_find_first` & `bmesh_disk_faceedge_find_first` can be replaced with a single call to a new function: `bmesh_disk_faceloop_find_first` - `bmesh_disk_faceedge_find_first` called `bmesh_radial_facevert_check` which isn't needed, since either the current or next loop in the cycle is attached to the edge we're looking for. --- source/blender/bmesh/intern/bmesh_iterators.c | 8 +++---- source/blender/bmesh/intern/bmesh_structure.c | 23 +++++++++++++++---- source/blender/bmesh/intern/bmesh_structure.h | 1 + 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c index 961b10d848a..96154f051f9 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.c +++ b/source/blender/bmesh/intern/bmesh_iterators.c @@ -485,9 +485,9 @@ void bmiter__face_of_vert_begin(struct BMIter__face_of_vert *iter) { ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata); if (((BMIter *)iter)->count) { - iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata); + iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata); + iter->e_first = iter->l_first->e; iter->e_next = iter->e_first; - iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata); iter->l_next = iter->l_first; } else { @@ -526,9 +526,9 @@ void bmiter__loop_of_vert_begin(struct BMIter__loop_of_vert *iter) { ((BMIter *)iter)->count = bmesh_disk_facevert_count(iter->vdata); if (((BMIter *)iter)->count) { - iter->e_first = bmesh_disk_faceedge_find_first(iter->vdata->e, iter->vdata); + iter->l_first = bmesh_disk_faceloop_find_first(iter->vdata->e, iter->vdata); + iter->e_first = iter->l_first->e; iter->e_next = iter->e_first; - iter->l_first = bmesh_radial_faceloop_find_first(iter->e_first->l, iter->vdata); iter->l_next = iter->l_first; } else { diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c index 6052de421dd..8e484841568 100644 --- a/source/blender/bmesh/intern/bmesh_structure.c +++ b/source/blender/bmesh/intern/bmesh_structure.c @@ -338,13 +338,28 @@ int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) */ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) { - const BMEdge *e_find = e; + const BMEdge *e_iter = e; do { - if (e_find->l && bmesh_radial_facevert_check(e_find->l, v)) { - return (BMEdge *)e_find; + if (e_iter->l != NULL) { + return (BMEdge *)((e_iter->l->v == v) ? e_iter : e_iter->l->next->e); } - } while ((e_find = bmesh_disk_edge_next(e_find, v)) != e); + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e); + return NULL; +} +/** + * Special case for BM_LOOPS_OF_VERT & BM_FACES_OF_VERT, avoids 2x calls. + * + * The returned BMLoop.e matches the result of #bmesh_disk_faceedge_find_first + */ +BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) +{ + const BMEdge *e_iter = e; + do { + if (e_iter->l != NULL) { + return (e_iter->l->v == v) ? e_iter->l : e_iter->l->next; + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e); return NULL; } diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h index 679e7a269b3..0efb25da37c 100644 --- a/source/blender/bmesh/intern/bmesh_structure.h +++ b/source/blender/bmesh/intern/bmesh_structure.h @@ -52,6 +52,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v) ATTR_W int bmesh_disk_facevert_count_ex(const BMVert *v, const int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); int bmesh_disk_facevert_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +BMLoop *bmesh_disk_faceloop_find_first(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* RADIAL CYCLE MANAGMENT */ From c418ef48cb1ae1c9fc3748e32b43cfa5a7cadd00 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Nov 2016 07:55:55 +1100 Subject: [PATCH 206/590] BMesh: match BM_vert_find_first_loop with iterator logic Use changes from previous commit for BM_vert_find_first_loop. --- source/blender/bmesh/intern/bmesh_queries.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c index c7ba04ba7fd..7ca5640578a 100644 --- a/source/blender/bmesh/intern/bmesh_queries.c +++ b/source/blender/bmesh/intern/bmesh_queries.c @@ -381,17 +381,7 @@ BMFace *BM_vert_pair_share_face_by_angle( */ BMLoop *BM_vert_find_first_loop(BMVert *v) { - BMEdge *e; - - if (!v->e) - return NULL; - - e = bmesh_disk_faceedge_find_first(v->e, v); - - if (!e) - return NULL; - - return bmesh_radial_faceloop_find_first(e->l, v); + return v->e ? bmesh_disk_faceloop_find_first(v->e, v) : NULL; } /** From 46b5cdaa4d1b9d78bbbd078e98f64de1e6c288a8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 15 Nov 2016 12:39:33 +1100 Subject: [PATCH 207/590] BMesh: remove redundant link-list manipulation No need to track previous edge in vert-separate cleanup --- source/blender/bmesh/intern/bmesh_core.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index c71afc7a2ab..0cd91107171 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -2405,18 +2405,13 @@ static void bmesh_vert_separate__cleanup(BMesh *bm, LinkNode *edges_separate) do { BMEdge *e_orig = n_orig->link; LinkNode *n_step = n_orig->next; - LinkNode *n_prev = n_orig; do { BMEdge *e = n_step->link; BLI_assert(e != e_orig); if ((e->v1 == e_orig->v1) && (e->v2 == e_orig->v2)) { BM_edge_splice(bm, e_orig, e); - n_prev->next = n_step->next; - n_step = n_prev; } - } while ((void) - (n_prev = n_step), - (n_step = n_step->next)); + } while ((n_step = n_step->next)); } while ((n_orig = n_orig->next) && n_orig->next); } while ((edges_separate = edges_separate->next)); From 4ee08e9533593b0e7cf7f50b3c4c61eb5598c13e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 15 Nov 2016 12:16:26 +0100 Subject: [PATCH 208/590] Atomics: Make naming more obvious about which value is being returned --- intern/atomic/atomic_ops.h | 18 ++++++------- intern/atomic/intern/atomic_ops_ext.h | 26 +++++++++---------- intern/atomic/intern/atomic_ops_msvc.h | 8 +++--- intern/atomic/intern/atomic_ops_unix.h | 16 ++++++------ intern/cycles/kernel/kernel_passes.h | 16 ++++++------ intern/cycles/util/util_atomic.h | 2 +- intern/cycles/util/util_stats.h | 4 +-- .../intern/mallocn_guarded_impl.c | 12 ++++----- .../intern/mallocn_lockfree_impl.c | 24 ++++++++--------- source/blender/blenkernel/intern/depsgraph.c | 2 +- .../blender/blenkernel/intern/dynamicpaint.c | 4 +-- .../blender/blenkernel/intern/mesh_evaluate.c | 2 +- source/blender/blenkernel/intern/pbvh.c | 2 +- source/blender/blenlib/intern/task.c | 8 +++--- .../compositor/intern/COM_ExecutionGroup.cpp | 2 +- .../blender/depsgraph/intern/eval/deg_eval.cc | 4 +-- source/blender/editors/space_file/filelist.c | 2 +- .../gameengine/VideoTexture/VideoDeckLink.cpp | 4 +-- 18 files changed, 78 insertions(+), 78 deletions(-) diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h index f78eab7951f..c3926fdd68f 100644 --- a/intern/atomic/atomic_ops.h +++ b/intern/atomic/atomic_ops.h @@ -77,13 +77,13 @@ /* Function prototypes. */ #if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8) -ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x); -ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x); +ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x); +ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x); ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new); #endif -ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x); -ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x); +ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x); +ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x); ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _new); ATOMIC_INLINE uint32_t atomic_fetch_and_add_uint32(uint32_t *p, uint32_t x); @@ -93,18 +93,18 @@ ATOMIC_INLINE uint32_t atomic_fetch_and_and_uint32(uint32_t *p, uint32_t x); ATOMIC_INLINE uint8_t atomic_fetch_and_or_uint8(uint8_t *p, uint8_t b); ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b); -ATOMIC_INLINE size_t atomic_add_z(size_t *p, size_t x); -ATOMIC_INLINE size_t atomic_sub_z(size_t *p, size_t x); +ATOMIC_INLINE size_t atomic_add_and_fetch_z(size_t *p, size_t x); +ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x); ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new); -ATOMIC_INLINE unsigned atomic_add_u(unsigned *p, unsigned x); -ATOMIC_INLINE unsigned atomic_sub_u(unsigned *p, unsigned x); +ATOMIC_INLINE unsigned atomic_add_and_fetch_u(unsigned *p, unsigned x); +ATOMIC_INLINE unsigned atomic_sub_and_fetch_u(unsigned *p, unsigned x); ATOMIC_INLINE unsigned atomic_cas_u(unsigned *v, unsigned old, unsigned _new); /* WARNING! Float 'atomics' are really faked ones, those are actually closer to some kind of spinlock-sync'ed operation, * which means they are only efficient if collisions are highly unlikely (i.e. if probability of two threads * working on the same pointer at the same time is very low). */ -ATOMIC_INLINE float atomic_add_fl(float *p, const float x); +ATOMIC_INLINE float atomic_add_and_fetch_fl(float *p, const float x); /******************************************************************************/ /* Include system-dependent implementations. */ diff --git a/intern/atomic/intern/atomic_ops_ext.h b/intern/atomic/intern/atomic_ops_ext.h index 4065299d2ea..74ed327c1b7 100644 --- a/intern/atomic/intern/atomic_ops_ext.h +++ b/intern/atomic/intern/atomic_ops_ext.h @@ -56,25 +56,25 @@ /******************************************************************************/ /* size_t operations. */ -ATOMIC_INLINE size_t atomic_add_z(size_t *p, size_t x) +ATOMIC_INLINE size_t atomic_add_and_fetch_z(size_t *p, size_t x) { assert(sizeof(size_t) == LG_SIZEOF_PTR); #if (LG_SIZEOF_PTR == 8) - return (size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)x); + return (size_t)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_PTR == 4) - return (size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)x); + return (size_t)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)x); #endif } -ATOMIC_INLINE size_t atomic_sub_z(size_t *p, size_t x) +ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x) { assert(sizeof(size_t) == LG_SIZEOF_PTR); #if (LG_SIZEOF_PTR == 8) - return (size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x)); + return (size_t)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)-((int64_t)x)); #elif (LG_SIZEOF_PTR == 4) - return (size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x)); + return (size_t)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)-((int32_t)x)); #endif } @@ -91,25 +91,25 @@ ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new) /******************************************************************************/ /* unsigned operations. */ -ATOMIC_INLINE unsigned atomic_add_u(unsigned *p, unsigned x) +ATOMIC_INLINE unsigned atomic_add_and_fetch_u(unsigned *p, unsigned x) { assert(sizeof(unsigned) == LG_SIZEOF_INT); #if (LG_SIZEOF_INT == 8) - return (unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)x); + return (unsigned)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)x); #elif (LG_SIZEOF_INT == 4) - return (unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)x); + return (unsigned)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)x); #endif } -ATOMIC_INLINE unsigned atomic_sub_u(unsigned *p, unsigned x) +ATOMIC_INLINE unsigned atomic_sub_and_fetch_u(unsigned *p, unsigned x) { assert(sizeof(unsigned) == LG_SIZEOF_INT); #if (LG_SIZEOF_INT == 8) - return (unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x)); + return (unsigned)atomic_add_and_fetch_uint64((uint64_t *)p, (uint64_t)-((int64_t)x)); #elif (LG_SIZEOF_INT == 4) - return (unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x)); + return (unsigned)atomic_add_and_fetch_uint32((uint32_t *)p, (uint32_t)-((int32_t)x)); #endif } @@ -127,7 +127,7 @@ ATOMIC_INLINE unsigned atomic_cas_u(unsigned *v, unsigned old, unsigned _new) /******************************************************************************/ /* float operations. */ -ATOMIC_INLINE float atomic_add_fl(float *p, const float x) +ATOMIC_INLINE float atomic_add_and_fetch_fl(float *p, const float x) { assert(sizeof(float) == sizeof(uint32_t)); diff --git a/intern/atomic/intern/atomic_ops_msvc.h b/intern/atomic/intern/atomic_ops_msvc.h index 3461719a4e7..e7aae4a74a0 100644 --- a/intern/atomic/intern/atomic_ops_msvc.h +++ b/intern/atomic/intern/atomic_ops_msvc.h @@ -43,12 +43,12 @@ /******************************************************************************/ /* 64-bit operations. */ #if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8) -ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) +ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x) { return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x) + x; } -ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x) +ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x) { return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x)) - x; } @@ -61,12 +61,12 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne /******************************************************************************/ /* 32-bit operations. */ -ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x) +ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x) { return InterlockedExchangeAdd(p, x) + x; } -ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x) +ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x) { return InterlockedExchangeAdd(p, -((int32_t)x)) - x; } diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h index e63f09c76c5..3d00f91be25 100644 --- a/intern/atomic/intern/atomic_ops_unix.h +++ b/intern/atomic/intern/atomic_ops_unix.h @@ -58,12 +58,12 @@ /* 64-bit operations. */ #if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8) # if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8)) -ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) +ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x) { return __sync_add_and_fetch(p, x); } -ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x) +ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x) { return __sync_sub_and_fetch(p, x); } @@ -73,7 +73,7 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne return __sync_val_compare_and_swap(v, old, _new); } # elif (defined(__amd64__) || defined(__x86_64__)) -ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) +ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x) { asm volatile ( "lock; xaddq %0, %1;" @@ -83,7 +83,7 @@ ATOMIC_INLINE uint64_t atomic_add_uint64(uint64_t *p, uint64_t x) return x; } -ATOMIC_INLINE uint64_t atomic_sub_uint64(uint64_t *p, uint64_t x) +ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x) { x = (uint64_t)(-(int64_t)x); asm volatile ( @@ -112,12 +112,12 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne /******************************************************************************/ /* 32-bit operations. */ #if (defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4)) -ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x) +ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x) { return __sync_add_and_fetch(p, x); } -ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x) +ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x) { return __sync_sub_and_fetch(p, x); } @@ -127,7 +127,7 @@ ATOMIC_INLINE uint32_t atomic_cas_uint32(uint32_t *v, uint32_t old, uint32_t _ne return __sync_val_compare_and_swap(v, old, _new); } #elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__)) -ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x) +ATOMIC_INLINE uint32_t atomic_add_and_fetch_uint32(uint32_t *p, uint32_t x) { uint32_t ret = x; asm volatile ( @@ -138,7 +138,7 @@ ATOMIC_INLINE uint32_t atomic_add_uint32(uint32_t *p, uint32_t x) return ret+x; } -ATOMIC_INLINE uint32_t atomic_sub_uint32(uint32_t *p, uint32_t x) +ATOMIC_INLINE uint32_t atomic_sub_and_fetch_uint32(uint32_t *p, uint32_t x) { ret = (uint32_t)(-(int32_t)x); asm volatile ( diff --git a/intern/cycles/kernel/kernel_passes.h b/intern/cycles/kernel/kernel_passes.h index 20cf3fa931b..7aec47e4957 100644 --- a/intern/cycles/kernel/kernel_passes.h +++ b/intern/cycles/kernel/kernel_passes.h @@ -20,7 +20,7 @@ ccl_device_inline void kernel_write_pass_float(ccl_global float *buffer, int sam { ccl_global float *buf = buffer; #if defined(__SPLIT_KERNEL__) && defined(__WORK_STEALING__) - atomic_add_float(buf, value); + atomic_add_and_fetch_float(buf, value); #else *buf = (sample == 0)? value: *buf + value; #endif // __SPLIT_KERNEL__ && __WORK_STEALING__ @@ -33,9 +33,9 @@ ccl_device_inline void kernel_write_pass_float3(ccl_global float *buffer, int sa ccl_global float *buf_y = buffer + 1; ccl_global float *buf_z = buffer + 2; - atomic_add_float(buf_x, value.x); - atomic_add_float(buf_y, value.y); - atomic_add_float(buf_z, value.z); + atomic_add_and_fetch_float(buf_x, value.x); + atomic_add_and_fetch_float(buf_y, value.y); + atomic_add_and_fetch_float(buf_z, value.z); #else ccl_global float3 *buf = (ccl_global float3*)buffer; *buf = (sample == 0)? value: *buf + value; @@ -50,10 +50,10 @@ ccl_device_inline void kernel_write_pass_float4(ccl_global float *buffer, int sa ccl_global float *buf_z = buffer + 2; ccl_global float *buf_w = buffer + 3; - atomic_add_float(buf_x, value.x); - atomic_add_float(buf_y, value.y); - atomic_add_float(buf_z, value.z); - atomic_add_float(buf_w, value.w); + atomic_add_and_fetch_float(buf_x, value.x); + atomic_add_and_fetch_float(buf_y, value.y); + atomic_add_and_fetch_float(buf_z, value.z); + atomic_add_and_fetch_float(buf_w, value.w); #else ccl_global float4 *buf = (ccl_global float4*)buffer; *buf = (sample == 0)? value: *buf + value; diff --git a/intern/cycles/util/util_atomic.h b/intern/cycles/util/util_atomic.h index 1d1e2963348..433e41fbbb6 100644 --- a/intern/cycles/util/util_atomic.h +++ b/intern/cycles/util/util_atomic.h @@ -39,7 +39,7 @@ ATOMIC_INLINE void atomic_update_max_z(size_t *maximum_value, size_t value) /* Float atomics implementation credits: * http://suhorukov.blogspot.in/2011/12/opencl-11-atomic-operations-on-floating.html */ -ccl_device_inline void atomic_add_float(volatile ccl_global float *source, +ccl_device_inline void atomic_add_and_fetch_float(volatile ccl_global float *source, const float operand) { union { diff --git a/intern/cycles/util/util_stats.h b/intern/cycles/util/util_stats.h index b970b017270..c21a8488c81 100644 --- a/intern/cycles/util/util_stats.h +++ b/intern/cycles/util/util_stats.h @@ -29,13 +29,13 @@ public: explicit Stats(static_init_t) {} void mem_alloc(size_t size) { - atomic_add_z(&mem_used, size); + atomic_add_and_fetch_z(&mem_used, size); atomic_update_max_z(&mem_peak, mem_used); } void mem_free(size_t size) { assert(mem_used >= size); - atomic_sub_z(&mem_used, size); + atomic_sub_and_fetch_z(&mem_used, size); } size_t mem_used; diff --git a/intern/guardedalloc/intern/mallocn_guarded_impl.c b/intern/guardedalloc/intern/mallocn_guarded_impl.c index 1933e9d3ee3..76b7e072321 100644 --- a/intern/guardedalloc/intern/mallocn_guarded_impl.c +++ b/intern/guardedalloc/intern/mallocn_guarded_impl.c @@ -505,8 +505,8 @@ static void make_memhead_header(MemHead *memh, size_t len, const char *str) memt = (MemTail *)(((char *) memh) + sizeof(MemHead) + len); memt->tag3 = MEMTAG3; - atomic_add_u(&totblock, 1); - atomic_add_z(&mem_in_use, len); + atomic_add_and_fetch_u(&totblock, 1); + atomic_add_and_fetch_z(&mem_in_use, len); mem_lock_thread(); addtail(membase, &memh->next); @@ -638,7 +638,7 @@ void *MEM_guarded_mapallocN(size_t len, const char *str) if (memh != (MemHead *)-1) { make_memhead_header(memh, len, str); memh->mmap = 1; - atomic_add_z(&mmap_in_use, len); + atomic_add_and_fetch_z(&mmap_in_use, len); mem_lock_thread(); peak_mem = mmap_in_use > peak_mem ? mmap_in_use : peak_mem; mem_unlock_thread(); @@ -1007,8 +1007,8 @@ static void rem_memblock(MemHead *memh) } mem_unlock_thread(); - atomic_sub_u(&totblock, 1); - atomic_sub_z(&mem_in_use, memh->len); + atomic_sub_and_fetch_u(&totblock, 1); + atomic_sub_and_fetch_z(&mem_in_use, memh->len); #ifdef DEBUG_MEMDUPLINAME if (memh->need_free_name) @@ -1016,7 +1016,7 @@ static void rem_memblock(MemHead *memh) #endif if (memh->mmap) { - atomic_sub_z(&mmap_in_use, memh->len); + atomic_sub_and_fetch_z(&mmap_in_use, memh->len); #if defined(WIN32) /* our windows mmap implementation is not thread safe */ mem_lock_thread(); diff --git a/intern/guardedalloc/intern/mallocn_lockfree_impl.c b/intern/guardedalloc/intern/mallocn_lockfree_impl.c index a80d67c3e80..ce8a5b29ece 100644 --- a/intern/guardedalloc/intern/mallocn_lockfree_impl.c +++ b/intern/guardedalloc/intern/mallocn_lockfree_impl.c @@ -142,11 +142,11 @@ void MEM_lockfree_freeN(void *vmemh) return; } - atomic_sub_u(&totblock, 1); - atomic_sub_z(&mem_in_use, len); + atomic_sub_and_fetch_u(&totblock, 1); + atomic_sub_and_fetch_z(&mem_in_use, len); if (MEMHEAD_IS_MMAP(memh)) { - atomic_sub_z(&mmap_in_use, len); + atomic_sub_and_fetch_z(&mmap_in_use, len); #if defined(WIN32) /* our windows mmap implementation is not thread safe */ mem_lock_thread(); @@ -287,8 +287,8 @@ void *MEM_lockfree_callocN(size_t len, const char *str) if (LIKELY(memh)) { memh->len = len; - atomic_add_u(&totblock, 1); - atomic_add_z(&mem_in_use, len); + atomic_add_and_fetch_u(&totblock, 1); + atomic_add_and_fetch_z(&mem_in_use, len); update_maximum(&peak_mem, mem_in_use); return PTR_FROM_MEMHEAD(memh); @@ -312,8 +312,8 @@ void *MEM_lockfree_mallocN(size_t len, const char *str) } memh->len = len; - atomic_add_u(&totblock, 1); - atomic_add_z(&mem_in_use, len); + atomic_add_and_fetch_u(&totblock, 1); + atomic_add_and_fetch_z(&mem_in_use, len); update_maximum(&peak_mem, mem_in_use); return PTR_FROM_MEMHEAD(memh); @@ -361,8 +361,8 @@ void *MEM_lockfree_mallocN_aligned(size_t len, size_t alignment, const char *str memh->len = len | (size_t) MEMHEAD_ALIGN_FLAG; memh->alignment = (short) alignment; - atomic_add_u(&totblock, 1); - atomic_add_z(&mem_in_use, len); + atomic_add_and_fetch_u(&totblock, 1); + atomic_add_and_fetch_z(&mem_in_use, len); update_maximum(&peak_mem, mem_in_use); return PTR_FROM_MEMHEAD(memh); @@ -396,9 +396,9 @@ void *MEM_lockfree_mapallocN(size_t len, const char *str) if (memh != (MemHead *)-1) { memh->len = len | (size_t) MEMHEAD_MMAP_FLAG; - atomic_add_u(&totblock, 1); - atomic_add_z(&mem_in_use, len); - atomic_add_z(&mmap_in_use, len); + atomic_add_and_fetch_u(&totblock, 1); + atomic_add_and_fetch_z(&mem_in_use, len); + atomic_add_and_fetch_z(&mmap_in_use, len); update_maximum(&peak_mem, mem_in_use); update_maximum(&peak_mem, mmap_in_use); diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 02ae123a71e..50f8423bbff 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -3284,7 +3284,7 @@ void DAG_threaded_update_handle_node_updated(void *node_v, for (itA = node->child; itA; itA = itA->next) { DagNode *child_node = itA->node; if (child_node != node) { - atomic_sub_uint32(&child_node->num_pending_parents, 1); + atomic_sub_and_fetch_uint32(&child_node->num_pending_parents, 1); if (child_node->num_pending_parents == 0) { bool need_schedule; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index c7399047ed5..66070923153 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2264,7 +2264,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour). */ tPoint->neighbour_pixel = ind - 1; - atomic_add_uint32(&tPoint->neighbour_pixel, 1); + atomic_add_and_fetch_uint32(&tPoint->neighbour_pixel, 1); tPoint->tri_index = i; /* Now calculate pixel data for this pixel as it was on polygon surface */ @@ -2289,7 +2289,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in /* Increase the final number of active surface points if relevant. */ if (tPoint->tri_index != -1) - atomic_add_uint32(active_points, 1); + atomic_add_and_fetch_uint32(active_points, 1); } } diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 016c9c863f0..a3fe73e4b11 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -238,7 +238,7 @@ static void mesh_calc_normals_poly_accum_task_cb(void *userdata, const int pidx) /* accumulate */ for (int k = 3; k--; ) { - atomic_add_fl(&vnors[ml[i].v][k], pnor[k] * fac); + atomic_add_and_fetch_fl(&vnors[ml[i].v][k], pnor[k] * fac); } prev_edge = cur_edge; } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index ff69f381b06..4fe4d6e75a6 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -977,7 +977,7 @@ static void pbvh_update_normals_accum_task_cb(void *userdata, const int n) * Not exact equivalent though, since atomicity is only ensured for one component * of the vector at a time, but here it shall not make any sensible difference. */ for (int k = 3; k--; ) { - atomic_add_fl(&vnors[v][k], fn[k]); + atomic_add_and_fetch_fl(&vnors[v][k], fn[k]); } } } diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index 436cd2b8fde..fc2d9674c2f 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -237,7 +237,7 @@ static void task_pool_num_decrease(TaskPool *pool, size_t done) BLI_assert(pool->num >= done); pool->num -= done; - atomic_sub_z(&pool->currently_running_tasks, done); + atomic_sub_and_fetch_z(&pool->currently_running_tasks, done); pool->done += done; if (pool->num == 0) @@ -292,7 +292,7 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task continue; } - if (atomic_add_z(&pool->currently_running_tasks, 1) <= pool->num_threads || + if (atomic_add_and_fetch_z(&pool->currently_running_tasks, 1) <= pool->num_threads || pool->num_threads == 0) { *task = current_task; @@ -301,7 +301,7 @@ static bool task_scheduler_thread_wait_pop(TaskScheduler *scheduler, Task **task break; } else { - atomic_sub_z(&pool->currently_running_tasks, 1); + atomic_sub_and_fetch_z(&pool->currently_running_tasks, 1); } } if (!found_task) @@ -669,7 +669,7 @@ void BLI_task_pool_work_and_wait(TaskPool *pool) /* if found task, do it, otherwise wait until other tasks are done */ if (found_task) { /* run task */ - atomic_add_z(&pool->currently_running_tasks, 1); + atomic_add_and_fetch_z(&pool->currently_running_tasks, 1); work_task->run(pool, work_task->taskdata, 0); /* delete task */ diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cpp index e5c2b8ace4e..9a47c6b2438 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cpp @@ -383,7 +383,7 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED; - atomic_add_u(&this->m_chunksFinished, 1); + atomic_add_and_fetch_u(&this->m_chunksFinished, 1); if (memoryBuffers) { for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) { MemoryBuffer *buffer = memoryBuffers[index]; diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index c3fd202d832..e926f83bcbe 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -152,7 +152,7 @@ static void deg_task_run_func(TaskPool *pool, } if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) { BLI_assert(child->num_links_pending > 0); - atomic_sub_uint32(&child->num_links_pending, 1); + atomic_sub_and_fetch_uint32(&child->num_links_pending, 1); } if (child->num_links_pending == 0) { bool is_scheduled = atomic_fetch_and_or_uint8( @@ -287,7 +287,7 @@ static void schedule_node(TaskPool *pool, Depsgraph *graph, unsigned int layers, { if (dec_parents) { BLI_assert(node->num_links_pending > 0); - atomic_sub_uint32(&node->num_links_pending, 1); + atomic_sub_and_fetch_uint32(&node->num_links_pending, 1); } if (node->num_links_pending == 0) { diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 6af36ea6778..83469a48165 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -2510,7 +2510,7 @@ static void filelist_readjob_do( * Using an atomic operation to avoid having to lock thread... * Note that we do not really need this here currently, since there is a single listing thread, but better * remain consistent about threading! */ - *((uint32_t *)entry->uuid) = atomic_add_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1); + *((uint32_t *)entry->uuid) = atomic_add_and_fetch_uint32((uint32_t *)filelist->filelist_intern.curr_uuid, 1); /* Only thing we change in direntry here, so we need to free it first. */ MEM_freeN(entry->relpath); diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp index 4f5e34896fc..c588a4b33cf 100644 --- a/source/gameengine/VideoTexture/VideoDeckLink.cpp +++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp @@ -544,12 +544,12 @@ HRESULT STDMETHODCALLTYPE PinnedMemoryAllocator::QueryInterface(REFIID /*iid*/, ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::AddRef(void) { - return atomic_add_uint32(&mRefCount, 1U); + return atomic_add_and_fetch_uint32(&mRefCount, 1U); } ULONG STDMETHODCALLTYPE PinnedMemoryAllocator::Release(void) { - uint32_t newCount = atomic_sub_uint32(&mRefCount, 1U); + uint32_t newCount = atomic_sub_and_fetch_uint32(&mRefCount, 1U); if (newCount == 0) delete this; return (ULONG)newCount; From a284d040939408a07def751db7d255e3a26e756b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 15 Nov 2016 13:41:08 +0100 Subject: [PATCH 209/590] Atomics: Add some extra utility functions Also fixed semantic of fetch-and-add in assembler implementation, it seemed to not match the naming. --- intern/atomic/atomic_ops.h | 6 ++++ intern/atomic/intern/atomic_ops_ext.h | 44 ++++++++++++++++++++++++++ intern/atomic/intern/atomic_ops_msvc.h | 10 ++++++ intern/atomic/intern/atomic_ops_unix.h | 24 ++++++++++++-- 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/intern/atomic/atomic_ops.h b/intern/atomic/atomic_ops.h index c3926fdd68f..1107deddf94 100644 --- a/intern/atomic/atomic_ops.h +++ b/intern/atomic/atomic_ops.h @@ -79,6 +79,8 @@ #if (LG_SIZEOF_PTR == 8 || LG_SIZEOF_INT == 8) ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x); ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x); +ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x); +ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x); ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new); #endif @@ -95,10 +97,14 @@ ATOMIC_INLINE uint8_t atomic_fetch_and_and_uint8(uint8_t *p, uint8_t b); ATOMIC_INLINE size_t atomic_add_and_fetch_z(size_t *p, size_t x); ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x); +ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x); +ATOMIC_INLINE size_t atomic_fetch_and_sub_z(size_t *p, size_t x); ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new); ATOMIC_INLINE unsigned atomic_add_and_fetch_u(unsigned *p, unsigned x); ATOMIC_INLINE unsigned atomic_sub_and_fetch_u(unsigned *p, unsigned x); +ATOMIC_INLINE unsigned atomic_fetch_and_add_u(unsigned *p, unsigned x); +ATOMIC_INLINE unsigned atomic_fetch_and_sub_u(unsigned *p, unsigned x); ATOMIC_INLINE unsigned atomic_cas_u(unsigned *v, unsigned old, unsigned _new); /* WARNING! Float 'atomics' are really faked ones, those are actually closer to some kind of spinlock-sync'ed operation, diff --git a/intern/atomic/intern/atomic_ops_ext.h b/intern/atomic/intern/atomic_ops_ext.h index 74ed327c1b7..8421aa72192 100644 --- a/intern/atomic/intern/atomic_ops_ext.h +++ b/intern/atomic/intern/atomic_ops_ext.h @@ -78,6 +78,28 @@ ATOMIC_INLINE size_t atomic_sub_and_fetch_z(size_t *p, size_t x) #endif } +ATOMIC_INLINE size_t atomic_fetch_and_add_z(size_t *p, size_t x) +{ + assert(sizeof(size_t) == LG_SIZEOF_PTR); + +#if (LG_SIZEOF_PTR == 8) + return (size_t)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)x); +#elif (LG_SIZEOF_PTR == 4) + return (size_t)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)x); +#endif +} + +ATOMIC_INLINE size_t atomic_fetch_and_sub_z(size_t *p, size_t x) +{ + assert(sizeof(size_t) == LG_SIZEOF_PTR); + +#if (LG_SIZEOF_PTR == 8) + return (size_t)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x)); +#elif (LG_SIZEOF_PTR == 4) + return (size_t)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x)); +#endif +} + ATOMIC_INLINE size_t atomic_cas_z(size_t *v, size_t old, size_t _new) { assert(sizeof(size_t) == LG_SIZEOF_PTR); @@ -113,6 +135,28 @@ ATOMIC_INLINE unsigned atomic_sub_and_fetch_u(unsigned *p, unsigned x) #endif } +ATOMIC_INLINE unsigned atomic_fetch_and_add_u(unsigned *p, unsigned x) +{ + assert(sizeof(unsigned) == LG_SIZEOF_INT); + +#if (LG_SIZEOF_INT == 8) + return (unsigned)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)x); +#elif (LG_SIZEOF_INT == 4) + return (unsigned)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)x); +#endif +} + +ATOMIC_INLINE unsigned atomic_fetch_and_sub_u(unsigned *p, unsigned x) +{ + assert(sizeof(unsigned) == LG_SIZEOF_INT); + +#if (LG_SIZEOF_INT == 8) + return (unsigned)atomic_fetch_and_add_uint64((uint64_t *)p, (uint64_t)-((int64_t)x)); +#elif (LG_SIZEOF_INT == 4) + return (unsigned)atomic_fetch_and_add_uint32((uint32_t *)p, (uint32_t)-((int32_t)x)); +#endif +} + ATOMIC_INLINE unsigned atomic_cas_u(unsigned *v, unsigned old, unsigned _new) { assert(sizeof(unsigned) == LG_SIZEOF_INT); diff --git a/intern/atomic/intern/atomic_ops_msvc.h b/intern/atomic/intern/atomic_ops_msvc.h index e7aae4a74a0..034ac1e3e53 100644 --- a/intern/atomic/intern/atomic_ops_msvc.h +++ b/intern/atomic/intern/atomic_ops_msvc.h @@ -57,6 +57,16 @@ ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _ne { return InterlockedCompareExchange64((int64_t *)v, _new, old); } + +ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x) +{ + return InterlockedExchangeAdd64((int64_t *)p, (int64_t)x); +} + +ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x) +{ + return InterlockedExchangeAdd64((int64_t *)p, -((int64_t)x)); +} #endif /******************************************************************************/ diff --git a/intern/atomic/intern/atomic_ops_unix.h b/intern/atomic/intern/atomic_ops_unix.h index 3d00f91be25..0a3322ad2b1 100644 --- a/intern/atomic/intern/atomic_ops_unix.h +++ b/intern/atomic/intern/atomic_ops_unix.h @@ -68,12 +68,22 @@ ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x) return __sync_sub_and_fetch(p, x); } +ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x) +{ + return __sync_fetch_and_add(p, x); +} + +ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x) +{ + return __sync_fetch_and_sub(p, x); +} + ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new) { return __sync_val_compare_and_swap(v, old, _new); } # elif (defined(__amd64__) || defined(__x86_64__)) -ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x) +ATOMIC_INLINE uint64_t atomic_fetch_and_add_uint64(uint64_t *p, uint64_t x) { asm volatile ( "lock; xaddq %0, %1;" @@ -83,7 +93,7 @@ ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x) return x; } -ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x) +ATOMIC_INLINE uint64_t atomic_fetch_and_sub_uint64(uint64_t *p, uint64_t x) { x = (uint64_t)(-(int64_t)x); asm volatile ( @@ -94,6 +104,16 @@ ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x) return x; } +ATOMIC_INLINE uint64_t atomic_add_and_fetch_uint64(uint64_t *p, uint64_t x) +{ + return atomic_fetch_and_add_uint64(p, x) + x; +} + +ATOMIC_INLINE uint64_t atomic_sub_and_fetch_uint64(uint64_t *p, uint64_t x) +{ + return atomic_fetch_and_sub_uint64(p, x) - x; +} + ATOMIC_INLINE uint64_t atomic_cas_uint64(uint64_t *v, uint64_t old, uint64_t _new) { uint64_t ret; From 445274fc4fd8d563de585c27711f8385ce4174be Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 15 Nov 2016 11:30:21 +0100 Subject: [PATCH 210/590] Depsgraph: Fix typo in previous optimization commit Was a residue from another experiment, caused infinite loop when reporting dependency cycles. --- source/blender/depsgraph/intern/builder/deg_builder_cycle.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc index d84a590b29f..9b37aaa12ff 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_cycle.cc @@ -88,7 +88,7 @@ void deg_graph_detect_cycles(Depsgraph *graph) } while (!traversal_stack.empty()) { - StackEntry entry = traversal_stack.top(); + StackEntry& entry = traversal_stack.top(); OperationDepsNode *node = entry.node; bool all_child_traversed = true; for (int i = node->done; i < node->outlinks.size(); ++i) { From 69470e36d6b17042260b06f26ca3c2f702747324 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Tue, 15 Nov 2016 11:50:11 +0100 Subject: [PATCH 211/590] Implement grouped undo option for operators This option makes an operator to not push a task to the undo stack if the previous stored elemen is the same operator or part of the same undo group. The main usage is for animation, so you can change frames to inspect the poses, and revert the previous pose without having to roll back tons of "change frame" operator, or even see the undo stack full. This complements rB13ee9b8e Design with help by Sergey Sharybin. Reviewers: sergey, mont29 Reviewed By: mont29, sergey Subscribers: pyc0d3r, hjalti, Severin, lowercase, brecht, monio, aligorith, hadrien, jbakker Differential Revision: https://developer.blender.org/D2330 --- source/blender/blenkernel/BKE_blender_undo.h | 1 + .../blender/blenkernel/intern/blender_undo.c | 7 +++ source/blender/editors/animation/anim_ops.c | 4 +- source/blender/editors/include/ED_util.h | 2 + source/blender/editors/screen/screen_ops.c | 12 +++-- source/blender/editors/util/undo.c | 23 ++++++++++ source/blender/makesrna/intern/rna_wm.c | 46 +++++++++++++++++-- source/blender/windowmanager/WM_types.h | 2 + .../windowmanager/intern/wm_event_system.c | 4 ++ 9 files changed, 92 insertions(+), 9 deletions(-) diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h index 9547eeb9838..84a6d07be7d 100644 --- a/source/blender/blenkernel/BKE_blender_undo.h +++ b/source/blender/blenkernel/BKE_blender_undo.h @@ -42,6 +42,7 @@ extern bool BKE_undo_is_valid(const char *name); extern void BKE_undo_reset(void); extern void BKE_undo_number(struct bContext *C, int nr); extern const char *BKE_undo_get_name(int nr, bool *r_active); +extern const char *BKE_undo_get_name_last(void); extern bool BKE_undo_save_file(const char *filename); extern struct Main *BKE_undo_get_main(struct Scene **r_scene); diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index d64bf7ecf43..ce6d29bbfee 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -319,6 +319,13 @@ const char *BKE_undo_get_name(int nr, bool *r_active) return NULL; } +/* return the name of the last item */ +const char *BKE_undo_get_name_last() +{ + UndoElem *uel = undobase.last; + return (uel ? uel->name : NULL); +} + /** * Saves .blend using undo buffer. * diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index d7899061218..c0d6963acbb 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -57,6 +57,7 @@ #include "ED_anim_api.h" #include "ED_screen.h" #include "ED_sequencer.h" +#include "ED_util.h" #include "anim_intern.h" @@ -263,7 +264,8 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) ot->poll = change_frame_poll; /* flags */ - ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR; + ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_CURSOR | OPTYPE_UNDO_GROUPED; + ot->undo_group = "FRAME_CHANGE"; /* rna */ ot->prop = RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME); diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index f5968397f65..a4afa958450 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -52,6 +52,8 @@ void ED_OT_flush_edits(struct wmOperatorType *ot); /* undo.c */ void ED_undo_push(struct bContext *C, const char *str); void ED_undo_push_op(struct bContext *C, struct wmOperator *op); +void ED_undo_grouped_push(struct bContext *C, const char *str); +void ED_undo_grouped_push_op(struct bContext *C, struct wmOperator *op); void ED_undo_pop_op(struct bContext *C, struct wmOperator *op); void ED_undo_pop(struct bContext *C); void ED_undo_redo(struct bContext *C); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 860a865466a..022b8605436 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -2136,7 +2136,8 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot) ot->exec = frame_offset_exec; ot->poll = ED_operator_screenactive_norender; - ot->flag = 0; + ot->flag = OPTYPE_UNDO_GROUPED; + ot->undo_group = "FRAME_CHANGE"; /* rna */ RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX); @@ -2189,7 +2190,8 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot) ot->exec = frame_jump_exec; ot->poll = ED_operator_screenactive_norender; - ot->flag = OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO_GROUPED; + ot->undo_group = "FRAME_CHANGE"; /* rna */ RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range"); @@ -2295,7 +2297,8 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot) ot->exec = keyframe_jump_exec; ot->poll = ED_operator_screenactive_norender; - ot->flag = OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO_GROUPED; + ot->undo_group = "FRAME_CHANGE"; /* properties */ RNA_def_boolean(ot->srna, "next", true, "Next Keyframe", ""); @@ -2357,7 +2360,8 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot) ot->exec = marker_jump_exec; ot->poll = ED_operator_screenactive_norender; - ot->flag = OPTYPE_UNDO; + ot->flag = OPTYPE_UNDO_GROUPED; + ot->undo_group = "FRAME_CHANGE"; /* properties */ RNA_def_boolean(ot->srna, "next", true, "Next Marker", ""); diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index ee6700666c0..4a9311416b3 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -217,6 +217,19 @@ static int ed_undo_step(bContext *C, int step, const char *undoname) return OPERATOR_FINISHED; } +void ED_undo_grouped_push(bContext *C, const char *str) +{ + /* do nothing if previous undo task is the same as this one (or from the same undo group) */ + const char *last_undo = BKE_undo_get_name_last(); + + if (last_undo && STREQ(str, last_undo)) { + return; + } + + /* push as usual */ + ED_undo_push(C, str); +} + void ED_undo_pop(bContext *C) { ed_undo_step(C, 1, NULL); @@ -232,6 +245,16 @@ void ED_undo_push_op(bContext *C, wmOperator *op) ED_undo_push(C, op->type->name); } +void ED_undo_grouped_push_op(bContext *C, wmOperator *op) +{ + if (op->type->undo_group[0] != '\0') { + ED_undo_grouped_push(C, op->type->undo_group); + } + else { + ED_undo_grouped_push(C, op->type->name); + } +} + void ED_undo_pop_op(bContext *C, wmOperator *op) { /* search back a couple of undo's, in case something else added pushes */ diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 90081a93188..35c9c9bcc89 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -419,6 +419,7 @@ static EnumPropertyItem keymap_modifiers_items[] = { static EnumPropertyItem operator_flag_items[] = { {OPTYPE_REGISTER, "REGISTER", 0, "Register", "Display in the info window and support the redo toolbar panel"}, {OPTYPE_UNDO, "UNDO", 0, "Undo", "Push an undo event (needed for operator redo)"}, + {OPTYPE_UNDO_GROUPED, "UNDO_GROUPED", 0, "Grouped Undo", "Push a single undo event for repetead instances of this operator"}, {OPTYPE_BLOCKING, "BLOCKING", 0, "Blocking", "Block anything else from using the cursor"}, {OPTYPE_MACRO, "MACRO", 0, "Macro", "Use to check if an operator is a macro"}, {OPTYPE_GRAB_CURSOR, "GRAB_CURSOR", 0, "Grab Pointer", @@ -1139,6 +1140,7 @@ static char _operator_idname[OP_MAX_TYPENAME]; static char _operator_name[OP_MAX_TYPENAME]; static char _operator_descr[RNA_DYN_DESCR_MAX]; static char _operator_ctxt[RNA_DYN_DESCR_MAX]; +static char _operator_undo_group[OP_MAX_TYPENAME]; static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void *data, const char *identifier, StructValidateFunc validate, StructCallbackFunc call, StructFreeFunc free) { @@ -1153,10 +1155,11 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */ dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */ dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */ + dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr); /* clear in case they are left unset */ - _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0'; + _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0'; /* We have to set default op context! */ strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); @@ -1210,9 +1213,10 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * int namelen = strlen(_operator_name) + 1; int desclen = strlen(_operator_descr) + 1; int ctxtlen = strlen(_operator_ctxt) + 1; + int ugrouplen = strlen(_operator_undo_group) + 1; char *ch; /* 2 terminators and 3 to convert a.b -> A_OT_b */ - ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname"); + ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname"); WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */ dummyot.idname = ch; ch += idlen; @@ -1224,6 +1228,9 @@ static StructRNA *rna_Operator_register(Main *bmain, ReportList *reports, void * ch += desclen; strcpy(ch, _operator_ctxt); dummyot.translation_context = ch; + ch += ctxtlen; + strcpy(ch, _operator_undo_group); + dummyot.undo_group = ch; } } @@ -1280,10 +1287,11 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v dummyot.name = _operator_name; /* only assigne the pointer, string is NULL'd */ dummyot.description = _operator_descr; /* only assigne the pointer, string is NULL'd */ dummyot.translation_context = _operator_ctxt; /* only assigne the pointer, string is NULL'd */ + dummyot.undo_group = _operator_undo_group; /* only assigne the pointer, string is NULL'd */ RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr); /* clear in case they are left unset */ - _operator_idname[0] = _operator_name[0] = _operator_descr[0] = '\0'; + _operator_idname[0] = _operator_name[0] = _operator_descr[0] = _operator_undo_group[0] = '\0'; /* We have to set default op context! */ strcpy(_operator_ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT); @@ -1297,9 +1305,10 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v int namelen = strlen(_operator_name) + 1; int desclen = strlen(_operator_descr) + 1; int ctxtlen = strlen(_operator_ctxt) + 1; + int ugrouplen = strlen(_operator_undo_group) + 1; char *ch; /* 2 terminators and 3 to convert a.b -> A_OT_b */ - ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen), "_operator_idname"); + ch = MEM_callocN(sizeof(char) * (idlen + namelen + desclen + ctxtlen + ugrouplen), "_operator_idname"); WM_operator_bl_idname(ch, _operator_idname); /* convert the idname from python */ dummyot.idname = ch; ch += idlen; @@ -1311,6 +1320,9 @@ static StructRNA *rna_MacroOperator_register(Main *bmain, ReportList *reports, v ch += desclen; strcpy(ch, _operator_ctxt); dummyot.translation_context = ch; + ch += ctxtlen; + strcpy(ch, _operator_undo_group); + dummyot.undo_group = ch; } if (strlen(identifier) >= sizeof(dummyop.idname)) { @@ -1401,6 +1413,16 @@ static void rna_Operator_bl_description_set(PointerRNA *ptr, const char *value) assert(!"setting the bl_description on a non-builtin operator"); } +static void rna_Operator_bl_undo_group_set(PointerRNA *ptr, const char *value) +{ + wmOperator *data = (wmOperator *)(ptr->data); + char *str = (char *)data->type->undo_group; + if (!str[0]) + BLI_strncpy(str, value, OP_MAX_TYPENAME); /* utf8 already ensured */ + else + assert(!"setting the bl_undo_group on a non-builtin operator"); +} + static void rna_KeyMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { wmKeyMapItem *kmi = ptr->data; @@ -1509,6 +1531,14 @@ static void rna_def_operator(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ + prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->undo_group"); + RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */ + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set"); + /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ + prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type->flag"); RNA_def_property_enum_items(prop, operator_flag_items); @@ -1587,6 +1617,14 @@ static void rna_def_macro_operator(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ + prop = RNA_def_property(srna, "bl_undo_group", PROP_STRING, PROP_NONE); + RNA_def_property_string_sdna(prop, NULL, "type->undo_group"); + RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); /* else it uses the pointer size! */ + RNA_def_property_string_funcs(prop, NULL, NULL, "rna_Operator_bl_undo_group_set"); + /* RNA_def_property_clear_flag(prop, PROP_EDITABLE); */ + RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); + RNA_def_property_clear_flag(prop, PROP_NEVER_NULL); /* check for NULL */ + prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type->flag"); RNA_def_property_enum_items(prop, operator_flag_items); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 0fe3e8a0fcf..cd46e24264d 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -138,6 +138,7 @@ enum { OPTYPE_INTERNAL = (1 << 6), OPTYPE_LOCK_BYPASS = (1 << 7), /* Allow operator to run when interface is locked */ + OPTYPE_UNDO_GROUPED = (1 << 8), /* Special type of undo which doesn't store itself multiple times */ }; /* context to call operator in for WM_operator_name_call */ @@ -522,6 +523,7 @@ typedef struct wmOperatorType { const char *idname; /* unique identifier */ const char *translation_context; const char *description; /* tooltips and python docs */ + const char *undo_group; /* identifier to group operators together */ /* this callback executes the operator without any interactive input, * parameters may be provided through operator properties. cannot use diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index dc34e8015c9..ad8a67027c0 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -730,6 +730,8 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat) if (wm->op_undo_depth == 0) if (op->type->flag & OPTYPE_UNDO) ED_undo_push_op(C, op); + else if (op->type->flag & OPTYPE_UNDO_GROUPED) + ED_undo_grouped_push_op(C, op); if (repeat == 0) { if (G.debug & G_DEBUG_WM) { @@ -1857,6 +1859,8 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) if (handler->op->type->flag & OPTYPE_UNDO) ED_undo_push_op(C, handler->op); + else if (handler->op->type->flag & OPTYPE_UNDO_GROUPED) + ED_undo_grouped_push_op(C, handler->op); if (handler->op->reports->list.first) { From 0cd1b5ef85142cc3dcd69acdd5dbfc42a622ee3b Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 15 Nov 2016 15:27:22 +0100 Subject: [PATCH 212/590] Fix T50022: "Mirror" in Dopesheet Crashes Blender Just fixing crash itself. Actually operator shouldn't run in most editors (not in dopesheet either I guess), but don't want to spend time on that right now. --- source/blender/editors/transform/transform.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index ef6cff19181..daf0aed59e7 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -3392,7 +3392,9 @@ static void ElementResize(TransInfo *t, TransData *td, float mat[3][3]) } protectedTransBits(td->protectflag, vec); - add_v3_v3v3(td->loc, td->iloc, vec); + if (td->loc) { + add_v3_v3v3(td->loc, td->iloc, vec); + } constraintTransLim(t, td); } From 85e51b063854d81b486d7099536bc21404fc627e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 15 Nov 2016 15:38:03 +0100 Subject: [PATCH 213/590] Avoid driver target remapping when freeing the whole database Added BKE_libblock_free_data_ex() which takes special do_id_user argument which basically indicates whether main database was already taken care about not having "dead" pointers. Gives about 40% speedup of main database free with quadbot scene (3.4sec vs. 5.4 sec on quite powerful desktop). --- source/blender/blenkernel/BKE_library.h | 1 + source/blender/blenkernel/intern/library_remap.c | 15 +++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 1cc7014765c..39e8d712630 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -68,6 +68,7 @@ void BKE_libblock_free(struct Main *bmain, void *idv) 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_free_data_ex(struct Main *bmain, struct ID *id, const bool do_id_user) ATTR_NONNULL(); void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index b468e6436c8..4262972e015 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -690,14 +690,21 @@ static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata } void BKE_libblock_free_data(Main *bmain, ID *id) +{ + BKE_libblock_free_data_ex(bmain, id, true); +} + +void BKE_libblock_free_data_ex(Main *bmain, ID *id, const bool do_id_user) { if (id->properties) { IDP_FreeProperty(id->properties); MEM_freeN(id->properties); } - - /* this ID may be a driver target! */ - BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); + + if (do_id_user) { + /* this ID may be a driver target! */ + BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); + } } /** @@ -840,7 +847,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) BLI_remlink(lb, id); - BKE_libblock_free_data(bmain, id); + BKE_libblock_free_data_ex(bmain, id, do_id_user); BKE_main_unlock(bmain); MEM_freeN(id); From 625db1d86eab7d1a24f8ce01f12f7ffb945dea14 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 15 Nov 2016 15:46:52 +0100 Subject: [PATCH 214/590] Avoid interface ID remapping when freeing the whole database This makes heavy scenes to be freed almost instantly (so now quadbot scene takes only 0.06sec to free), --- source/blender/blenkernel/BKE_library.h | 2 +- source/blender/blenkernel/intern/blendfile.c | 4 +- source/blender/blenkernel/intern/library.c | 74 +++++++++---------- .../blender/blenkernel/intern/library_remap.c | 19 +++-- 4 files changed, 52 insertions(+), 47 deletions(-) diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 39e8d712630..afe13b24f3f 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -65,7 +65,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, const bool do_id_user) ATTR_NONNULL(); +void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user, const bool do_ui_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_free_data_ex(struct Main *bmain, struct ID *id, const bool do_id_user) ATTR_NONNULL(); diff --git a/source/blender/blenkernel/intern/blendfile.c b/source/blender/blenkernel/intern/blendfile.c index 6da68470ecc..54f709a1e5b 100644 --- a/source/blender/blenkernel/intern/blendfile.c +++ b/source/blender/blenkernel/intern/blendfile.c @@ -407,9 +407,9 @@ bool BKE_blendfile_read_from_memfile( if (bfd) { /* remove the unused screens and wm */ while (bfd->main->wm.first) - BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true); + BKE_libblock_free_ex(bfd->main, bfd->main->wm.first, true, true); while (bfd->main->screen.first) - BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true); + BKE_libblock_free_ex(bfd->main, bfd->main->screen.first, true, true); setup_app_data(C, bfd, "", reports); } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index e5b066a3c26..3411eae22e1 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1211,46 +1211,46 @@ void BKE_main_free(Main *mainvar) while ( (id = lb->first) ) { #if 1 - BKE_libblock_free_ex(mainvar, id, false); + BKE_libblock_free_ex(mainvar, id, false, false); #else /* errors freeing ID's can be hard to track down, * enable this so valgrind will give the line number in its error log */ switch (a) { - case 0: BKE_libblock_free_ex(mainvar, id, false); break; - case 1: BKE_libblock_free_ex(mainvar, id, false); break; - case 2: BKE_libblock_free_ex(mainvar, id, false); break; - case 3: BKE_libblock_free_ex(mainvar, id, false); break; - case 4: BKE_libblock_free_ex(mainvar, id, false); break; - case 5: BKE_libblock_free_ex(mainvar, id, false); break; - case 6: BKE_libblock_free_ex(mainvar, id, false); break; - case 7: BKE_libblock_free_ex(mainvar, id, false); break; - case 8: BKE_libblock_free_ex(mainvar, id, false); break; - case 9: BKE_libblock_free_ex(mainvar, id, false); break; - case 10: BKE_libblock_free_ex(mainvar, id, false); break; - case 11: BKE_libblock_free_ex(mainvar, id, false); break; - case 12: BKE_libblock_free_ex(mainvar, id, false); break; - case 13: BKE_libblock_free_ex(mainvar, id, false); break; - case 14: BKE_libblock_free_ex(mainvar, id, false); break; - case 15: BKE_libblock_free_ex(mainvar, id, false); break; - case 16: BKE_libblock_free_ex(mainvar, id, false); break; - case 17: BKE_libblock_free_ex(mainvar, id, false); break; - case 18: BKE_libblock_free_ex(mainvar, id, false); break; - case 19: BKE_libblock_free_ex(mainvar, id, false); break; - case 20: BKE_libblock_free_ex(mainvar, id, false); break; - case 21: BKE_libblock_free_ex(mainvar, id, false); break; - case 22: BKE_libblock_free_ex(mainvar, id, false); break; - case 23: BKE_libblock_free_ex(mainvar, id, false); break; - case 24: BKE_libblock_free_ex(mainvar, id, false); break; - case 25: BKE_libblock_free_ex(mainvar, id, false); break; - case 26: BKE_libblock_free_ex(mainvar, id, false); break; - case 27: BKE_libblock_free_ex(mainvar, id, false); break; - case 28: BKE_libblock_free_ex(mainvar, id, false); break; - case 29: BKE_libblock_free_ex(mainvar, id, false); break; - case 30: BKE_libblock_free_ex(mainvar, id, false); break; - case 31: BKE_libblock_free_ex(mainvar, id, false); break; - case 32: BKE_libblock_free_ex(mainvar, id, false); break; - case 33: BKE_libblock_free_ex(mainvar, id, false); break; - case 34: BKE_libblock_free_ex(mainvar, id, false); break; + case 0: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 1: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 2: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 3: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 4: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 5: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 6: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 7: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 8: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 9: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 10: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 11: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 12: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 13: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 14: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 15: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 16: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 17: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 18: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 19: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 20: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 21: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 22: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 23: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 24: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 25: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 26: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 27: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 28: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 29: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 30: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 31: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 32: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 33: BKE_libblock_free_ex(mainvar, id, false, false); break; + case 34: BKE_libblock_free_ex(mainvar, id, false, false); break; default: BLI_assert(0); break; @@ -1852,7 +1852,7 @@ void BKE_library_make_local( * 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 1 - BKE_libblock_free_ex(bmain, id, false); + BKE_libblock_free_ex(bmain, id, false, true); #else BKE_libblock_unlink(bmain, id, false, false); BKE_libblock_free(bmain, id); diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 4262972e015..4133342f3f2 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -711,8 +711,11 @@ void BKE_libblock_free_data_ex(Main *bmain, ID *id, const bool do_id_user) * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c * * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv. + * (only applies to main database) + * \param do_ui_user: similar to do_id_user but makes sure UI does not hold references to + * \a id. */ -void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) +void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const bool do_ui_user) { ID *id = idv; short type = GS(id->name); @@ -837,12 +840,14 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) /* avoid notifying on removed data */ BKE_main_lock(bmain); - if (free_notifier_reference_cb) { - free_notifier_reference_cb(id); - } + if (do_ui_user) { + if (free_notifier_reference_cb) { + free_notifier_reference_cb(id); + } - if (remap_editor_id_reference_cb) { - remap_editor_id_reference_cb(id, NULL); + if (remap_editor_id_reference_cb) { + remap_editor_id_reference_cb(id, NULL); + } } BLI_remlink(lb, id); @@ -855,7 +860,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) void BKE_libblock_free(Main *bmain, void *idv) { - BKE_libblock_free_ex(bmain, idv, true); + BKE_libblock_free_ex(bmain, idv, true, true); } void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ From a828818d59f0f8ea41900a12db703ba3fae075a7 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 15 Nov 2016 16:01:21 +0100 Subject: [PATCH 215/590] Cleanup: More explicit parentheses --- source/blender/windowmanager/intern/wm_event_system.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index ad8a67027c0..d2b0acd836b 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -727,12 +727,13 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat) /* we don't want to do undo pushes for operators that are being * called from operators that already do an undo push. usually * this will happen for python operators that call C operators */ - if (wm->op_undo_depth == 0) + if (wm->op_undo_depth == 0) { if (op->type->flag & OPTYPE_UNDO) ED_undo_push_op(C, op); else if (op->type->flag & OPTYPE_UNDO_GROUPED) ED_undo_grouped_push_op(C, op); - + } + if (repeat == 0) { if (G.debug & G_DEBUG_WM) { char *buf = WM_operator_pystring(C, op, false, true); @@ -1856,11 +1857,12 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand wm->op_undo_depth--; /* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */ - if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) + if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0) { if (handler->op->type->flag & OPTYPE_UNDO) ED_undo_push_op(C, handler->op); else if (handler->op->type->flag & OPTYPE_UNDO_GROUPED) ED_undo_grouped_push_op(C, handler->op); + } if (handler->op->reports->list.first) { From cb117f283bda615eb63b6767c77a361cea2b8992 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Tue, 15 Nov 2016 15:55:54 +0100 Subject: [PATCH 216/590] Fix menu inconsistencies This commit fixes two issues: - UV/Image editor uvs menu did not match the 3D View's which was changed in rB2b240b043078 - Circle select tool was missing in particle edit mode Reviewers: Severin Differential Revision: https://developer.blender.org/D2329 --- release/scripts/startup/bl_ui/space_image.py | 17 +++++++++++++++-- release/scripts/startup/bl_ui/space_view3d.py | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index b6087184518..04b4cef9512 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -259,6 +259,20 @@ class IMAGE_MT_uvs_showhide(Menu): layout.operator("uv.hide", text="Hide Unselected").unselected = True +class IMAGE_MT_uvs_proportional(Menu): + bl_label = "Proportional Editing" + + def draw(self, context): + layout = self.layout + + layout.props_enum(context.tool_settings, "proportional_edit") + + layout.separator() + + layout.label("Falloff:") + layout.props_enum(context.tool_settings, "proportional_edit_falloff") + + class IMAGE_MT_uvs_transform(Menu): bl_label = "Transform" @@ -360,8 +374,7 @@ class IMAGE_MT_uvs(Menu): layout.separator() - layout.prop_menu_enum(toolsettings, "proportional_edit") - layout.prop_menu_enum(toolsettings, "proportional_edit_falloff") + layout.menu("IMAGE_MT_uvs_proportional") layout.separator() diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index bb5eb05c4e9..9de9376312c 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -710,6 +710,7 @@ class VIEW3D_MT_select_particle(Menu): layout = self.layout layout.operator("view3d.select_border") + layout.operator("view3d.select_circle") layout.separator() From 9019f8ca95d3316cd45abe024ac71d21a9793044 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 15 Nov 2016 16:13:24 +0100 Subject: [PATCH 217/590] Revert "Proxy: Construct pchan hash when syncing armature proxy" This reverts commit 9b5a32cbfb8a8565202bdccd232c53f98b62eeec. Apparently it is possible to have other thread mocking around with the hash. Needs deeper investigation, for the time being reverting to prevent crashes. --- source/blender/blenkernel/intern/armature.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index badfeaee6bd..2b333941c6e 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1781,7 +1781,6 @@ static void pose_proxy_synchronize(Object *ob, Object *from, int layer_protected BLI_duplicatelist(&pose->agroups, &frompose->agroups); pose->active_group = frompose->active_group; - BKE_pose_channels_hash_make(frompose); for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) { pchanp = BKE_pose_channel_find_name(frompose, pchan->name); From af0e6b31a5b06521ef541d8e2adc2b0777c880f9 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 15 Nov 2016 16:18:59 +0100 Subject: [PATCH 218/590] Depsgraph: Fix frash with iTaSC solver This commit reverts part of a fix for T33275, but things are: - I can not reproduce the original issue at all, so doesn't seem to cause any regressions. - It is really bad idea to do delayed initialization in the threaded environment, it's a straight way to some nasty issues. - We can't do things like this anyway because we go more granular, meaning such a delayed initialization will fail in the case of having several IK solvers (unless they properly accommodate to changed bone head). - Verified the fix with various files from Mango project and all of them seems to work nice with new depednency graph now (old depsgraph has some flickering, but it's not related on DEG itself, but on an environment with lots of proxies and threaded evaluation and it is not a new behavior). --- source/blender/ikplugin/intern/itasc_plugin.cpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index b8ed780397f..d58340965a7 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -1763,20 +1763,15 @@ void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime) } // if at least one tree, create the scenes from the PoseTree stored in the channels // postpone until execute_tree: this way the pose constraint are included - //if (count) - // create_scene(scene, ob, ctime); - //itasc_update_param(ob->pose); + if (count) + create_scene(scene, ob, ctime); + itasc_update_param(ob->pose); // make sure we don't rebuilt until the user changes something important ob->pose->flag &= ~POSE_WAS_REBUILT; } void itasc_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) { - if (!ob->pose->ikdata) { - // IK tree not yet created, no it now - create_scene(scene, ob, ctime); - itasc_update_param(ob->pose); - } if (ob->pose->ikdata) { IK_Data *ikdata = (IK_Data *)ob->pose->ikdata; bItasc *ikparam = (bItasc *) ob->pose->ikparam; From f2690673ba4966542684d5b6f17d0fa329c33b82 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 15 Nov 2016 16:36:47 +0100 Subject: [PATCH 219/590] Get rid of 'drivers unlinking' code in `BKE_libblock_free_data()` This has nothing to do here (freeing is not unlinking/remapping!), and was actually redoing something already taken care of by `BKE_libblock_relink_ex()` call in `BKE_libblock_free_ex()`. Also, gives some noticeable speedup when removing datablocks with do_unlink=True, about 5 to 10% quicker e.g. when deleting all objects from a py console, in a big production file... --- source/blender/blenkernel/BKE_library.h | 1 - source/blender/blenkernel/intern/library_remap.c | 12 +----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index afe13b24f3f..855eb10976c 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -68,7 +68,6 @@ void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_libblock_free_ex(struct Main *bmain, void *idv, const bool do_id_user, const bool do_ui_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_free_data_ex(struct Main *bmain, struct ID *id, const bool do_id_user) ATTR_NONNULL(); void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 4133342f3f2..4e5ece1fde5 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -690,21 +690,11 @@ static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata } void BKE_libblock_free_data(Main *bmain, ID *id) -{ - BKE_libblock_free_data_ex(bmain, id, true); -} - -void BKE_libblock_free_data_ex(Main *bmain, ID *id, const bool do_id_user) { if (id->properties) { IDP_FreeProperty(id->properties); MEM_freeN(id->properties); } - - if (do_id_user) { - /* this ID may be a driver target! */ - BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); - } } /** @@ -852,7 +842,7 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user, const b BLI_remlink(lb, id); - BKE_libblock_free_data_ex(bmain, id, do_id_user); + BKE_libblock_free_data(bmain, id); BKE_main_unlock(bmain); MEM_freeN(id); From 44b691dc658db9d4ae0993546abe559223146b67 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 15 Nov 2016 17:12:18 +0100 Subject: [PATCH 220/590] RNA Main API: set remove's do_unlink default value to true. On second and third thoughts, this should have been done that way since the begining, cases were you just delete a few data-blocks without any serious knowledge of their usages are much, much more frequent than cases where you are deleting thousands of data-blocks and are sure they are not used anywhere anymore... Own fault, but really frustrated that this topic was only raised the day after 2.78a was released. :( --- source/blender/makesrna/intern/rna_main_api.c | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index cc290eab59d..594c1752328 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -585,7 +585,7 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this camera before deleting it " "(WARNING: will also delete objects instancing that camera data)"); @@ -624,7 +624,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this scene before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -665,7 +665,7 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this object before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_objects_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -702,7 +702,7 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this material before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_materials_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -746,7 +746,7 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this node tree before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -805,7 +805,7 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mesh before deleting it " "(WARNING: will also delete objects instancing that mesh data)"); @@ -845,7 +845,7 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lamp before deleting it " "(WARNING: will also delete objects instancing that lamp data)"); @@ -963,7 +963,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this image before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_images_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1000,7 +1000,7 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lattice before deleting it " "(WARNING: will also delete objects instancing that lattice data)"); @@ -1040,7 +1040,7 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this curve before deleting it " "(WARNING: will also delete objects instancing that curve data)"); @@ -1078,7 +1078,7 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this metaball before deleting it " "(WARNING: will also delete objects instancing that metaball data)"); @@ -1118,7 +1118,7 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this font before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1156,7 +1156,7 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this texture before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_textures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1193,7 +1193,7 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this brush before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1230,7 +1230,7 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "world", "World", "", "World to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this world before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1267,7 +1267,7 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this group before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1304,7 +1304,7 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this speaker before deleting it " "(WARNING: will also delete objects instancing that speaker data)"); @@ -1343,7 +1343,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this text before deleting it"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_texts_load"); @@ -1393,7 +1393,7 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this sound before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1430,7 +1430,7 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this armature before deleting it " "(WARNING: will also delete objects instancing that armature data)"); @@ -1468,7 +1468,7 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this action before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_actions_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1504,7 +1504,7 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "Particle Settings to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of those particle settings before deleting them"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of those particle settings before deleting them"); func = RNA_def_function(srna, "tag", "rna_Main_particles_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1540,7 +1540,7 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this palette before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1610,7 +1610,7 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this grease pencil before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1639,7 +1639,7 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this movie clip before deleting it"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_movieclip_load"); @@ -1691,7 +1691,7 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mask before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1728,7 +1728,7 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); - RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it"); + RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this line style before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); From 0de157a3204206a5d0d90daa00e7c6648e3c9674 Mon Sep 17 00:00:00 2001 From: lazydodo Date: Tue, 15 Nov 2016 13:21:01 -0700 Subject: [PATCH 221/590] FIX T49899: Add EIGEN_MAKE_ALIGNED_OPERATOR_NEW to classes that use eigen's data types , to force aligned on 16 byte boundaries. --- intern/iksolver/intern/IK_QSegment.h | 1 + intern/iksolver/intern/IK_Solver.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/intern/iksolver/intern/IK_QSegment.h b/intern/iksolver/intern/IK_QSegment.h index 74f157aa763..247807dc5e0 100644 --- a/intern/iksolver/intern/IK_QSegment.h +++ b/intern/iksolver/intern/IK_QSegment.h @@ -60,6 +60,7 @@ class IK_QSegment { public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW virtual ~IK_QSegment(); // start: a user defined translation diff --git a/intern/iksolver/intern/IK_Solver.cpp b/intern/iksolver/intern/IK_Solver.cpp index cefb8c7ed7b..a00db4fa2f5 100644 --- a/intern/iksolver/intern/IK_Solver.cpp +++ b/intern/iksolver/intern/IK_Solver.cpp @@ -42,6 +42,7 @@ using namespace std; class IK_QSolver { public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW IK_QSolver() : root(NULL) { } From 6397319659cd8304f90f23832d42cdfd1f4f9fb3 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 16 Nov 2016 11:09:02 +1300 Subject: [PATCH 222/590] =?UTF-8?q?Fix=20T50023:=20Inverse=20Kinematics=20?= =?UTF-8?q?angle=20limits=20defaulting=20to=2010313.2403124=C2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Regression from 2.77a. The units for the min/max limits were changed in RNA but the pose channels were still being initialised with in degrees. --- source/blender/blenkernel/intern/action.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 470098f8c7c..dcbb667adca 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -433,8 +433,8 @@ bPoseChannel *BKE_pose_channel_verify(bPose *pose, const char *name) chan->scaleIn = chan->scaleOut = 1.0f; - chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -180.0f; - chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = 180.0f; + chan->limitmin[0] = chan->limitmin[1] = chan->limitmin[2] = -M_PI; + chan->limitmax[0] = chan->limitmax[1] = chan->limitmax[2] = M_PI; chan->stiffness[0] = chan->stiffness[1] = chan->stiffness[2] = 0.0f; chan->ikrotweight = chan->iklinweight = 0.0f; unit_m4(chan->constinv); From 8b2905952e9a82206f1a112e99ccc27a6acdde63 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 16 Nov 2016 11:14:38 +1300 Subject: [PATCH 223/590] Fix T50026: "Only Insert Needed" doesn't work when using Trackball rotation The rotation case here only covered rotation by the "Rotate" tool, but skipped the "Trackball" tool. --- source/blender/editors/transform/transform_conversions.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 9c266890d6d..ce3d903b8f6 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -5583,7 +5583,7 @@ void autokeyframe_ob_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *ob, if (tmode == TFM_TRANSLATION) { do_loc = true; } - else if (tmode == TFM_ROTATION) { + else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) { if (v3d->around == V3D_AROUND_ACTIVE) { if (ob != OBACT) do_loc = true; @@ -5728,7 +5728,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o else do_loc = true; } - else if (tmode == TFM_ROTATION) { + else if (ELEM(tmode, TFM_ROTATION, TFM_TRACKBALL)) { if (ELEM(v3d->around, V3D_AROUND_CURSOR, V3D_AROUND_ACTIVE)) do_loc = true; From eb9e9f7f1ac2c7aaec13906acca4f047d3e82e99 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 16 Nov 2016 10:09:43 +0100 Subject: [PATCH 224/590] Cleanup: Remove unused function --- .../blender/blenkernel/intern/library_remap.c | 25 +------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 4e5ece1fde5..40441034171 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -666,30 +666,7 @@ void BKE_libblock_relink_ex( } } -static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) -{ - ChannelDriver *driver; - FCurve *fcu; - - /* find the driver this belongs to and update it */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - driver = fcu->driver; - - if (driver) { - DriverVar *dvar; - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - DRIVER_TARGETS_USED_LOOPER(dvar) - { - if (dtar->id == userdata) - dtar->id = NULL; - } - DRIVER_TARGETS_LOOPER_END - } - } - } -} - -void BKE_libblock_free_data(Main *bmain, ID *id) +void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id) { if (id->properties) { IDP_FreeProperty(id->properties); From 4722fc5dd0a335588a160e43cf77223c256ebd31 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 16 Nov 2016 10:39:41 +0100 Subject: [PATCH 225/590] Disable possibility to flip bone names of linked armatures Linked data should not be modified in such a way. Reported by Nathan here in the studio, reviewed by Bastien, thanks! --- source/blender/editors/armature/pose_edit.c | 2 +- source/blender/editors/include/ED_screen.h | 1 + source/blender/editors/screen/screen_ops.c | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 5015829f868..322476dcca0 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -626,7 +626,7 @@ void POSE_OT_flip_names(wmOperatorType *ot) /* api callbacks */ ot->exec = pose_flip_names_exec; - ot->poll = ED_operator_posemode; + ot->poll = ED_operator_posemode_local; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 6a558d1c185..ec09add56b8 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -183,6 +183,7 @@ int ED_operator_uvmap(struct bContext *C); int ED_operator_posemode_exclusive(struct bContext *C); int ED_operator_posemode_context(struct bContext *C); int ED_operator_posemode(struct bContext *C); +int ED_operator_posemode_local(struct bContext *C); int ED_operator_mask(struct bContext *C); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 022b8605436..c69e01422e0 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -442,6 +442,17 @@ int ED_operator_posemode(bContext *C) return 0; } +int ED_operator_posemode_local(bContext *C) +{ + if (ED_operator_posemode(C)) { + Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); + bArmature *arm = ob->data; + return !(ID_IS_LINKED_DATABLOCK(&ob->id) || + ID_IS_LINKED_DATABLOCK(&arm->id)); + } + return false; +} + /* wrapper for ED_space_image_show_uvedit */ int ED_operator_uvedit(bContext *C) { From e17b92f535826bac45bb5205c557f88dee15e2ea Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 16 Nov 2016 11:07:07 +0100 Subject: [PATCH 226/590] Fix custom props not being handled correctly by manual/pyref UI menu entries. --- release/scripts/startup/bl_operators/wm.py | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 343fcdb0d22..68a25acc2db 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -935,16 +935,23 @@ def _wm_doc_get_id(doc_id, do_url=True, url_prefix=""): # detect if this is a inherited member and use that name instead rna_parent = rna_class.bl_rna - rna_prop = rna_parent.properties[class_prop] - rna_parent = rna_parent.base - while rna_parent and rna_prop == rna_parent.properties.get(class_prop): - class_name = rna_parent.identifier + rna_prop = rna_parent.properties.get(class_prop) + if rna_prop: rna_parent = rna_parent.base + while rna_parent and rna_prop == rna_parent.properties.get(class_prop): + class_name = rna_parent.identifier + rna_parent = rna_parent.base - if do_url: - url = ("%s/bpy.types.%s.html#bpy.types.%s.%s" % (url_prefix, class_name, class_name, class_prop)) + if do_url: + url = ("%s/bpy.types.%s.html#bpy.types.%s.%s" % (url_prefix, class_name, class_name, class_prop)) + else: + rna = ("bpy.types.%s.%s" % (class_name, class_prop)) else: - rna = ("bpy.types.%s.%s" % (class_name, class_prop)) + # We assume this is custom property, only try to generate generic url/rna_id... + if do_url: + url = ("%s/bpy.types.bpy_struct.html#bpy.types.bpy_struct.items" % (url_prefix,)) + else: + rna = "bpy.types.bpy_struct" return url if do_url else rna From f86eccb1ca2388ae203df2a59285a2f2fb9b6aa8 Mon Sep 17 00:00:00 2001 From: Martijn Berger Date: Wed, 16 Nov 2016 10:03:11 +0100 Subject: [PATCH 227/590] Remove unused vector icons it seems to me the icons are unused: - VICO_VIEW3D_VEC - VICO_EDIT_VEC - VICO_EDITMODE_VEC_DEHLT - VICO_EDITMODE_VEC_HLT - VICO_DISCLOSURE_TRI_RIGHT_VEC - VICO_DISCLOSURE_TRI_DOWN_VEC - VICO_MOVE_UP_VEC - VICO_MOVE_DOWN_VEC - VICO_X_VEC Since their code contains immediate mode GL calls and they seem to be unused i thought we could remove them. Reviewers: mont29 Reviewed By: mont29 Subscribers: merwin Tags: #bf_blender_2.8 Differential Revision: https://developer.blender.org/D2356 --- .../editors/interface/interface_icons.c | 233 ------------------ 1 file changed, 233 deletions(-) diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index ff9d2840e9c..65b12fcd64e 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -213,173 +213,6 @@ static void viconutil_set_point(GLint pt[2], int x, int y) pt[1] = y; } -static void viconutil_draw_tri(GLint(*pts)[2]) -{ - glBegin(GL_TRIANGLES); - glVertex2iv(pts[0]); - glVertex2iv(pts[1]); - glVertex2iv(pts[2]); - glEnd(); -} - -static void viconutil_draw_lineloop(GLint(*pts)[2], int numPoints) -{ - int i; - - glBegin(GL_LINE_LOOP); - for (i = 0; i < numPoints; i++) { - glVertex2iv(pts[i]); - } - glEnd(); -} - -static void viconutil_draw_lineloop_smooth(GLint(*pts)[2], int numPoints) -{ - glEnable(GL_LINE_SMOOTH); - viconutil_draw_lineloop(pts, numPoints); - glDisable(GL_LINE_SMOOTH); -} - -static void viconutil_draw_points(GLint(*pts)[2], int numPoints, int pointSize) -{ - int i; - - glBegin(GL_QUADS); - for (i = 0; i < numPoints; i++) { - int x = pts[i][0], y = pts[i][1]; - - glVertex2i(x - pointSize, y - pointSize); - glVertex2i(x + pointSize, y - pointSize); - glVertex2i(x + pointSize, y + pointSize); - glVertex2i(x - pointSize, y + pointSize); - } - glEnd(); -} - -/* Drawing functions */ - -static void vicon_x_draw(int x, int y, int w, int h, float alpha) -{ - x += 3; - y += 3; - w -= 6; - h -= 6; - - glEnable(GL_LINE_SMOOTH); - - glLineWidth(2.5); - - glColor4f(0.0, 0.0, 0.0, alpha); - glBegin(GL_LINES); - glVertex2i(x, y); - glVertex2i(x + w, y + h); - glVertex2i(x + w, y); - glVertex2i(x, y + h); - glEnd(); - - glDisable(GL_LINE_SMOOTH); -} - -static void vicon_view3d_draw(int x, int y, int w, int h, float alpha) -{ - int cx = x + w / 2; - int cy = y + h / 2; - int d = MAX2(2, h / 3); - - glColor4f(0.5, 0.5, 0.5, alpha); - glBegin(GL_LINES); - glVertex2i(x, cy - d); - glVertex2i(x + w, cy - d); - glVertex2i(x, cy + d); - glVertex2i(x + w, cy + d); - - glVertex2i(cx - d, y); - glVertex2i(cx - d, y + h); - glVertex2i(cx + d, y); - glVertex2i(cx + d, y + h); - glEnd(); - - glColor4f(0.0, 0.0, 0.0, alpha); - glBegin(GL_LINES); - glVertex2i(x, cy); - glVertex2i(x + w, cy); - glVertex2i(cx, y); - glVertex2i(cx, y + h); - glEnd(); -} - -static void vicon_edit_draw(int x, int y, int w, int h, float alpha) -{ - GLint pts[4][2]; - - viconutil_set_point(pts[0], x + 3, y + 3); - viconutil_set_point(pts[1], x + w - 3, y + 3); - viconutil_set_point(pts[2], x + w - 3, y + h - 3); - viconutil_set_point(pts[3], x + 3, y + h - 3); - - glColor4f(0.0, 0.0, 0.0, alpha); - viconutil_draw_lineloop(pts, 4); - - glColor3f(1, 1, 0.0); - viconutil_draw_points(pts, 4, 1); -} - -static void vicon_editmode_hlt_draw(int x, int y, int w, int h, float alpha) -{ - GLint pts[3][2]; - - viconutil_set_point(pts[0], x + w / 2, y + h - 2); - viconutil_set_point(pts[1], x + 3, y + 4); - viconutil_set_point(pts[2], x + w - 3, y + 4); - - glColor4f(0.5, 0.5, 0.5, alpha); - viconutil_draw_tri(pts); - - glColor4f(0.0, 0.0, 0.0, 1); - viconutil_draw_lineloop_smooth(pts, 3); - - glColor3f(1, 1, 0.0); - viconutil_draw_points(pts, 3, 1); -} - -static void vicon_editmode_dehlt_draw(int x, int y, int w, int h, float UNUSED(alpha)) -{ - GLint pts[3][2]; - - viconutil_set_point(pts[0], x + w / 2, y + h - 2); - viconutil_set_point(pts[1], x + 3, y + 4); - viconutil_set_point(pts[2], x + w - 3, y + 4); - - glColor4f(0.0f, 0.0f, 0.0f, 1); - viconutil_draw_lineloop_smooth(pts, 3); - - glColor3f(0.9f, 0.9f, 0.9f); - viconutil_draw_points(pts, 3, 1); -} - -static void vicon_disclosure_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha) -{ - GLint pts[3][2]; - int cx = x + w / 2; - int cy = y + w / 2; - int d = w / 3, d2 = w / 5; - - viconutil_set_point(pts[0], cx - d2, cy + d); - viconutil_set_point(pts[1], cx - d2, cy - d); - viconutil_set_point(pts[2], cx + d2, cy); - - glBegin(GL_TRIANGLES); - glColor4f(0.8f, 0.8f, 0.8f, alpha); - glVertex2iv(pts[0]); - glVertex2iv(pts[1]); - glColor4f(0.3f, 0.3f, 0.3f, alpha); - glVertex2iv(pts[2]); - glEnd(); - - glColor4f(0.0f, 0.0f, 0.0f, 1); - viconutil_draw_lineloop_smooth(pts, 3); -} - static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float alpha) { GLint pts[3][2]; @@ -400,63 +233,6 @@ static void vicon_small_tri_right_draw(int x, int y, int w, int UNUSED(h), float glEnd(); } -static void vicon_disclosure_tri_down_draw(int x, int y, int w, int UNUSED(h), float alpha) -{ - GLint pts[3][2]; - int cx = x + w / 2; - int cy = y + w / 2; - int d = w / 3, d2 = w / 5; - - viconutil_set_point(pts[0], cx + d, cy + d2); - viconutil_set_point(pts[1], cx - d, cy + d2); - viconutil_set_point(pts[2], cx, cy - d2); - - glBegin(GL_TRIANGLES); - glColor4f(0.8f, 0.8f, 0.8f, alpha); - glVertex2iv(pts[0]); - glVertex2iv(pts[1]); - glColor4f(0.3f, 0.3f, 0.3f, alpha); - glVertex2iv(pts[2]); - glEnd(); - - glColor4f(0.0f, 0.0f, 0.0f, 1); - viconutil_draw_lineloop_smooth(pts, 3); -} - -static void vicon_move_up_draw(int x, int y, int w, int h, float UNUSED(alpha)) -{ - int d = -2; - - glEnable(GL_LINE_SMOOTH); - glLineWidth(1); - glColor3f(0.0, 0.0, 0.0); - - glBegin(GL_LINE_STRIP); - glVertex2i(x + w / 2 - d * 2, y + h / 2 + d); - glVertex2i(x + w / 2, y + h / 2 - d + 1); - glVertex2i(x + w / 2 + d * 2, y + h / 2 + d); - glEnd(); - - glDisable(GL_LINE_SMOOTH); -} - -static void vicon_move_down_draw(int x, int y, int w, int h, float UNUSED(alpha)) -{ - int d = 2; - - glEnable(GL_LINE_SMOOTH); - glLineWidth(1); - glColor3f(0.0, 0.0, 0.0); - - glBegin(GL_LINE_STRIP); - glVertex2i(x + w / 2 - d * 2, y + h / 2 + d); - glVertex2i(x + w / 2, y + h / 2 - d - 1); - glVertex2i(x + w / 2 + d * 2, y + h / 2 + d); - glEnd(); - - glDisable(GL_LINE_SMOOTH); -} - static void vicon_keytype_draw_wrapper(int x, int y, int w, int h, float alpha, short key_type) { /* init dummy theme state for Action Editor - where these colors are defined @@ -782,15 +558,6 @@ static void init_internal_icons(void) } } - def_internal_vicon(VICO_VIEW3D_VEC, vicon_view3d_draw); - def_internal_vicon(VICO_EDIT_VEC, vicon_edit_draw); - def_internal_vicon(VICO_EDITMODE_VEC_DEHLT, vicon_editmode_dehlt_draw); - def_internal_vicon(VICO_EDITMODE_VEC_HLT, vicon_editmode_hlt_draw); - def_internal_vicon(VICO_DISCLOSURE_TRI_RIGHT_VEC, vicon_disclosure_tri_right_draw); - def_internal_vicon(VICO_DISCLOSURE_TRI_DOWN_VEC, vicon_disclosure_tri_down_draw); - def_internal_vicon(VICO_MOVE_UP_VEC, vicon_move_up_draw); - def_internal_vicon(VICO_MOVE_DOWN_VEC, vicon_move_down_draw); - def_internal_vicon(VICO_X_VEC, vicon_x_draw); def_internal_vicon(VICO_SMALL_TRI_RIGHT_VEC, vicon_small_tri_right_draw); def_internal_vicon(VICO_KEYTYPE_KEYFRAME_VEC, vicon_keytype_keyframe_draw); From 209bc9977c9754d3ad5d4cf550a460eb56814686 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 16 Nov 2016 12:38:57 +0100 Subject: [PATCH 228/590] Fix T50046: Segmentation fault due to out-of-range VertexGroup.weight() call. `get_vert_def_nr()` was not checking vert index in bmesh case (aka Edit mode). --- source/blender/editors/object/object_vgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 82da6f58912..56f59dca9a1 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -886,7 +886,7 @@ static float get_vert_def_nr(Object *ob, const int def_nr, const int vertnum) const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); /* warning, this lookup is _not_ fast */ - if (cd_dvert_offset != -1) { + if (cd_dvert_offset != -1 && vertnum < em->bm->totvert) { BMVert *eve; BM_mesh_elem_table_ensure(em->bm, BM_VERT); eve = BM_vert_at_index(em->bm, vertnum); From 2a2eb0c463bd96d42f7306eb17f88cad87f73aea Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 16 Nov 2016 15:12:31 +0100 Subject: [PATCH 229/590] Cycles: Fix different noise pattern from fix in T49838: No need to hash subframe == 0. --- intern/cycles/blender/blender_sync.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 8ec9ecfd861..6118cc72239 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -257,9 +257,14 @@ void BlenderSync::sync_integrator() integrator->seed = get_int(cscene, "seed"); if(get_boolean(cscene, "use_animated_seed")) { integrator->seed = hash_int_2d(b_scene.frame_current(), - get_int(cscene, "seed")) + - hash_int_2d((int)(b_scene.frame_subframe() * (float)INT_MAX), get_int(cscene, "seed")); + if(b_scene.frame_subframe() != 0.0f) { + /* TODO(sergey): Ideally should be some sort of hash_merge, + * but this is good enough for now. + */ + integrator->seed += hash_int_2d((int)(b_scene.frame_subframe() * (float)INT_MAX), + get_int(cscene, "seed")); + } } integrator->sampling_pattern = (SamplingPattern)get_enum( From e400f4a53ec435b8c93c309896e63393c5b70bf3 Mon Sep 17 00:00:00 2001 From: Antonioya Date: Wed, 16 Nov 2016 21:33:47 +0100 Subject: [PATCH 230/590] Fix T50051: Avoid crash when render grease pencil from VSE The renderpasses for grease pencil are not necessary when render from sequencer. This fix solves the GPF but we need to rethink the complete render process for grease pencil and integrate better in the render and composition workflow. Thanks to Dalai Felinto por helping in the debug and fixing of the problem. --- source/blender/editors/render/render_opengl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 16842efb436..9097432a251 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -552,8 +552,11 @@ static void screen_opengl_render_apply(OGLRender *oglrender) BLI_assert(view_id < oglrender->views_len); RE_SetActiveRenderView(oglrender->re, rv->name); oglrender->view_id = view_id; - /* add grease pencil passes */ - add_gpencil_renderpass(oglrender, rr, rv); + /* add grease pencil passes. For sequencer, the render does not include renderpasses + * TODO: The sequencer render of grease pencil should be rethought */ + if (!oglrender->is_sequencer) { + add_gpencil_renderpass(oglrender, rr, rv); + } /* render composite */ screen_opengl_render_doit(oglrender, rr); } From 60409841a4b9308575b108933f5e4c0d96e64f7e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 17 Nov 2016 02:16:21 +0100 Subject: [PATCH 231/590] Fix T50001: auto tile size addon broken after Cycles GPU device changes. Adds a get_num_gpu_devices() utility function for the addon to use. --- intern/cycles/blender/addon/properties.py | 14 ++++++++++---- intern/cycles/blender/addon/ui.py | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 27c9b922042..a7dff1f79f3 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -1199,15 +1199,21 @@ class CyclesPreferences(bpy.types.AddonPreferences): return cuda_devices, opencl_devices - def has_active_device(self): + def get_num_gpu_devices(self): import _cycles device_list = _cycles.available_devices() + num = 0 for device in device_list: if device[1] != self.compute_device_type: continue - if any(dev.use and dev.id == device[2] for dev in self.devices): - return True - return False + for dev in self.devices: + if dev.use and dev.id == device[2]: + num += 1 + return num + + + def has_active_device(self): + return self.get_num_gpu_devices() > 0 def draw_impl(self, layout, context): diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index f28fa0d52ba..f435af178b5 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1620,7 +1620,7 @@ def draw_device(self, context): sub = row.split(align=True) sub.active = show_device_selection(context) sub.prop(cscene, "device", text="") - row.operator("wm.addon_userpref_show", text="Preferences", icon='PREFERENCES').module = __package__ + row.operator("wm.addon_userpref_show", text="", icon='PREFERENCES').module = __package__ if engine.with_osl() and use_cpu(context): layout.prop(cscene, "shading_system") From 16e2c0ef3c08b3a5d81ab21a71fc3c4c37e47e81 Mon Sep 17 00:00:00 2001 From: lazydodo Date: Wed, 16 Nov 2016 20:13:58 -0700 Subject: [PATCH 232/590] [MSVC] Preliminary VS2017 support. --- .../cmake/platform/platform_win32_msvc.cmake | 6 ++++-- make.bat | 16 +++++++++++++++- source/creator/CMakeLists.txt | 2 +- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/build_files/cmake/platform/platform_win32_msvc.cmake b/build_files/cmake/platform/platform_win32_msvc.cmake index 5efda52b2c5..6ca0568b5fd 100644 --- a/build_files/cmake/platform/platform_win32_msvc.cmake +++ b/build_files/cmake/platform/platform_win32_msvc.cmake @@ -129,8 +129,10 @@ if(NOT DEFINED LIBDIR) message(STATUS "32 bit compiler detected.") set(LIBDIR_BASE "windows") endif() - - if(MSVC_VERSION EQUAL 1900) + if(MSVC_VERSION EQUAL 1910) + message(STATUS "Visual Studio 2017 detected.") + set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14) + elseif(MSVC_VERSION EQUAL 1900) message(STATUS "Visual Studio 2015 detected.") set(LIBDIR ${CMAKE_SOURCE_DIR}/../lib/${LIBDIR_BASE}_vc14) else() diff --git a/make.bat b/make.bat index 74148e5599d..f3ec646dc8f 100644 --- a/make.bat +++ b/make.bat @@ -61,6 +61,9 @@ if NOT "%1" == "" ( set BUILD_ARCH=x86 ) else if "%1" == "x64" ( set BUILD_ARCH=x64 + ) else if "%1" == "2017" ( + set BUILD_VS_VER=15 + set BUILD_VS_YEAR=2017 ) else if "%1" == "2015" ( set BUILD_VS_VER=14 set BUILD_VS_YEAR=2015 @@ -140,7 +143,7 @@ if "%target%"=="Release" ( ) :DetectMSVC -REM Detect MSVC Installation +REM Detect MSVC Installation for 2013-2015 if DEFINED VisualStudioVersion goto msvc_detect_finally set VALUE_NAME=ProductDir REM Check 64 bits @@ -153,7 +156,18 @@ for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY %KEY_NAME% /v %VALUE_NAM if DEFINED MSVC_VC_DIR goto msvc_detect_finally :msvc_detect_finally if DEFINED MSVC_VC_DIR call "%MSVC_VC_DIR%\vcvarsall.bat" +if DEFINED MSVC_VC_DIR goto sanity_checks +rem MSVC Build environment 2017 and up. +for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SXS\VS7" /v %BUILD_VS_VER%.0 2^>nul`) DO set MSVC_VS_DIR=%%C +if DEFINED MSVC_VS_DIR goto msvc_detect_finally_2017 +REM Check 32 bits +for /F "usebackq skip=2 tokens=1-2*" %%A IN (`REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\sxs\vs7" /v %BUILD_VS_VER%.0 2^>nul`) DO set MSVC_VS_DIR=%%C +if DEFINED MSVC_VS_DIR goto msvc_detect_finally_2017 +:msvc_detect_finally_2017 +if DEFINED MSVC_VS_DIR call "%MSVC_VS_DIR%\Common7\Tools\VsDevCmd.bat" + +:sanity_checks REM Sanity Checks where /Q msbuild if %ERRORLEVEL% NEQ 0 ( diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 10af0d5489e..aa0a213cf64 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -714,7 +714,7 @@ elseif(WIN32) if(WITH_PYTHON_INSTALL_NUMPY) set(PYTHON_NUMPY_VERSION 1.9) - if(MSVC_VERSION EQUAL 1900) + if((MSVC_VERSION EQUAL 1900) OR (MSVC_VERSION EQUAL 1910)) set(PYTHON_NUMPY_VERSION 1.11) endif() add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages From 0c322c3000a0ddd7ac58c650f30b29d55afd1a97 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 17 Nov 2016 14:34:46 +0100 Subject: [PATCH 233/590] Depsgraph: Move rig builder functions to own files Those routines are rather big and started to be annoying to have one big file. Should be no functional changes. --- source/blender/depsgraph/CMakeLists.txt | 2 + .../intern/builder/deg_builder_nodes.cc | 209 -------- .../intern/builder/deg_builder_nodes_rig.cc | 275 +++++++++++ .../intern/builder/deg_builder_relations.cc | 385 --------------- .../builder/deg_builder_relations_rig.cc | 458 ++++++++++++++++++ 5 files changed, 735 insertions(+), 594 deletions(-) create mode 100644 source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc create mode 100644 source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index ab12a8d5b3e..ea839d11071 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -43,9 +43,11 @@ set(SRC intern/builder/deg_builder.cc intern/builder/deg_builder_cycle.cc intern/builder/deg_builder_nodes.cc + intern/builder/deg_builder_nodes_rig.cc intern/builder/deg_builder_pchanmap.cc intern/builder/deg_builder_relations.cc intern/builder/deg_builder_relations_keys.cc + intern/builder/deg_builder_relations_rig.cc intern/builder/deg_builder_transitive.cc intern/debug/deg_debug_graphviz.cc intern/eval/deg_eval.cc diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 12050e3e003..1eaacea69eb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -626,14 +626,6 @@ void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob) DEG_OPCODE_TRANSFORM_CONSTRAINTS); } -void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan) -{ - /* create node for constraint stack */ - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan), - DEG_OPCODE_BONE_CONSTRAINTS); -} - /** * Build graph nodes for AnimData block * \param id: ID-Block which hosts the AnimData @@ -829,207 +821,6 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) // TODO... } -/* IK Solver Eval Steps */ -void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) -{ - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - - /* Find the chain's root. */ - bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - - if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, - DEG_OPCODE_POSE_IK_SOLVER)) - { - return; - } - - /* Operation node for evaluating/running IK Solver. */ - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, - DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan), - DEG_OPCODE_POSE_IK_SOLVER); -} - -/* Spline IK Eval Steps */ -void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) -{ - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - - /* Find the chain's root. */ - bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); - - /* Operation node for evaluating/running Spline IK Solver. - * Store the "root bone" of this chain in the solver, so it knows where to start. - */ - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, - DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan), - DEG_OPCODE_POSE_SPLINE_IK_SOLVER); -} - -/* Pose/Armature Bones Graph */ -void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) -{ - bArmature *arm = (bArmature *)ob->data; - - /* animation and/or drivers linking posebones to base-armature used to define them - * NOTE: AnimData here is really used to control animated deform properties, - * which ideally should be able to be unique across different instances. - * Eventually, we need some type of proxy/isolation mechanism in-between here - * to ensure that we can use same rig multiple times in same scene... - */ - build_animdata(&arm->id); - - /* Rebuild pose if not up to date. */ - if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { - BKE_pose_rebuild_ex(ob, arm, false); - /* XXX: Without this animation gets lost in certain circumstances - * after loading file. Need to investigate further since it does - * not happen with simple scenes.. - */ - if (ob->adt) { - ob->adt->recalc |= ADT_RECALC_ANIM; - } - } - - /* speed optimization for animation lookups */ - if (ob->pose) { - BKE_pose_channels_hash_make(ob->pose); - if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(ob->pose); - } - } - - /* Make sure pose is up-to-date with armature updates. */ - add_operation_node(&arm->id, - DEPSNODE_TYPE_PARAMETERS, - DEPSOP_TYPE_EXEC, - NULL, - DEG_OPCODE_PLACEHOLDER, - "Armature Eval"); - - /** - * Pose Rig Graph - * ============== - * - * Pose Component: - * - Mainly used for referencing Bone components. - * - This is where the evaluation operations for init/exec/cleanup - * (ik) solvers live, and are later hooked up (so that they can be - * interleaved during runtime) with bone-operations they depend on/affect. - * - init_pose_eval() and cleanup_pose_eval() are absolute first and last - * steps of pose eval process. ALL bone operations must be performed - * between these two... - * - * Bone Component: - * - Used for representing each bone within the rig - * - Acts to encapsulate the evaluation operations (base matrix + parenting, - * and constraint stack) so that they can be easily found. - * - Everything else which depends on bone-results hook up to the component only - * so that we can redirect those to point at either the the post-IK/ - * post-constraint/post-matrix steps, as needed. - */ - - /* pose eval context */ - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT); - - add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE); - - /* bones */ - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - /* node for bone eval */ - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local - DEG_OPCODE_BONE_LOCAL); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose - DEG_OPCODE_BONE_POSE_PARENT); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */ - DEG_OPCODE_BONE_READY); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan), - DEG_OPCODE_BONE_DONE); - - /* constraints */ - if (pchan->constraints.first != NULL) { - build_pose_constraints(ob, pchan); - } - - /** - * IK Solvers... - * - * - These require separate processing steps are pose-level - * to be executed between chains of bones (i.e. once the - * base transforms of a bunch of bones is done) - * - * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building - * - Animated chain-lengths are a problem... - */ - for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - build_ik_pose(scene, ob, pchan, con); - break; - - case CONSTRAINT_TYPE_SPLINEIK: - build_splineik_pose(scene, ob, pchan, con); - break; - - default: - break; - } - } - } -} - -void DepsgraphNodeBuilder::build_proxy_rig(Object *ob) -{ - ID *obdata = (ID *)ob->data; - build_animdata(obdata); - - BLI_assert(ob->pose != NULL); - - /* speed optimization for animation lookups */ - BKE_pose_channels_hash_make(ob->pose); - if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { - BKE_pose_update_constraint_flags(ob->pose); - } - - add_operation_node(&ob->id, - DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_INIT, - function_bind(BKE_pose_eval_proxy_copy, _1, ob), - DEG_OPCODE_POSE_INIT); - - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; - pchan != NULL; - pchan = pchan->next) - { - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_INIT, NULL, - DEG_OPCODE_BONE_LOCAL); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_EXEC, NULL, - DEG_OPCODE_BONE_READY); - - add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, - DEPSOP_TYPE_POST, NULL, - DEG_OPCODE_BONE_DONE); - } - - add_operation_node(&ob->id, - DEPSNODE_TYPE_EVAL_POSE, - DEPSOP_TYPE_POST, - NULL, - DEG_OPCODE_POSE_DONE); -} - /* Shapekeys */ void DepsgraphNodeBuilder::build_shapekeys(Key *key) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc new file mode 100644 index 00000000000..b9c7c3c7f92 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -0,0 +1,275 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_nodes.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph's nodes + */ + +#include "intern/builder/deg_builder_nodes.h" + +#include +#include + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_blenlib.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" +#include "BKE_armature.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +} /* extern "C" */ + +#include "intern/builder/deg_builder.h" +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" +#include "intern/depsgraph_types.h" +#include "intern/depsgraph_intern.h" + +namespace DEG { + +void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan) +{ + /* create node for constraint stack */ + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan), + DEG_OPCODE_BONE_CONSTRAINTS); +} + +/* IK Solver Eval Steps */ +void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) +{ + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + + /* Find the chain's root. */ + bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); + + if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, + DEG_OPCODE_POSE_IK_SOLVER)) + { + return; + } + + /* Operation node for evaluating/running IK Solver. */ + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, + DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan), + DEG_OPCODE_POSE_IK_SOLVER); +} + +/* Spline IK Eval Steps */ +void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con) +{ + bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; + + /* Find the chain's root. */ + bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); + + /* Operation node for evaluating/running Spline IK Solver. + * Store the "root bone" of this chain in the solver, so it knows where to start. + */ + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, + DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan), + DEG_OPCODE_POSE_SPLINE_IK_SOLVER); +} + +/* Pose/Armature Bones Graph */ +void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) +{ + bArmature *arm = (bArmature *)ob->data; + + /* animation and/or drivers linking posebones to base-armature used to define them + * NOTE: AnimData here is really used to control animated deform properties, + * which ideally should be able to be unique across different instances. + * Eventually, we need some type of proxy/isolation mechanism in-between here + * to ensure that we can use same rig multiple times in same scene... + */ + build_animdata(&arm->id); + + /* Rebuild pose if not up to date. */ + if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) { + BKE_pose_rebuild_ex(ob, arm, false); + /* XXX: Without this animation gets lost in certain circumstances + * after loading file. Need to investigate further since it does + * not happen with simple scenes.. + */ + if (ob->adt) { + ob->adt->recalc |= ADT_RECALC_ANIM; + } + } + + /* speed optimization for animation lookups */ + if (ob->pose) { + BKE_pose_channels_hash_make(ob->pose); + if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(ob->pose); + } + } + + /* Make sure pose is up-to-date with armature updates. */ + add_operation_node(&arm->id, + DEPSNODE_TYPE_PARAMETERS, + DEPSOP_TYPE_EXEC, + NULL, + DEG_OPCODE_PLACEHOLDER, + "Armature Eval"); + + /** + * Pose Rig Graph + * ============== + * + * Pose Component: + * - Mainly used for referencing Bone components. + * - This is where the evaluation operations for init/exec/cleanup + * (ik) solvers live, and are later hooked up (so that they can be + * interleaved during runtime) with bone-operations they depend on/affect. + * - init_pose_eval() and cleanup_pose_eval() are absolute first and last + * steps of pose eval process. ALL bone operations must be performed + * between these two... + * + * Bone Component: + * - Used for representing each bone within the rig + * - Acts to encapsulate the evaluation operations (base matrix + parenting, + * and constraint stack) so that they can be easily found. + * - Everything else which depends on bone-results hook up to the component only + * so that we can redirect those to point at either the the post-IK/ + * post-constraint/post-matrix steps, as needed. + */ + + /* pose eval context */ + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT); + + add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE); + + /* bones */ + for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + /* node for bone eval */ + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local + DEG_OPCODE_BONE_LOCAL); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose + DEG_OPCODE_BONE_POSE_PARENT); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */ + DEG_OPCODE_BONE_READY); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan), + DEG_OPCODE_BONE_DONE); + + /* constraints */ + if (pchan->constraints.first != NULL) { + build_pose_constraints(ob, pchan); + } + + /** + * IK Solvers... + * + * - These require separate processing steps are pose-level + * to be executed between chains of bones (i.e. once the + * base transforms of a bunch of bones is done) + * + * Unsolved Issues: + * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building + * - Animated chain-lengths are a problem... + */ + for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { + switch (con->type) { + case CONSTRAINT_TYPE_KINEMATIC: + build_ik_pose(scene, ob, pchan, con); + break; + + case CONSTRAINT_TYPE_SPLINEIK: + build_splineik_pose(scene, ob, pchan, con); + break; + + default: + break; + } + } + } +} + +void DepsgraphNodeBuilder::build_proxy_rig(Object *ob) +{ + ID *obdata = (ID *)ob->data; + build_animdata(obdata); + + BLI_assert(ob->pose != NULL); + + /* speed optimization for animation lookups */ + BKE_pose_channels_hash_make(ob->pose); + if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) { + BKE_pose_update_constraint_flags(ob->pose); + } + + add_operation_node(&ob->id, + DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_INIT, + function_bind(BKE_pose_eval_proxy_copy, _1, ob), + DEG_OPCODE_POSE_INIT); + + for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; + pchan != NULL; + pchan = pchan->next) + { + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_INIT, NULL, + DEG_OPCODE_BONE_LOCAL); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_EXEC, NULL, + DEG_OPCODE_BONE_READY); + + add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, + DEPSOP_TYPE_POST, NULL, + DEG_OPCODE_BONE_DONE); + } + + add_operation_node(&ob->id, + DEPSNODE_TYPE_EVAL_POSE, + DEPSOP_TYPE_POST, + NULL, + DEG_OPCODE_POSE_DONE); +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index fe75de5e350..1497a16e47f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1345,391 +1345,6 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) // TODO... } -/* IK Solver Eval Steps */ -void DepsgraphRelationBuilder::build_ik_pose(Object *ob, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map) -{ - bKinematicConstraint *data = (bKinematicConstraint *)con->data; - - /* attach owner to IK Solver too - * - assume that owner is always part of chain - * - see notes on direction of rel below... - */ - bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); - OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER); - - /* IK target */ - // XXX: this should get handled as part of the constraint code - if (data->tar != NULL) { - /* TODO(sergey): For until we'll store partial matricies in the depsgraph, - * we create dependency between target object and pose eval component. - * - * This way we ensuring the whole subtree is updated from scratch without - * need of intermediate matricies. This is an overkill, but good enough for - * testing IK solver. - */ - // FIXME: geometry targets... - ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) { - /* TODO(sergey): This is only for until granular update stores intermediate result. */ - if (data->tar != ob) { - /* different armature - can just read the results */ - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget); - add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - else { - /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */ - OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE); - add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - } - else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) { - /* vertex group target */ - /* NOTE: for now, we don't need to represent vertex groups separately... */ - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); - add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); - - if (data->tar->type == OB_MESH) { - OperationDepsNode *node2 = find_operation_node(target_key); - if (node2 != NULL) { - node2->customdata_mask |= CD_MASK_MDEFORMVERT; - } - } - } - else { - /* Standard Object Target */ - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM); - add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - - if ((data->tar == ob) && (data->subtarget[0])) { - /* Prevent target's constraints from linking to anything from same - * chain that it controls. - */ - root_map->add_bone(data->subtarget, rootchan->name); - } - } - - /* Pole Target */ - // XXX: this should get handled as part of the constraint code - if (data->poletar != NULL) { - if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { - // XXX: same armature issues - ready vs done? - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget); - add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) { - /* vertex group target */ - /* NOTE: for now, we don't need to represent vertex groups separately... */ - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY); - add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); - - if (data->poletar->type == OB_MESH) { - OperationDepsNode *node2 = find_operation_node(target_key); - if (node2 != NULL) { - node2->customdata_mask |= CD_MASK_MDEFORMVERT; - } - } - } - else { - ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM); - add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); - } - } - - DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n", - pchan->name, data->tar->id.name, data->subtarget, data->rootbone); - - bPoseChannel *parchan = pchan; - /* exclude tip from chain? */ - if (!(data->flag & CONSTRAINT_IK_TIP)) { - OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, - parchan->name, DEG_OPCODE_BONE_LOCAL); - add_relation(solver_key, tip_transforms_key, - DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); - parchan = pchan->parent; - } - - root_map->add_bone(parchan->name, rootchan->name); - - OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, - parchan->name, DEG_OPCODE_BONE_READY); - add_relation(parchan_transforms_key, solver_key, - DEPSREL_TYPE_TRANSFORM, "IK Solver Owner"); - - /* Walk to the chain's root */ - //size_t segcount = 0; - int segcount = 0; - - while (parchan) { - /* Make IK-solver dependent on this bone's result, - * since it can only run after the standard results - * of the bone are know. Validate links step on the - * bone will ensure that users of this bone only - * grab the result with IK solver results... - */ - if (parchan != pchan) { - OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); - add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent"); - - OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); - } - else { - OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); - } - parchan->flag |= POSE_DONE; - - - root_map->add_bone(parchan->name, rootchan->name); - - /* continue up chain, until we reach target number of items... */ - DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name); - segcount++; - if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */ - - parchan = parchan->parent; - } - - OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); -} - -/* Spline IK Eval Steps */ -void DepsgraphRelationBuilder::build_splineik_pose(Object *ob, - bPoseChannel *pchan, - bConstraint *con, - RootPChanMap *root_map) -{ - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); - OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); - OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER); - - /* attach owner to IK Solver too - * - assume that owner is always part of chain - * - see notes on direction of rel below... - */ - add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner"); - - /* attach path dependency to solver */ - if (data->tar) { - /* TODO(sergey): For until we'll store partial matricies in the depsgraph, - * we create dependency between target object and pose eval component. - * See IK pose for a bit more information. - */ - // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry... - ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); - ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel"); - } - - pchan->flag |= POSE_DONE; - OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result"); - - root_map->add_bone(pchan->name, rootchan->name); - - /* Walk to the chain's root */ - //size_t segcount = 0; - int segcount = 0; - - for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) { - /* Make Spline IK solver dependent on this bone's result, - * since it can only run after the standard results - * of the bone are know. Validate links step on the - * bone will ensure that users of this bone only - * grab the result with IK solver results... - */ - if (parchan != pchan) { - OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); - add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update"); - - OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); - } - parchan->flag |= POSE_DONE; - - OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); - add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result"); - - root_map->add_bone(parchan->name, rootchan->name); - - /* continue up chain, until we reach target number of items... */ - segcount++; - if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */ - } - - OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); -} - -/* Pose/Armature Bones Graph */ -void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) -{ - /* Armature-Data */ - bArmature *arm = (bArmature *)ob->data; - - // TODO: selection status? - - /* attach links between pose operations */ - OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); - OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - - add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]"); - - /* Make sure pose is up-to-date with armature updates. */ - OperationKey armature_key(&arm->id, - DEPSNODE_TYPE_PARAMETERS, - DEG_OPCODE_PLACEHOLDER, - "Armature Eval"); - add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency"); - - if (needs_animdata_node(&ob->id)) { - ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION); - add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation"); - } - - /* IK Solvers... - * - These require separate processing steps are pose-level - * to be executed between chains of bones (i.e. once the - * base transforms of a bunch of bones is done) - * - * - We build relations for these before the dependencies - * between ops in the same component as it is necessary - * to check whether such bones are in the same IK chain - * (or else we get weird issues with either in-chain - * references, or with bones being parented to IK'd bones) - * - * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building - * - Animated chain-lengths are a problem... - */ - RootPChanMap root_map; - bool pose_depends_on_local_transform = false; - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { - switch (con->type) { - case CONSTRAINT_TYPE_KINEMATIC: - build_ik_pose(ob, pchan, con, &root_map); - pose_depends_on_local_transform = true; - break; - - case CONSTRAINT_TYPE_SPLINEIK: - build_splineik_pose(ob, pchan, con, &root_map); - pose_depends_on_local_transform = true; - break; - - /* Constraints which needs world's matrix for transform. - * TODO(sergey): More constraints here? - */ - case CONSTRAINT_TYPE_ROTLIKE: - case CONSTRAINT_TYPE_SIZELIKE: - case CONSTRAINT_TYPE_LOCLIKE: - case CONSTRAINT_TYPE_TRANSLIKE: - /* TODO(sergey): Add used space check. */ - pose_depends_on_local_transform = true; - break; - - default: - break; - } - } - } - //root_map.print_debug(); - - if (pose_depends_on_local_transform) { - /* TODO(sergey): Once partial updates are possible use relation between - * object transform and solver itself in it's build function. - */ - ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM); - add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms"); - } - - - /* links between operations for each bone */ - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); - OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT); - OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); - OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); - - pchan->flag &= ~POSE_DONE; - - /* pose init to bone local */ - add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link"); - - /* local to pose parenting operation */ - add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link"); - - /* parent relation */ - if (pchan->parent != NULL) { - eDepsOperation_Code parent_key_opcode; - - /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */ - if (root_map.has_common_root(pchan->name, pchan->parent->name)) { - parent_key_opcode = DEG_OPCODE_BONE_READY; - } - else { - parent_key_opcode = DEG_OPCODE_BONE_DONE; - } - - OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode); - add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]"); - } - - /* constraints */ - if (pchan->constraints.first != NULL) { - /* constraints stack and constraint dependencies */ - build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map); - - /* pose -> constraints */ - OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS); - add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack"); - - /* constraints -> ready */ - // TODO: when constraint stack is exploded, this step should occur before the first IK solver - add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready"); - } - else { - /* pose -> ready */ - add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready"); - } - - /* bone ready -> done - * NOTE: For bones without IK, this is all that's needed. - * For IK chains however, an additional rel is created from IK to done, - * with transitive reduction removing this one... - */ - add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done"); - - /* assume that all bones must be done for the pose to be ready (for deformers) */ - add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); - } -} - -void DepsgraphRelationBuilder::build_proxy_rig(Object *ob) -{ - OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); - OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; - pchan != NULL; - pchan = pchan->next) - { - OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); - OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); - OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); - add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local"); - add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready"); - add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done"); - add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done"); - } -} - /* Shapekeys */ void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc new file mode 100644 index 00000000000..3edb2b7acb7 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -0,0 +1,458 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph + */ + +#include "intern/builder/deg_builder_relations.h" + +#include +#include +#include /* required for STREQ later on. */ + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "DNA_action_types.h" +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_constraint_types.h" +#include "DNA_customdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_action.h" +#include "BKE_armature.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +} /* extern "C" */ + +#include "intern/builder/deg_builder.h" +#include "intern/builder/deg_builder_pchanmap.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "intern/depsgraph_intern.h" +#include "intern/depsgraph_types.h" + +#include "util/deg_util_foreach.h" + +namespace DEG { + +/* IK Solver Eval Steps */ +void DepsgraphRelationBuilder::build_ik_pose(Object *ob, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map) +{ + bKinematicConstraint *data = (bKinematicConstraint *)con->data; + + /* attach owner to IK Solver too + * - assume that owner is always part of chain + * - see notes on direction of rel below... + */ + bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data); + OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER); + + /* IK target */ + // XXX: this should get handled as part of the constraint code + if (data->tar != NULL) { + /* TODO(sergey): For until we'll store partial matricies in the depsgraph, + * we create dependency between target object and pose eval component. + * + * This way we ensuring the whole subtree is updated from scratch without + * need of intermediate matricies. This is an overkill, but good enough for + * testing IK solver. + */ + // FIXME: geometry targets... + ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) { + /* TODO(sergey): This is only for until granular update stores intermediate result. */ + if (data->tar != ob) { + /* different armature - can just read the results */ + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget); + add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + else { + /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */ + OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE); + add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + } + else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) { + /* vertex group target */ + /* NOTE: for now, we don't need to represent vertex groups separately... */ + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); + add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); + + if (data->tar->type == OB_MESH) { + OperationDepsNode *node2 = find_operation_node(target_key); + if (node2 != NULL) { + node2->customdata_mask |= CD_MASK_MDEFORMVERT; + } + } + } + else { + /* Standard Object Target */ + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM); + add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + + if ((data->tar == ob) && (data->subtarget[0])) { + /* Prevent target's constraints from linking to anything from same + * chain that it controls. + */ + root_map->add_bone(data->subtarget, rootchan->name); + } + } + + /* Pole Target */ + // XXX: this should get handled as part of the constraint code + if (data->poletar != NULL) { + if ((data->poletar->type == OB_ARMATURE) && (data->polesubtarget[0])) { + // XXX: same armature issues - ready vs done? + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->polesubtarget); + add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->polesubtarget[0])) { + /* vertex group target */ + /* NOTE: for now, we don't need to represent vertex groups separately... */ + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY); + add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name); + + if (data->poletar->type == OB_MESH) { + OperationDepsNode *node2 = find_operation_node(target_key); + if (node2 != NULL) { + node2->customdata_mask |= CD_MASK_MDEFORMVERT; + } + } + } + else { + ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM); + add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name); + } + } + + DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n", + pchan->name, data->tar->id.name, data->subtarget, data->rootbone); + + bPoseChannel *parchan = pchan; + /* exclude tip from chain? */ + if (!(data->flag & CONSTRAINT_IK_TIP)) { + OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, + parchan->name, DEG_OPCODE_BONE_LOCAL); + add_relation(solver_key, tip_transforms_key, + DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); + parchan = pchan->parent; + } + + root_map->add_bone(parchan->name, rootchan->name); + + OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, + parchan->name, DEG_OPCODE_BONE_READY); + add_relation(parchan_transforms_key, solver_key, + DEPSREL_TYPE_TRANSFORM, "IK Solver Owner"); + + /* Walk to the chain's root */ + //size_t segcount = 0; + int segcount = 0; + + while (parchan) { + /* Make IK-solver dependent on this bone's result, + * since it can only run after the standard results + * of the bone are know. Validate links step on the + * bone will ensure that users of this bone only + * grab the result with IK solver results... + */ + if (parchan != pchan) { + OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); + add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent"); + + OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); + } + else { + OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); + } + parchan->flag |= POSE_DONE; + + + root_map->add_bone(parchan->name, rootchan->name); + + /* continue up chain, until we reach target number of items... */ + DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name); + segcount++; + if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */ + + parchan = parchan->parent; + } + + OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); +} + +/* Spline IK Eval Steps */ +void DepsgraphRelationBuilder::build_splineik_pose(Object *ob, + bPoseChannel *pchan, + bConstraint *con, + RootPChanMap *root_map) +{ + bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; + bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data); + OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); + OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER); + + /* attach owner to IK Solver too + * - assume that owner is always part of chain + * - see notes on direction of rel below... + */ + add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner"); + + /* attach path dependency to solver */ + if (data->tar) { + /* TODO(sergey): For until we'll store partial matricies in the depsgraph, + * we create dependency between target object and pose eval component. + * See IK pose for a bit more information. + */ + // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry... + ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY); + ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, "[Curve.Path -> Spline IK] DepsRel"); + } + + pchan->flag |= POSE_DONE; + OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result"); + + root_map->add_bone(pchan->name, rootchan->name); + + /* Walk to the chain's root */ + //size_t segcount = 0; + int segcount = 0; + + for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) { + /* Make Spline IK solver dependent on this bone's result, + * since it can only run after the standard results + * of the bone are know. Validate links step on the + * bone will ensure that users of this bone only + * grab the result with IK solver results... + */ + if (parchan != pchan) { + OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY); + add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update"); + + OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); + } + parchan->flag |= POSE_DONE; + + OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); + add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result"); + + root_map->add_bone(parchan->name, rootchan->name); + + /* continue up chain, until we reach target number of items... */ + segcount++; + if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */ + } + + OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); +} + +/* Pose/Armature Bones Graph */ +void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) +{ + /* Armature-Data */ + bArmature *arm = (bArmature *)ob->data; + + // TODO: selection status? + + /* attach links between pose operations */ + OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); + OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + + add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]"); + + /* Make sure pose is up-to-date with armature updates. */ + OperationKey armature_key(&arm->id, + DEPSNODE_TYPE_PARAMETERS, + DEG_OPCODE_PLACEHOLDER, + "Armature Eval"); + add_relation(armature_key, init_key, DEPSREL_TYPE_COMPONENT_ORDER, "Data dependency"); + + if (needs_animdata_node(&ob->id)) { + ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION); + add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation"); + } + + /* IK Solvers... + * - These require separate processing steps are pose-level + * to be executed between chains of bones (i.e. once the + * base transforms of a bunch of bones is done) + * + * - We build relations for these before the dependencies + * between ops in the same component as it is necessary + * to check whether such bones are in the same IK chain + * (or else we get weird issues with either in-chain + * references, or with bones being parented to IK'd bones) + * + * Unsolved Issues: + * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building + * - Animated chain-lengths are a problem... + */ + RootPChanMap root_map; + bool pose_depends_on_local_transform = false; + for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { + switch (con->type) { + case CONSTRAINT_TYPE_KINEMATIC: + build_ik_pose(ob, pchan, con, &root_map); + pose_depends_on_local_transform = true; + break; + + case CONSTRAINT_TYPE_SPLINEIK: + build_splineik_pose(ob, pchan, con, &root_map); + pose_depends_on_local_transform = true; + break; + + /* Constraints which needs world's matrix for transform. + * TODO(sergey): More constraints here? + */ + case CONSTRAINT_TYPE_ROTLIKE: + case CONSTRAINT_TYPE_SIZELIKE: + case CONSTRAINT_TYPE_LOCLIKE: + case CONSTRAINT_TYPE_TRANSLIKE: + /* TODO(sergey): Add used space check. */ + pose_depends_on_local_transform = true; + break; + + default: + break; + } + } + } + //root_map.print_debug(); + + if (pose_depends_on_local_transform) { + /* TODO(sergey): Once partial updates are possible use relation between + * object transform and solver itself in it's build function. + */ + ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM); + add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms"); + } + + + /* links between operations for each bone */ + for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT); + OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); + OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + + pchan->flag &= ~POSE_DONE; + + /* pose init to bone local */ + add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link"); + + /* local to pose parenting operation */ + add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link"); + + /* parent relation */ + if (pchan->parent != NULL) { + eDepsOperation_Code parent_key_opcode; + + /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */ + if (root_map.has_common_root(pchan->name, pchan->parent->name)) { + parent_key_opcode = DEG_OPCODE_BONE_READY; + } + else { + parent_key_opcode = DEG_OPCODE_BONE_DONE; + } + + OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode); + add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]"); + } + + /* constraints */ + if (pchan->constraints.first != NULL) { + /* constraints stack and constraint dependencies */ + build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map); + + /* pose -> constraints */ + OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS); + add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack"); + + /* constraints -> ready */ + // TODO: when constraint stack is exploded, this step should occur before the first IK solver + add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready"); + } + else { + /* pose -> ready */ + add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready"); + } + + /* bone ready -> done + * NOTE: For bones without IK, this is all that's needed. + * For IK chains however, an additional rel is created from IK to done, + * with transitive reduction removing this one... + */ + add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done"); + + /* assume that all bones must be done for the pose to be ready (for deformers) */ + add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link"); + } +} + +void DepsgraphRelationBuilder::build_proxy_rig(Object *ob) +{ + OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); + OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); + for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; + pchan != NULL; + pchan = pchan->next) + { + OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); + OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); + OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); + add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local"); + add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready"); + add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done"); + add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done"); + } +} + +} // namespace DEG From 0a08d8c892d595eab9aaec46739ef697bcee5cef Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 17 Nov 2016 15:11:55 +0100 Subject: [PATCH 234/590] Depsgraph: Use utility macro to iterate over linked list This will be compiled into same exact code, just saves us from doing annoying type casts all over the place. --- .../intern/builder/deg_builder_nodes.cc | 73 ++++++++----------- .../intern/builder/deg_builder_nodes_rig.cc | 10 +-- .../intern/builder/deg_builder_relations.cc | 51 ++++++------- .../builder/deg_builder_relations_rig.cc | 11 +-- .../blender/depsgraph/util/deg_util_foreach.h | 5 ++ 5 files changed, 65 insertions(+), 85 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 1eaacea69eb..89b9fc98e33 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -105,6 +105,7 @@ extern "C" { #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_types.h" #include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" namespace DEG { @@ -347,7 +348,7 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) } /* scene objects */ - for (Base *base = (Base *)scene->base.first; base; base = base->next) { + LINKLIST_FOREACH (Base *, base, &scene->base) { Object *ob = base->object; /* object itself */ @@ -395,10 +396,7 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) } /* cache files */ - for (CacheFile *cachefile = static_cast(bmain->cachefiles.first); - cachefile; - cachefile = static_cast(cachefile->id.next)) - { + LINKLIST_FOREACH (CacheFile *, cachefile, &bmain->cachefiles) { build_cachefile(cachefile); } } @@ -413,10 +411,7 @@ void DepsgraphNodeBuilder::build_group(Scene *scene, } group_id->tag |= LIB_TAG_DOIT; - for (GroupObject *go = (GroupObject *)group->gobject.first; - go != NULL; - go = go->next) - { + LINKLIST_FOREACH (GroupObject *, go, &group->gobject) { build_object(scene, base, go->ob); } } @@ -433,10 +428,7 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group) DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph); /* add group objects */ - for (GroupObject *go = (GroupObject *)group->gobject.first; - go != NULL; - go = go->next) - { + LINKLIST_FOREACH (GroupObject *, go, &group->gobject) { /*Object *ob = go->ob;*/ /* Each "group object" is effectively a separate instance of the @@ -653,7 +645,7 @@ void DepsgraphNodeBuilder::build_animdata(ID *id) } /* drivers */ - for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) { + LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) { /* create driver */ build_driver(id, fcu); } @@ -766,7 +758,7 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene) /* objects - simulation participants */ if (rbw->group) { - for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) { + LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) { Object *ob = go->ob; if (!ob || (ob->type != OB_MESH)) @@ -802,7 +794,7 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) ComponentDepsNode *psys_comp = add_component_node(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES); /* particle systems */ - for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) { + LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { ParticleSettings *part = psys->part; /* particle settings */ @@ -812,7 +804,11 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob) /* this particle system */ // TODO: for now, this will just be a placeholder "ubereval" node add_operation_node(psys_comp, - DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval, _1, scene, ob, psys), + DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval, + _1, + scene, + ob, + psys), DEG_OPCODE_PSYS_EVAL, psys->name); } @@ -871,33 +867,26 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) // TODO: "Done" operation /* Modifiers */ - if (ob->modifiers.first) { - for (ModifierData *md = (ModifierData *)ob->modifiers.first; - md != NULL; - md = md->next) - { - add_operation_node(&ob->id, - DEPSNODE_TYPE_GEOMETRY, - DEPSOP_TYPE_EXEC, - function_bind(BKE_object_eval_modifier, - _1, - scene, - ob, - md), - DEG_OPCODE_GEOMETRY_MODIFIER, - md->name); - } + LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) { + add_operation_node(&ob->id, + DEPSNODE_TYPE_GEOMETRY, + DEPSOP_TYPE_EXEC, + function_bind(BKE_object_eval_modifier, + _1, + scene, + ob, + md), + DEG_OPCODE_GEOMETRY_MODIFIER, + md->name); } /* materials */ - if (ob->totcol) { - for (int a = 1; a <= ob->totcol; a++) { - Material *ma = give_current_material(ob, a); - if (ma != NULL) { - // XXX?! - ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY); - build_material(geom_node, ma); - } + for (int a = 1; a <= ob->totcol; a++) { + Material *ma = give_current_material(ob, a); + if (ma != NULL) { + // XXX?! + ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY); + build_material(geom_node, ma); } } @@ -1091,7 +1080,7 @@ void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree DEG_OPCODE_PLACEHOLDER, "Parameters Eval"); /* nodetree's nodes... */ - for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) { + LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) { ID *id = bnode->id; if (id != NULL) { short id_type = GS(id->name); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index b9c7c3c7f92..8ba41a4b4b1 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -60,6 +60,7 @@ extern "C" { #include "intern/nodes/deg_node_operation.h" #include "intern/depsgraph_types.h" #include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" namespace DEG { @@ -178,7 +179,7 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE); /* bones */ - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { /* node for bone eval */ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local @@ -212,7 +213,7 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob) * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building * - Animated chain-lengths are a problem... */ - for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { + LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) { switch (con->type) { case CONSTRAINT_TYPE_KINEMATIC: build_ik_pose(scene, ob, pchan, con); @@ -248,10 +249,7 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *ob) function_bind(BKE_pose_eval_proxy_copy, _1, ob), DEG_OPCODE_POSE_INIT); - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; - pchan != NULL; - pchan = pchan->next) - { + LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEPSOP_TYPE_INIT, NULL, DEG_OPCODE_BONE_LOCAL); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 1497a16e47f..d8477358dad 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -356,7 +356,7 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) } /* scene objects */ - for (Base *base = (Base *)scene->base.first; base; base = base->next) { + LINKLIST_FOREACH (Base *, base, &scene->base) { Object *ob = base->object; /* object itself */ @@ -429,10 +429,7 @@ void DepsgraphRelationBuilder::build_group(Main *bmain, OperationKey object_local_transform_key(&object->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL); - for (GroupObject *go = (GroupObject *)group->gobject.first; - go != NULL; - go = go->next) - { + LINKLIST_FOREACH (GroupObject *, go, &group->gobject) { if (!group_done) { build_object(bmain, scene, go->ob); } @@ -709,9 +706,10 @@ void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode ListBase targets = {NULL, NULL}; cti->get_constraint_targets(con, &targets); - for (bConstraintTarget *ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) { - if (!ct->tar) + LINKLIST_FOREACH (bConstraintTarget *, ct, &targets) { + if (ct->tar == NULL) { continue; + } if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) { /* ignore IK constraints - these are handled separately (on pose level) */ @@ -838,7 +836,7 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) } /* drivers */ - for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) { + LINKLIST_FOREACH (FCurve *, fcu, &adt->drivers) { OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, @@ -862,10 +860,7 @@ void DepsgraphRelationBuilder::build_animdata(ID *id) */ if (fcu->array_index > 0) { FCurve *fcu_prev = NULL; - for (FCurve *fcu_candidate = (FCurve *)adt->drivers.first; - fcu_candidate != NULL; - fcu_candidate = fcu_candidate->next) - { + LINKLIST_FOREACH (FCurve *, fcu_candidate, &adt->drivers) { /* Writing to different RNA paths is */ if (!STREQ(fcu_candidate->rna_path, fcu->rna_path)) { continue; @@ -1029,7 +1024,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) // XXX: the data itself could also set this, if it were to be truly initialised later? /* loop over variables to get the target relationships */ - for (DriverVar *dvar = (DriverVar *)driver->variables.first; dvar; dvar = dvar->next) { + LINKLIST_FOREACH (DriverVar *, dvar, &driver->variables) { /* only used targets */ DRIVER_TARGETS_USED_LOOPER(dvar) { @@ -1149,10 +1144,11 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) /* objects - simulation participants */ if (rbw->group) { - for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) { + LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) { Object *ob = go->ob; - if (!ob || ob->type != OB_MESH) + if (ob == NULL || ob->type != OB_MESH) { continue; + } /* hook up evaluation order... * 1) flushing rigidbody results follows base transforms being applied @@ -1200,10 +1196,11 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) /* constraints */ if (rbw->constraints) { - for (GroupObject *go = (GroupObject *)rbw->constraints->gobject.first; go; go = go->next) { + LINKLIST_FOREACH (GroupObject *, go, &rbw->constraints->gobject) { Object *ob = go->ob; - if (!ob || !ob->rigidbody_constraint) + if (ob == NULL || !ob->rigidbody_constraint) { continue; + } RigidBodyCon *rbc = ob->rigidbody_constraint; @@ -1232,7 +1229,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) DEG_OPCODE_GEOMETRY_UBEREVAL); /* particle systems */ - for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) { + LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) { ParticleSettings *part = psys->part; /* particle settings */ @@ -1263,9 +1260,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) #if 0 if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) { - ParticleTarget *pt; - - for (pt = psys->targets.first; pt; pt = pt->next) { + LINKLIST_FOREACH (ParticleTarget *, pt, &psys->targets) { if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) { node2 = dag_get_node(dag, pt->ob); dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets"); @@ -1284,7 +1279,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) } if (part->ren_as == PART_DRAW_GR && part->dup_group) { - for (go = part->dup_group->gobject.first; go; go = go->next) { + LINKLIST_FOREACH (GroupObject *, go, &part->dup_group->gobject) { node2 = dag_get_node(dag, go->ob); dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization"); } @@ -1301,11 +1296,8 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) /* boids */ if (part->boids) { - BoidRule *rule = NULL; - BoidState *state = NULL; - - for (state = (BoidState *)part->boids->states.first; state; state = state->next) { - for (rule = (BoidRule *)state->rules.first; rule; rule = rule->next) { + LINKLIST_FOREACH (BoidState *, state, &part->boids->states) { + LINKLIST_FOREACH (BoidRule *, rule, &state->rules) { Object *ruleob = NULL; if (rule->type == eBoidRuleType_Avoid) ruleob = ((BoidRuleGoalAvoid *)rule)->ob; @@ -1405,10 +1397,9 @@ void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Obje /* Modifiers */ if (ob->modifiers.first) { - ModifierData *md; OperationKey prev_mod_key; - for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) { + LINKLIST_FOREACH (ModifierData *, md, &ob->modifiers) { const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type); OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name); @@ -1643,7 +1634,7 @@ void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree) "Parameters Eval"); /* nodetree's nodes... */ - for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) { + LINKLIST_FOREACH (bNode *, bnode, &ntree->nodes) { if (bnode->id) { if (GS(bnode->id->name) == ID_MA) { build_material(owner, (Material *)bnode->id); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index 3edb2b7acb7..0fa7a5b1830 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -335,8 +335,8 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) */ RootPChanMap root_map; bool pose_depends_on_local_transform = false; - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) { + LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { + LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) { switch (con->type) { case CONSTRAINT_TYPE_KINEMATIC: build_ik_pose(ob, pchan, con, &root_map); @@ -377,7 +377,7 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) /* links between operations for each bone */ - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { + LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT); OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); @@ -441,10 +441,7 @@ void DepsgraphRelationBuilder::build_proxy_rig(Object *ob) { OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT); OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE); - for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; - pchan != NULL; - pchan = pchan->next) - { + LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL); OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY); OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE); diff --git a/source/blender/depsgraph/util/deg_util_foreach.h b/source/blender/depsgraph/util/deg_util_foreach.h index 14cf4fc11ed..87d37168d51 100644 --- a/source/blender/depsgraph/util/deg_util_foreach.h +++ b/source/blender/depsgraph/util/deg_util_foreach.h @@ -66,3 +66,8 @@ #define GSET_FOREACH_END() \ } \ } while(0) + +#define LINKLIST_FOREACH(type, var, list) \ + for (type var = (type)((list)->first); \ + var != NULL; \ + var = (type)(((Link*)(var))->next)) From 1f8762bb8e2783ec3943894eaaf2ae8df08c5e02 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 17 Nov 2016 15:29:22 +0100 Subject: [PATCH 235/590] Fix T50060: New depsgraph does not update mask animation --- .../intern/builder/deg_builder_nodes.cc | 16 ++++++++++++++-- .../intern/builder/deg_builder_nodes.h | 2 ++ .../intern/builder/deg_builder_relations.cc | 17 +++++++++++++++++ .../intern/builder/deg_builder_relations.h | 4 ++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 89b9fc98e33..011eec9e0c1 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -55,6 +55,7 @@ extern "C" { #include "DNA_key_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" +#include "DNA_mask_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" #include "DNA_node_types.h" @@ -395,10 +396,15 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) build_gpencil(scene->gpd); } - /* cache files */ + /* Cache file. */ LINKLIST_FOREACH (CacheFile *, cachefile, &bmain->cachefiles) { build_cachefile(cachefile); } + + /* Masks. */ + LINKLIST_FOREACH (Mask *, mask, &bmain->mask) { + build_mask(mask); + } } void DepsgraphNodeBuilder::build_group(Scene *scene, @@ -1211,7 +1217,6 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) ID *cache_file_id = &cache_file->id; add_component_node(cache_file_id, DEPSNODE_TYPE_CACHE); - add_operation_node(cache_file_id, DEPSNODE_TYPE_CACHE, DEPSOP_TYPE_EXEC, NULL, DEG_OPCODE_PLACEHOLDER, "Cache File Update"); @@ -1220,4 +1225,11 @@ void DepsgraphNodeBuilder::build_cachefile(CacheFile *cache_file) build_animdata(cache_file_id); } +void DepsgraphNodeBuilder::build_mask(Mask *mask) +{ + ID *mask_id = &mask->id; + add_id_node(mask_id); + build_animdata(mask_id); +} + } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 72dc73357bf..0cfddeed6ef 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -44,6 +44,7 @@ struct Group; struct Key; struct Main; struct Material; +struct Mask; struct MTex; struct bNodeTree; struct Object; @@ -154,6 +155,7 @@ struct DepsgraphNodeBuilder { void build_compositor(Scene *scene); void build_gpencil(bGPdata *gpd); void build_cachefile(CacheFile *cache_file); + void build_mask(Mask *mask); protected: Main *m_bmain; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index d8477358dad..293c14e5dde 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -55,6 +55,7 @@ extern "C" { #include "DNA_key_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" +#include "DNA_mask_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" #include "DNA_node_types.h" @@ -405,6 +406,11 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) build_gpencil(&scene->id, scene->gpd); } + /* Masks. */ + LINKLIST_FOREACH (Mask *, mask, &bmain->mask) { + build_mask(mask); + } + for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin(); it_op != m_graph->operations.end(); ++it_op) @@ -1738,4 +1744,15 @@ bool DepsgraphRelationBuilder::needs_animdata_node(ID *id) return false; } +void DepsgraphRelationBuilder::build_cachefile(CacheFile *cache_file) { + /* Animation. */ + build_animdata(&cache_file->id); +} + +void DepsgraphRelationBuilder::build_mask(Mask *mask) +{ + /* Animation. */ + build_animdata(&mask->id); +} + } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 8d8ad6772b8..1c293aa1508 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -47,6 +47,7 @@ struct Base; struct bGPdata; +struct CacheFile; struct ListBase; struct GHash; struct ID; @@ -54,6 +55,7 @@ struct FCurve; struct Group; struct Key; struct Main; +struct Mask; struct Material; struct MTex; struct bNodeTree; @@ -220,6 +222,8 @@ struct DepsgraphRelationBuilder void build_texture_stack(ID *owner, MTex **texture_stack); void build_compositor(Scene *scene); void build_gpencil(ID *owner, bGPdata *gpd); + void build_cachefile(CacheFile *cache_file); + void build_mask(Mask *mask); void add_collision_relations(const OperationKey &key, Scene *scene, Object *ob, Group *group, int layer, bool dupli, const char *name); void add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name); From 4dbd61cc64bfa5a545ce07cd6e06f1cfa2f3bd28 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 17 Nov 2016 15:38:03 +0100 Subject: [PATCH 236/590] Depsgraph: Move scene builder function to own file This way it's much easier to grasp what the graph actually contains. --- source/blender/depsgraph/CMakeLists.txt | 2 + .../intern/builder/deg_builder_nodes.cc | 88 ---------- .../intern/builder/deg_builder_nodes_rig.cc | 2 +- .../intern/builder/deg_builder_nodes_scene.cc | 154 +++++++++++++++++ .../builder/deg_builder_relations_keys.cc | 2 +- .../builder/deg_builder_relations_rig.cc | 2 +- .../builder/deg_builder_relations_scene.cc | 157 ++++++++++++++++++ 7 files changed, 316 insertions(+), 91 deletions(-) create mode 100644 source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc create mode 100644 source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index ea839d11071..e635256cda6 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -44,10 +44,12 @@ set(SRC intern/builder/deg_builder_cycle.cc intern/builder/deg_builder_nodes.cc intern/builder/deg_builder_nodes_rig.cc + intern/builder/deg_builder_nodes_scene.cc intern/builder/deg_builder_pchanmap.cc intern/builder/deg_builder_relations.cc intern/builder/deg_builder_relations_keys.cc intern/builder/deg_builder_relations_rig.cc + intern/builder/deg_builder_relations_scene.cc intern/builder/deg_builder_transitive.cc intern/debug/deg_debug_graphviz.cc intern/eval/deg_eval.cc diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 011eec9e0c1..4e6ab73b353 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -319,94 +319,6 @@ OperationDepsNode *DepsgraphNodeBuilder::find_operation_node( /* **** Build functions for entity nodes **** */ -void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) -{ - /* LIB_TAG_DOIT is used to indicate whether node for given ID was already - * created or not. This flag is being set in add_id_node(), so functions - * shouldn't bother with setting it, they only might query this flag when - * needed. - */ - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - /* XXX nested node trees are not included in tag-clearing above, - * so we need to do this manually. - */ - FOREACH_NODETREE(bmain, nodetree, id) { - if (id != (ID *)nodetree) - nodetree->id.tag &= ~LIB_TAG_DOIT; - } FOREACH_NODETREE_END - - /* scene ID block */ - add_id_node(&scene->id); - - /* timesource */ - add_time_source(NULL); - - /* build subgraph for set, and link this in... */ - // XXX: depending on how this goes, that scene itself could probably store its - // own little partial depsgraph? - if (scene->set) { - build_scene(bmain, scene->set); - } - - /* scene objects */ - LINKLIST_FOREACH (Base *, base, &scene->base) { - Object *ob = base->object; - - /* object itself */ - build_object(scene, base, ob); - - /* object that this is a proxy for */ - // XXX: the way that proxies work needs to be completely reviewed! - if (ob->proxy) { - ob->proxy->proxy_from = ob; - build_object(scene, base, ob->proxy); - } - - /* Object dupligroup. */ - if (ob->dup_group) { - build_group(scene, base, ob->dup_group); - } - } - - /* rigidbody */ - if (scene->rigidbody_world) { - build_rigidbody(scene); - } - - /* scene's animation and drivers */ - if (scene->adt) { - build_animdata(&scene->id); - } - - /* world */ - if (scene->world) { - build_world(scene->world); - } - - /* compo nodes */ - if (scene->nodetree) { - build_compositor(scene); - } - - /* sequencer */ - // XXX... - - /* grease pencil */ - if (scene->gpd) { - build_gpencil(scene->gpd); - } - - /* Cache file. */ - LINKLIST_FOREACH (CacheFile *, cachefile, &bmain->cachefiles) { - build_cachefile(cachefile); - } - - /* Masks. */ - LINKLIST_FOREACH (Mask *, mask, &bmain->mask) { - build_mask(mask); - } -} - void DepsgraphNodeBuilder::build_group(Scene *scene, Base *base, Group *group) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 8ba41a4b4b1..4a5f3dc8664 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_builder_nodes.cc +/** \file blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc * \ingroup depsgraph * * Methods for constructing depsgraph's nodes diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc new file mode 100644 index 00000000000..fb243ab0672 --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc @@ -0,0 +1,154 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph's nodes + */ + +#include "intern/builder/deg_builder_nodes.h" + +#include +#include + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_blenlib.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_main.h" +#include "BKE_node.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +} /* extern "C" */ + +#include "intern/builder/deg_builder.h" +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" +#include "intern/depsgraph_types.h" +#include "intern/depsgraph_intern.h" +#include "util/deg_util_foreach.h" + +namespace DEG { + +void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) +{ + /* LIB_TAG_DOIT is used to indicate whether node for given ID was already + * created or not. This flag is being set in add_id_node(), so functions + * shouldn't bother with setting it, they only might query this flag when + * needed. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + /* XXX nested node trees are not included in tag-clearing above, + * so we need to do this manually. + */ + FOREACH_NODETREE(bmain, nodetree, id) { + if (id != (ID *)nodetree) + nodetree->id.tag &= ~LIB_TAG_DOIT; + } FOREACH_NODETREE_END + + /* scene ID block */ + add_id_node(&scene->id); + + /* timesource */ + add_time_source(NULL); + + /* build subgraph for set, and link this in... */ + // XXX: depending on how this goes, that scene itself could probably store its + // own little partial depsgraph? + if (scene->set) { + build_scene(bmain, scene->set); + } + + /* scene objects */ + LINKLIST_FOREACH (Base *, base, &scene->base) { + Object *ob = base->object; + + /* object itself */ + build_object(scene, base, ob); + + /* object that this is a proxy for */ + // XXX: the way that proxies work needs to be completely reviewed! + if (ob->proxy) { + ob->proxy->proxy_from = ob; + build_object(scene, base, ob->proxy); + } + + /* Object dupligroup. */ + if (ob->dup_group) { + build_group(scene, base, ob->dup_group); + } + } + + /* rigidbody */ + if (scene->rigidbody_world) { + build_rigidbody(scene); + } + + /* scene's animation and drivers */ + if (scene->adt) { + build_animdata(&scene->id); + } + + /* world */ + if (scene->world) { + build_world(scene->world); + } + + /* compo nodes */ + if (scene->nodetree) { + build_compositor(scene); + } + + /* sequencer */ + // XXX... + + /* grease pencil */ + if (scene->gpd) { + build_gpencil(scene->gpd); + } + + /* Cache file. */ + LINKLIST_FOREACH (CacheFile *, cachefile, &bmain->cachefiles) { + build_cachefile(cachefile); + } + + /* Masks. */ + LINKLIST_FOREACH (Mask *, mask, &bmain->mask) { + build_mask(mask); + } +} + +} // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc index 7ada04e8f74..feae8bca303 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc +/** \file blender/depsgraph/intern/builder/deg_builder_relations_keys.cc * \ingroup depsgraph * * Methods for constructing depsgraph diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc index 0fa7a5b1830..2b4c000f483 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_builder_relations.cc +/** \file blender/depsgraph/intern/builder/deg_builder_relations_rig.cc * \ingroup depsgraph * * Methods for constructing depsgraph diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc new file mode 100644 index 00000000000..946c9da6cab --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc @@ -0,0 +1,157 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + * + * Original Author: Joshua Leung + * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013) + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/depsgraph/intern/builder/deg_builder_relations_scene.cc + * \ingroup depsgraph + * + * Methods for constructing depsgraph + */ + +#include "intern/builder/deg_builder_relations.h" + +#include +#include +#include /* required for STREQ later on. */ + +#include "MEM_guardedalloc.h" + +extern "C" { +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_main.h" +#include "BKE_node.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_build.h" +} /* extern "C" */ + +#include "intern/builder/deg_builder.h" +#include "intern/builder/deg_builder_pchanmap.h" + +#include "intern/nodes/deg_node.h" +#include "intern/nodes/deg_node_component.h" +#include "intern/nodes/deg_node_operation.h" + +#include "intern/depsgraph_intern.h" +#include "intern/depsgraph_types.h" + +#include "util/deg_util_foreach.h" + +namespace DEG { + +void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) +{ + /* LIB_TAG_DOIT is used to indicate whether node for given ID was already + * created or not. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + /* XXX nested node trees are not included in tag-clearing above, + * so we need to do this manually. + */ + FOREACH_NODETREE(bmain, nodetree, id) { + if (id != (ID *)nodetree) + nodetree->id.tag &= ~LIB_TAG_DOIT; + } FOREACH_NODETREE_END + + if (scene->set) { + // TODO: link set to scene, especially our timesource... + } + + /* scene objects */ + LINKLIST_FOREACH (Base *, base, &scene->base) { + Object *ob = base->object; + + /* object itself */ + build_object(bmain, scene, ob); + + /* object that this is a proxy for */ + if (ob->proxy) { + ob->proxy->proxy_from = ob; + build_object(bmain, scene, ob->proxy); + /* TODO(sergey): This is an inverted relation, matches old depsgraph + * behavior and need to be investigated if it still need to be inverted. + */ + ComponentKey ob_pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); + ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE); + add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy"); + } + + /* Object dupligroup. */ + if (ob->dup_group) { + build_group(bmain, scene, ob, ob->dup_group); + } + } + + /* rigidbody */ + if (scene->rigidbody_world) { + build_rigidbody(scene); + } + + /* scene's animation and drivers */ + if (scene->adt) { + build_animdata(&scene->id); + } + + /* world */ + if (scene->world) { + build_world(scene->world); + } + + /* compo nodes */ + if (scene->nodetree) { + build_compositor(scene); + } + + /* grease pencil */ + if (scene->gpd) { + build_gpencil(&scene->id, scene->gpd); + } + + /* Masks. */ + LINKLIST_FOREACH (Mask *, mask, &bmain->mask) { + build_mask(mask); + } + + for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin(); + it_op != m_graph->operations.end(); + ++it_op) + { + OperationDepsNode *node = *it_op; + IDDepsNode *id_node = node->owner->owner; + ID *id = id_node->id; + if (GS(id->name) == ID_OB) { + Object *object = (Object *)id; + object->customdata_mask |= node->customdata_mask; + } + } +} + +} // namespace DEG From d294509dd845a1cab07cccd2bdcb7797b01cae32 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 17 Nov 2016 16:37:25 +0100 Subject: [PATCH 237/590] Depsgrpah: Fix missing animation update in movie clips --- .../intern/builder/deg_builder_nodes.cc | 7 ++ .../intern/builder/deg_builder_nodes.h | 2 + .../intern/builder/deg_builder_nodes_scene.cc | 5 + .../intern/builder/deg_builder_relations.cc | 94 ++----------------- .../intern/builder/deg_builder_relations.h | 2 + .../builder/deg_builder_relations_scene.cc | 5 + 6 files changed, 28 insertions(+), 87 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 4e6ab73b353..f986d5dea46 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -58,6 +58,7 @@ extern "C" { #include "DNA_mask_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" +#include "DNA_movieclip_types.h" #include "DNA_node_types.h" #include "DNA_particle_types.h" #include "DNA_object_types.h" @@ -1144,4 +1145,10 @@ void DepsgraphNodeBuilder::build_mask(Mask *mask) build_animdata(mask_id); } +void DepsgraphNodeBuilder::build_movieclip(MovieClip *clip) { + ID *clip_id = &clip->id; + add_id_node(clip_id); + build_animdata(clip_id); +} + } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 0cfddeed6ef..9cb8bc5d45c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -46,6 +46,7 @@ struct Main; struct Material; struct Mask; struct MTex; +struct MovieClip; struct bNodeTree; struct Object; struct bPoseChannel; @@ -156,6 +157,7 @@ struct DepsgraphNodeBuilder { void build_gpencil(bGPdata *gpd); void build_cachefile(CacheFile *cache_file); void build_mask(Mask *mask); + void build_movieclip(MovieClip *clip); protected: Main *m_bmain; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc index fb243ab0672..bcd4bc51448 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_scene.cc @@ -149,6 +149,11 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) LINKLIST_FOREACH (Mask *, mask, &bmain->mask) { build_mask(mask); } + + /* Movie clips. */ + LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) { + build_movieclip(clip); + } } } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 293c14e5dde..dadb7f8917f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -58,6 +58,7 @@ extern "C" { #include "DNA_mask_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" +#include "DNA_movieclip_types.h" #include "DNA_node_types.h" #include "DNA_particle_types.h" #include "DNA_object_types.h" @@ -338,93 +339,6 @@ void DepsgraphRelationBuilder::add_forcefield_relations(const OperationKey &key, /* **** Functions to build relations between entities **** */ -void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) -{ - /* LIB_TAG_DOIT is used to indicate whether node for given ID was already - * created or not. - */ - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - /* XXX nested node trees are not included in tag-clearing above, - * so we need to do this manually. - */ - FOREACH_NODETREE(bmain, nodetree, id) { - if (id != (ID *)nodetree) - nodetree->id.tag &= ~LIB_TAG_DOIT; - } FOREACH_NODETREE_END - - if (scene->set) { - // TODO: link set to scene, especially our timesource... - } - - /* scene objects */ - LINKLIST_FOREACH (Base *, base, &scene->base) { - Object *ob = base->object; - - /* object itself */ - build_object(bmain, scene, ob); - - /* object that this is a proxy for */ - if (ob->proxy) { - ob->proxy->proxy_from = ob; - build_object(bmain, scene, ob->proxy); - /* TODO(sergey): This is an inverted relation, matches old depsgraph - * behavior and need to be investigated if it still need to be inverted. - */ - ComponentKey ob_pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE); - ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE); - add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy"); - } - - /* Object dupligroup. */ - if (ob->dup_group) { - build_group(bmain, scene, ob, ob->dup_group); - } - } - - /* rigidbody */ - if (scene->rigidbody_world) { - build_rigidbody(scene); - } - - /* scene's animation and drivers */ - if (scene->adt) { - build_animdata(&scene->id); - } - - /* world */ - if (scene->world) { - build_world(scene->world); - } - - /* compo nodes */ - if (scene->nodetree) { - build_compositor(scene); - } - - /* grease pencil */ - if (scene->gpd) { - build_gpencil(&scene->id, scene->gpd); - } - - /* Masks. */ - LINKLIST_FOREACH (Mask *, mask, &bmain->mask) { - build_mask(mask); - } - - for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin(); - it_op != m_graph->operations.end(); - ++it_op) - { - OperationDepsNode *node = *it_op; - IDDepsNode *id_node = node->owner->owner; - ID *id = id_node->id; - if (GS(id->name) == ID_OB) { - Object *object = (Object *)id; - object->customdata_mask |= node->customdata_mask; - } - } -} - void DepsgraphRelationBuilder::build_group(Main *bmain, Scene *scene, Object *object, @@ -1755,4 +1669,10 @@ void DepsgraphRelationBuilder::build_mask(Mask *mask) build_animdata(&mask->id); } +void DepsgraphRelationBuilder::build_movieclip(MovieClip *clip) +{ + /* Animation. */ + build_animdata(&clip->id); +} + } // namespace DEG diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 1c293aa1508..6e8485bee30 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -58,6 +58,7 @@ struct Main; struct Mask; struct Material; struct MTex; +struct MovieClip; struct bNodeTree; struct Object; struct bPoseChannel; @@ -224,6 +225,7 @@ struct DepsgraphRelationBuilder void build_gpencil(ID *owner, bGPdata *gpd); void build_cachefile(CacheFile *cache_file); void build_mask(Mask *mask); + void build_movieclip(MovieClip *clip); void add_collision_relations(const OperationKey &key, Scene *scene, Object *ob, Group *group, int layer, bool dupli, const char *name); void add_forcefield_relations(const OperationKey &key, Scene *scene, Object *ob, ParticleSystem *psys, EffectorWeights *eff, bool add_absorption, const char *name); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc index 946c9da6cab..6b51a957da0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_scene.cc @@ -140,6 +140,11 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) build_mask(mask); } + /* Movie clips. */ + LINKLIST_FOREACH (MovieClip *, clip, &bmain->movieclip) { + build_movieclip(clip); + } + for (Depsgraph::OperationNodes::const_iterator it_op = m_graph->operations.begin(); it_op != m_graph->operations.end(); ++it_op) From a1a8343281354d2dfb192e7b9262921ee132a287 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 18 Nov 2016 06:08:51 +1100 Subject: [PATCH 238/590] Cleanup: redundant index loop for monkey-create Also rename face vars (the faces aren't temp), and quiet old-style-definition warning. --- .../blender/blenkernel/intern/blender_undo.c | 2 +- source/blender/bmesh/intern/bmesh_queries.h | 2 +- .../blender/bmesh/operators/bmo_primitive.c | 23 +++++++++---------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index ce6d29bbfee..bc98d6f6805 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -320,7 +320,7 @@ const char *BKE_undo_get_name(int nr, bool *r_active) } /* return the name of the last item */ -const char *BKE_undo_get_name_last() +const char *BKE_undo_get_name_last(void) { UndoElem *uel = undobase.last; return (uel ? uel->name : NULL); diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h index a6a37767ee9..903fdc59cb8 100644 --- a/source/blender/bmesh/intern/bmesh_queries.h +++ b/source/blender/bmesh/intern/bmesh_queries.h @@ -135,7 +135,7 @@ BMLoop *BM_face_find_longest_loop(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNUL BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -BMFace* BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1); +BMFace *BM_face_exists(BMVert **varr, int len) ATTR_NONNULL(1); bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index 7b32921f8cf..8408169d85e 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -1174,7 +1174,7 @@ void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag) } BMIter iter2; - BMLoop* l; + BMLoop *l; int loop_index; float minx = 1.0f; @@ -1236,14 +1236,14 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) int uvi = 0; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); for (i = 0; i < monkeynf; i++) { - BMFace* temp1 = BM_face_create_quad_tri(bm, + BMFace *f_new_a = BM_face_create_quad_tri(bm, tv[monkeyf[i][0] + i - monkeyo], tv[monkeyf[i][1] + i - monkeyo], tv[monkeyf[i][2] + i - monkeyo], (monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeyf[i][3] + i - monkeyo] : NULL, NULL, BM_CREATE_NOP); - BMFace* temp2 = BM_face_create_quad_tri(bm, + BMFace *f_new_b = BM_face_create_quad_tri(bm, tv[monkeynv + monkeyf[i][2] + i - monkeyo], tv[monkeynv + monkeyf[i][1] + i - monkeyo], tv[monkeynv + monkeyf[i][0] + i - monkeyo], @@ -1252,20 +1252,19 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) /* Set the UVs here, the iteration order of the faces is not guaranteed, * so it's best to set the UVs right after the face is created. */ - if(calc_uvs) { - BMLoop* l; + if (calc_uvs) { + BMLoop *l; BMIter liter; - int loop_index; - BM_ITER_ELEM_INDEX (l, &liter, temp1, BM_LOOPS_OF_FACE, loop_index) { + BM_ITER_ELEM (l, &liter, f_new_a, BM_LOOPS_OF_FACE) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[0] = monkeyuvs[uvi*2 + 0]; - luv->uv[1] = monkeyuvs[uvi*2 + 1]; + luv->uv[0] = monkeyuvs[uvi * 2 + 0]; + luv->uv[1] = monkeyuvs[uvi * 2 + 1]; uvi++; } - BM_ITER_ELEM_INDEX (l, &liter, temp2, BM_LOOPS_OF_FACE, loop_index) { + BM_ITER_ELEM (l, &liter, f_new_b, BM_LOOPS_OF_FACE) { MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->uv[0] = monkeyuvs[uvi*2 + 0]; - luv->uv[1] = monkeyuvs[uvi*2 + 1]; + luv->uv[0] = monkeyuvs[uvi * 2 + 0]; + luv->uv[1] = monkeyuvs[uvi * 2 + 1]; uvi++; } From 46739f1e5ceee43f6e7313dcb4c21829a13789d6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 16 Nov 2016 03:22:49 +1100 Subject: [PATCH 239/590] BMesh: minor cleanup Comment & don't use dummy pointer. --- source/blender/bmesh/intern/bmesh_core.c | 4 +++- source/blender/bmesh/intern/bmesh_mods.c | 21 +++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 0cd91107171..d1178a198dc 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -2682,8 +2682,10 @@ BMVert *bmesh_urmv_loop(BMesh *bm, BMLoop *l_sep) /** * A version of #bmesh_urmv_loop that disconnects multiple loops at once. + * The loops must all share the same vertex, can be in any order + * and are all moved to use a single new vertex - which is returned. * - * Handles the task of finding fans boundaries. + * This function handles the details of finding fans boundaries. */ BMVert *bmesh_urmv_loop_multi( BMesh *bm, BMLoop **larr, int larr_len) diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 03165beb329..500da6b8788 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -346,7 +346,7 @@ BMFace *BM_face_split_n( BMLoop **r_l, BMEdge *example) { BMFace *f_new, *f_tmp; - BMLoop *l_dummy; + BMLoop *l_new; BMEdge *e, *e_new; BMVert *v_new; // BMVert *v_a = l_a->v; /* UNUSED */ @@ -368,24 +368,21 @@ BMFace *BM_face_split_n( } f_tmp = BM_face_copy(bm, bm, f, true, true); - - if (!r_l) - r_l = &l_dummy; #ifdef USE_BMESH_HOLES - f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, NULL, example, false); + f_new = bmesh_sfme(bm, f, l_a, l_b, &l_new, NULL, example, false); #else - f_new = bmesh_sfme(bm, f, l_a, l_b, r_l, example, false); + f_new = bmesh_sfme(bm, f, l_a, l_b, &l_new, example, false); #endif - /* bmesh_sfme returns in r_l a Loop for f_new going from v_a to v_b. - * The radial_next is for f and goes from v_b to v_a */ + /* bmesh_sfme returns in 'l_new' a Loop for f_new going from 'v_a' to 'v_b'. + * The radial_next is for 'f' and goes from 'v_b' to 'v_a' */ if (f_new) { - e = (*r_l)->e; + e = l_new->e; for (i = 0; i < n; i++) { v_new = bmesh_semv(bm, v_b, e, &e_new); BLI_assert(v_new != NULL); - /* bmesh_semv returns in e_new the edge going from v_new to tv */ + /* bmesh_semv returns in 'e_new' the edge going from 'v_new' to 'v_b' */ copy_v3_v3(v_new->co, cos[i]); /* interpolate the loop data for the loops with (v == v_new), using orig face */ @@ -405,6 +402,10 @@ BMFace *BM_face_split_n( BM_face_verts_kill(bm, f_tmp); + if (r_l) { + *r_l = l_new; + } + return f_new; } From 03a395766aee1b19d42360edaca2fdd03acebb7b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 18 Nov 2016 05:55:37 +1100 Subject: [PATCH 240/590] BMesh: avoid using temp array for face-area --- source/blender/bmesh/intern/bmesh_polygon.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index c500d7b9ec2..6acd790fc0c 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -225,24 +225,16 @@ void BM_face_calc_point_in_face(const BMFace *f, float r_co[3]) */ float BM_face_calc_area(const BMFace *f) { + /* inline 'area_poly_v3' logic, avoid creating a temp array */ const BMLoop *l_iter, *l_first; - float (*verts)[3] = BLI_array_alloca(verts, f->len); - float area; - unsigned int i = 0; + float n[3]; + zero_v3(n); l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - copy_v3_v3(verts[i++], l_iter->v->co); + add_newell_cross_v3_v3v3(n, l_iter->v->co, l_iter->next->v->co); } while ((l_iter = l_iter->next) != l_first); - - if (f->len == 3) { - area = area_tri_v3(verts[0], verts[1], verts[2]); - } - else { - area = area_poly_v3((const float (*)[3])verts, f->len); - } - - return area; + return len_v3(n) * 0.5f; } /** From b859fef67016cb67222380d4145781d822183e71 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 18 Nov 2016 11:55:28 +0100 Subject: [PATCH 241/590] Fix copy/paste typo in new depsgraph object geometry builder (found by coverity). --- source/blender/depsgraph/intern/builder/deg_builder_nodes.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index f986d5dea46..4de82dd63e4 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -901,7 +901,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob) build_object(scene, NULL, cu->bevobj); } if (cu->taperobj != NULL) { - build_object(scene, NULL, cu->bevobj); + build_object(scene, NULL, cu->taperobj); } if (ob->type == OB_FONT && cu->textoncurve != NULL) { build_object(scene, NULL, cu->textoncurve); From 841c4deed7a8a98761cb3f154a6581f10841eb35 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 18 Nov 2016 12:03:12 +0100 Subject: [PATCH 242/590] Fix potential NULL dereference in mesh sequence cache modifier. Reported by coverity. --- source/blender/modifiers/intern/MOD_meshsequencecache.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index d25e8e38de3..72644d56323 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -114,6 +114,10 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, mcmd->reader, ob, mcmd->object_path); + if (!mcmd->reader) { + modifier_setError(md, "Could not create Alembic reader for file %s", cache_file->filepath); + return dm; + } } DerivedMesh *result = ABC_read_mesh(mcmd->reader, From fffb1a4cfbd25cccc5df2a113907b6aa29d0f204 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Fri, 18 Nov 2016 12:37:39 +0100 Subject: [PATCH 243/590] Implement multi-view stereo support for image empties Empty images were implemented to expand (and eventually replace) the background images functionalities. If we are ever to drop background images "image empties" should support stereo/multi-view as well. --- .../blender/editors/space_view3d/drawobject.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index dd282c427f6..90d33dc5995 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -631,10 +631,20 @@ void drawaxes(const float viewmat_local[4][4], float size, char drawtype) /* Function to draw an Image on an empty Object */ -static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4]) +static void draw_empty_image(Object *ob, const short dflag, const unsigned char ob_wire_col[4], StereoViews sview) { Image *ima = ob->data; - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, ob->iuser, NULL); + ImBuf *ibuf; + ImageUser iuser = *ob->iuser; + + /* Support multi-view */ + if (ima && (sview == STEREO_RIGHT_ID)) { + iuser.multiview_eye = sview; + iuser.flag |= IMA_SHOW_STEREO; + BKE_image_multiview_index(ima, &iuser); + } + + ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); if (ibuf && (ibuf->rect == NULL) && (ibuf->rect_float != NULL)) { IMB_rect_from_float(ibuf); @@ -7708,7 +7718,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short case OB_EMPTY: if (!render_override) { if (ob->empty_drawtype == OB_EMPTY_IMAGE) { - draw_empty_image(ob, dflag, ob_wire_col); + draw_empty_image(ob, dflag, ob_wire_col, v3d->multiview_eye); } else { drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype); @@ -8488,7 +8498,7 @@ void draw_object_instance(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object case OB_EMPTY: if (ob->empty_drawtype == OB_EMPTY_IMAGE) { /* CONSTCOLOR == no wire outline */ - draw_empty_image(ob, DRAW_CONSTCOLOR, NULL); + draw_empty_image(ob, DRAW_CONSTCOLOR, NULL, v3d->multiview_eye); } else { drawaxes(rv3d->viewmatob, ob->empty_drawsize, ob->empty_drawtype); From 3fb11061bad7c76ea53925ed599ee155b0d4222f Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 18 Nov 2016 13:37:04 +0100 Subject: [PATCH 244/590] Fix T50063: Editing driver's expression eliminates "Zero" number Disables trimming of trailing zeros in case button contains an expression. --- source/blender/editors/interface/interface_anim.c | 8 +++++++- source/blender/editors/interface/interface_handlers.c | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 991cd54fecf..5da294302e9 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -99,6 +99,10 @@ void ui_but_anim_flag(uiBut *but, float cfra) } } +/** + * \a str can be NULL to only perform check if \a but has an expression at all. + * \return if button has an expression. + */ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen) { FCurve *fcu; @@ -111,7 +115,9 @@ bool ui_but_anim_expression_get(uiBut *but, char *str, size_t maxlen) driver = fcu->driver; if (driver && driver->type == DRIVER_TYPE_PYTHON) { - BLI_strncpy(str, driver->expression, maxlen); + if (str) { + BLI_strncpy(str, driver->expression, maxlen); + } return true; } } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index f3eeadb6604..fc511d61e2b 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3067,7 +3067,7 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) data->str = ui_but_string_get_dynamic(but, &data->maxlen); } - if (ui_but_is_float(but) && !ui_but_is_unit(but)) { + if (ui_but_is_float(but) && !ui_but_is_unit(but) && !ui_but_anim_expression_get(but, NULL, 0)) { BLI_str_rstrip_float_zero(data->str, '\0'); } From 8f0dc3cef6c3f3e02a0a4322cd241cf379e52552 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 18 Nov 2016 15:14:22 +0100 Subject: [PATCH 245/590] Fix T50052: bpy.utils.unregister_module doesn't unregister classes of submodules in reload scenario. reload case would clear TypeMap before unregistering addons, which made all calls to unregister_module() to do absolutely nothing. --- release/scripts/modules/bpy/utils/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index 66974dedc24..31dd836e034 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -154,8 +154,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): original_modules = _sys.modules.values() if reload_scripts: - _bpy_types.TypeMap.clear() - # just unload, don't change user defaults, this means we can sync # to reload. note that they will only actually reload of the # modification time changes. This `won't` work for packages so... @@ -163,6 +161,9 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): for module_name in [ext.module for ext in _user_preferences.addons]: _addon_utils.disable(module_name) + # *AFTER* unregistering all add-ons, otherwise all calls to unregister_module() will silently fail (do nothing). + _bpy_types.TypeMap.clear() + def register_module_call(mod): register = getattr(mod, "register", None) if register: From f6083b7bcd6901ae8d8452e34d1230afaa8da3fb Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 18 Nov 2016 15:32:50 +0100 Subject: [PATCH 246/590] Fix (unreported) bad handling of brush's fill threshold value. '1' threshold value would only allow to access a third of the basic 'color space' (from black to white, from 0.0 to 1.0 component values), when you expect it to access the whole range. Unfortunately, this needs a subversion bump to allow already defined brushes to keep exact same behavior! Also, did not change default value (0.2) for new brushes, think here keeping current one makes more sense. Thanks to @LucaRood for confirming the issue. --- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenloader/intern/versioning_270.c | 7 +++++++ source/blender/editors/sculpt_paint/paint_image_2d.c | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index baf8510dd0d..4f4787f9da5 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -28,7 +28,7 @@ * and keep comment above the defines. * Use STRINGIFY() rather than defining with quotes */ #define BLENDER_VERSION 278 -#define BLENDER_SUBVERSION 3 +#define BLENDER_SUBVERSION 4 /* Several breakages with 270, e.g. constraint deg vs rad */ #define BLENDER_MINVERSION 270 #define BLENDER_MINSUBVERSION 6 diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 8133d0496fa..25d78b73d59 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1466,4 +1466,11 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + if (!MAIN_VERSION_ATLEAST(main, 278, 4)) { + const float sqrt_3 = (float)M_SQRT3; + for (Brush *br = main->brush.first; br; br = br->id.next) { + br->fill_threshold /= sqrt_3; + } + } } diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 9474a46d716..4f93c12385d 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -1489,7 +1489,8 @@ void paint_2d_bucket_fill( float image_init[2]; int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0; float pixel_color[4]; - float threshold_sq = br->fill_threshold * br->fill_threshold; + /* We are comparing to sum of three squared values (assumed in range [0,1]), so need to multiply... */ + float threshold_sq = br->fill_threshold * br->fill_threshold * 3; UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]); From 27de0c40c594b9a2e853ec2c3c913d5a16e68e84 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 18 Nov 2016 15:49:41 +0100 Subject: [PATCH 247/590] Fix T50035: Minor interface bug: UV/ImageEditor - Paint Mode - Fill Brush Patch by @LucaRood, added some cleanup of DRAW/FILL conditions in this code too... --- release/scripts/startup/bl_ui/properties_paint_common.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index cca142b645c..09a3a19cbce 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -119,16 +119,14 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal col.label("Gradient Colors") col.template_color_ramp(brush, "gradient", expand=True) - if brush.image_tool != 'FILL': + if brush.image_tool == 'DRAW': col.label("Background Color") row = col.row(align=True) panel.prop_unified_color(row, context, brush, "secondary_color", text="") - - if brush.image_tool == 'DRAW': col.prop(brush, "gradient_stroke_mode", text="Mode") if brush.gradient_stroke_mode in {'SPACING_REPEAT', 'SPACING_CLAMP'}: col.prop(brush, "grad_spacing") - elif brush.image_tool == 'FILL': + else: # if brush.image_tool == 'FILL': col.prop(brush, "gradient_fill_mode") else: row = col.row(align=True) @@ -139,6 +137,9 @@ def brush_texpaint_common(panel, context, layout, brush, settings, projpaint=Fal panel.prop_unified_color(row, context, brush, "secondary_color", text="") row.separator() row.operator("paint.brush_colors_flip", icon='FILE_REFRESH', text="") + else: + if brush.image_tool == 'FILL' and not projpaint: + col.prop(brush, "fill_threshold") elif brush.image_tool == 'SOFTEN': col = layout.column(align=True) From ba7c11aa055f01f9a3cdcec07fea8fb7355b0e95 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 18 Nov 2016 17:47:17 +0100 Subject: [PATCH 248/590] Depsgraph: Fix residue of debug-only code --- source/blender/depsgraph/intern/builder/deg_builder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 8939e4cc93a..8a0bec5ed1d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -85,7 +85,7 @@ void deg_graph_build_finalize(Depsgraph *graph) */ GHASH_FOREACH_BEGIN(IDDepsNode *, id_node, graph->id_hash) { - if (id_node->layers == 0 || 1) { + if (id_node->layers == 0) { ID *id = id_node->id; if (GS(id->name) == ID_OB) { Object *object = (Object *)id; From 0f8e5f4fb463289be1b69b1cb5eaad495ae720c6 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Fri, 18 Nov 2016 18:23:45 +0100 Subject: [PATCH 249/590] Cycles: Different noise seed for stereoscopic rendering (Fix #T50024) Patch by Sergey Sharybin. --- intern/cycles/blender/blender_session.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index c250a54f259..171153dd440 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -32,6 +32,7 @@ #include "util_color.h" #include "util_foreach.h" #include "util_function.h" +#include "util_hash.h" #include "util_logging.h" #include "util_progress.h" #include "util_time.h" @@ -498,7 +499,8 @@ void BlenderSession::render() scene->film->tag_update(scene); scene->integrator->tag_update(scene); - for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter) { + int view_index = 0; + for(b_rr.views.begin(b_view_iter); b_view_iter != b_rr.views.end(); ++b_view_iter, ++view_index) { b_rview_name = b_view_iter->name(); /* set the current view */ @@ -514,6 +516,12 @@ void BlenderSession::render() &python_thread_state, b_rlay_name.c_str()); + /* Make sure all views have different noise patterns. - hardcoded value just to make it random */ + if(view_index != 0) { + scene->integrator->seed += hash_int_2d(scene->integrator->seed, hash_int(view_index * 0xdeadbeef)); + scene->integrator->tag_update(scene); + } + /* Update number of samples per layer. */ int samples = sync->get_layer_samples(); bool bound_samples = sync->get_layer_bound_samples(); From a90644ed19afbd84d422208772c4a970484b4248 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 18 Nov 2016 18:46:10 +0100 Subject: [PATCH 250/590] Minor debug-report tweak to autosave code. Print in cosole a warning when we skip autosave due to runnning modal op. Related to T49974. --- source/blender/windowmanager/intern/wm_files.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index fe257cc4c41..05d63869074 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1144,6 +1144,9 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w for (handler = win->modalhandlers.first; handler; handler = handler->next) { if (handler->op) { wm->autosavetimer = WM_event_add_timer(wm, NULL, TIMERAUTOSAVE, 10.0); + if (G.debug) { + printf("Skipping auto-save, modal operator running, retrying in ten seconds...\n"); + } return; } } @@ -1161,7 +1164,7 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w ED_editors_flush_edits(C, false); - /* no error reporting to console */ + /* Error reporting into console */ BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL); } /* do timer after file write, just in case file write takes a long time */ From 39be226e93c4fe133065fb56ef5191fcc2ff8c9c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 19 Nov 2016 06:26:25 +1100 Subject: [PATCH 251/590] BMesh: invalid return from BM_mesh_validate Returned value was always false, even for valid meshes, note that this is a debug-only function. Also set internal-tag cleared. --- source/blender/bmesh/intern/bmesh_mesh_validate.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_mesh_validate.c b/source/blender/bmesh/intern/bmesh_mesh_validate.c index 478194735f3..7c9ebc800a3 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_validate.c +++ b/source/blender/bmesh/intern/bmesh_mesh_validate.c @@ -64,7 +64,7 @@ bool BM_mesh_validate(BMesh *bm) int i, j; - errtot = -1; + errtot = -1; /* 'ERRMSG' next line will set at zero */ fprintf(stderr, "\n"); ERRMSG("This is a debugging function and not intended for general use, running slow test!"); @@ -187,15 +187,22 @@ bool BM_mesh_validate(BMesh *bm) } while ((l_iter = l_iter->next) != l_first); if (j != f->len) { - ERRMSG("face %d: has length if %d but should be %d", i, f->len, j); + ERRMSG("face %d: has length of %d but should be %d", i, f->len, j); } + + /* leave elements un-tagged, not essential but nice to avoid unintended dirty tag use later. */ + do { + BM_elem_flag_disable(l_iter, BM_ELEM_INTERNAL_TAG); + BM_elem_flag_disable(l_iter->v, BM_ELEM_INTERNAL_TAG); + BM_elem_flag_disable(l_iter->e, BM_ELEM_INTERNAL_TAG); + } while ((l_iter = l_iter->next) != l_first); } BLI_edgehash_free(edge_hash, NULL); + const bool is_valid = (errtot == 0); ERRMSG("Finished - errors %d", errtot); - - return (errtot == 0); + return is_valid; } From 40990d52d143b1698580986405134429b5a4899f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 19 Nov 2016 06:57:13 +1100 Subject: [PATCH 252/590] Add Torus: avoid excessive attr access --- .../startup/bl_operators/add_mesh_torus.py | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index 303a8b01192..f12e7484e64 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -84,26 +84,27 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg): def add_uvs(mesh, minor_seg, major_seg): mesh.uv_textures.new() - uv_layer = mesh.uv_layers.active - u_step = 1.0/major_seg - v_step = 1.0/minor_seg + uv_data = mesh.uv_layers.active.data + polygons = mesh.polygons + u_step = 1.0 / major_seg + v_step = 1.0 / minor_seg vertex_index = 0 u = 0.5 for major_index in range(major_seg): v = 0.5 for minor_index in range(minor_seg): - loops = mesh.polygons[vertex_index].loop_indices - if minor_index == minor_seg-1 and major_index == 0: - uv_layer.data[loops[1]].uv = (u, v) - uv_layer.data[loops[2]].uv = (u + u_step, v) - uv_layer.data[loops[0]].uv = (u, v + v_step) - uv_layer.data[loops[3]].uv = (u + u_step, v + v_step) + loops = polygons[vertex_index].loop_indices + if minor_index == minor_seg - 1 and major_index == 0: + uv_data[loops[1]].uv = (u, v) + uv_data[loops[2]].uv = (u + u_step, v) + uv_data[loops[0]].uv = (u, v + v_step) + uv_data[loops[3]].uv = (u + u_step, v + v_step) else: - uv_layer.data[loops[0]].uv = (u, v) - uv_layer.data[loops[1]].uv = (u + u_step, v) - uv_layer.data[loops[3]].uv = (u, v + v_step) - uv_layer.data[loops[2]].uv = (u + u_step, v + v_step) + uv_data[loops[0]].uv = (u, v) + uv_data[loops[1]].uv = (u + u_step, v) + uv_data[loops[3]].uv = (u, v + v_step) + uv_data[loops[2]].uv = (u + u_step, v + v_step) v = (v + v_step) % 1.0 vertex_index += 1 u = (u + u_step) % 1.0 From b8710e1468a3ce523c35260e47332393e2b967a3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 19 Nov 2016 06:57:55 +1100 Subject: [PATCH 253/590] Fix UV layer bug in object_utils.object_data_add() Adding a torus in edit-mode, with 'Generate UVs' for example would either create another UV layer with the default name or switch to the default UV layer name if it exists. Now use the existing UV layer if present. --- release/scripts/modules/bpy_extras/object_utils.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/release/scripts/modules/bpy_extras/object_utils.py b/release/scripts/modules/bpy_extras/object_utils.py index 88cd7398fe0..c48f03c133d 100644 --- a/release/scripts/modules/bpy_extras/object_utils.py +++ b/release/scripts/modules/bpy_extras/object_utils.py @@ -189,6 +189,14 @@ def object_data_add(context, obdata, operator=None, use_active_layer=True, name= scene.update() # apply location # scene.objects.active = obj_new + # Match up UV layers, this is needed so adding an object with UV's + # doesn't create new layers when there happens to be a naming mis-match. + uv_new = obdata.uv_layers.active + if uv_new is not None: + uv_act = obj_act.data.uv_layers.active + if uv_act is not None: + uv_new.name = uv_act.name + bpy.ops.object.join() # join into the active. if obdata: bpy.data.meshes.remove(obdata) From b6c0edcb0932d7001968dccfa94fce4e71876b06 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 18 Nov 2016 22:34:04 +0100 Subject: [PATCH 254/590] Fix T50071: Radience HDR fomat does not support alpha at all. --- source/blender/blenkernel/intern/image.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index df3a7630bb0..c9bad2160ff 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1244,7 +1244,6 @@ char BKE_imtype_valid_channels(const char imtype, bool write_file) case R_IMF_IMTYPE_RAWTGA: case R_IMF_IMTYPE_IRIS: case R_IMF_IMTYPE_PNG: - case R_IMF_IMTYPE_RADHDR: case R_IMF_IMTYPE_TIFF: case R_IMF_IMTYPE_OPENEXR: case R_IMF_IMTYPE_MULTILAYER: From 884693b42ae1d630349727519f6868b94f448643 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 18 Nov 2016 22:36:52 +0100 Subject: [PATCH 255/590] Fix Node space ID remap callback not handling node trees. Yep. Kinda ridiculous, but forgot to handle the very node trees data-blocks in that editor! Related (but not fixing) to T49991. --- .../blender/editors/space_node/space_node.c | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 4ef703c8994..bbdf6feef01 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -855,6 +855,42 @@ static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID id_us_plus(new_id); } } + else if (GS(old_id->name) == ID_NT) { + bNodeTreePath *path, *path_next; + + for (path = snode->treepath.first; path; path = path->next) { + if ((ID *)path->nodetree == old_id) { + path->nodetree = (bNodeTree *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + if (path == snode->treepath.first) { + /* first nodetree in path is same as snode->nodetree */ + snode->nodetree = path->nodetree; + } + if (path->nodetree == NULL) { + break; + } + } + + /* remaining path entries are invalid, remove */ + for (; path; path = path_next) { + path_next = path->next; + + BLI_remlink(&snode->treepath, path); + MEM_freeN(path); + } + + /* edittree is just the last in the path, + * set this directly since the path may have been shortened above */ + if (snode->treepath.last) { + path = snode->treepath.last; + snode->edittree = path->nodetree; + } + else { + snode->edittree = NULL; + } + } } /* only called once, from space/spacetypes.c */ From 5a6534a5bb62492af2bae8cff0880c3da19ac4d6 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 18 Nov 2016 22:41:56 +0100 Subject: [PATCH 256/590] Fix forward-compat Nodes write code being executed also for undo steps writing. Forward compatibility code should never, ever be run during undo saving. Note: related to T49991 (but does not fix it either, crash now happens when doing a real file save...). --- source/blender/blenloader/intern/writefile.c | 26 +++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index d104fc85eb7..ad1999c0bc7 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -914,20 +914,22 @@ static void write_curvemapping(WriteData *wd, CurveMapping *cumap) static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *node, bNodeSocket *sock) { #ifdef USE_NODE_COMPAT_CUSTOMNODES - /* forward compatibility code, so older blenders still open */ - sock->stack_type = 1; + /* forward compatibility code, so older blenders still open (not for undo) */ + if (wd->current == NULL) { + sock->stack_type = 1; - if (node->type == NODE_GROUP) { - bNodeTree *ngroup = (bNodeTree *)node->id; - if (ngroup) { - /* for node groups: look up the deprecated groupsock pointer */ - sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier); - BLI_assert(sock->groupsock != NULL); + if (node->type == NODE_GROUP) { + bNodeTree *ngroup = (bNodeTree *)node->id; + if (ngroup) { + /* for node groups: look up the deprecated groupsock pointer */ + sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier); + BLI_assert(sock->groupsock != NULL); - /* node group sockets now use the generic identifier string to verify group nodes, - * old blender uses the own_index. - */ - sock->own_index = sock->groupsock->own_index; + /* node group sockets now use the generic identifier string to verify group nodes, + * old blender uses the own_index. + */ + sock->own_index = sock->groupsock->own_index; + } } } #endif From bd6a9fd7341f5573451abe5924df94a06f9f168b Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 19 Nov 2016 12:16:14 +0100 Subject: [PATCH 257/590] Fix (unreported) nodeRemoveAllSockets() not clearing inputs/outputs sockets lists. Nice crasher (though seems to not be much used so far)! Related to T49991. --- source/blender/blenkernel/intern/node.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 2b88ae4823c..a227228ceb5 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -736,11 +736,14 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) node_socket_free(ntree, sock, node); MEM_freeN(sock); } + BLI_listbase_clear(&node->inputs); + for (sock = node->outputs.first; sock; sock = sock_next) { sock_next = sock->next; node_socket_free(ntree, sock, node); MEM_freeN(sock); } + BLI_listbase_clear(&node->outputs); node->update |= NODE_UPDATE; } From fa6a62fac2a394e66e779c0dc4aef0f9d840ab87 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 19 Nov 2016 12:18:32 +0100 Subject: [PATCH 258/590] Fix NodeGroup generic verify function crashing if node's ID pointer is NULL. Another nice crasher - in this case, we just want to nuke all sockets... Related to T49991. --- source/blender/nodes/intern/node_common.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c index fbc036435f0..736f17f1d70 100644 --- a/source/blender/nodes/intern/node_common.c +++ b/source/blender/nodes/intern/node_common.c @@ -178,9 +178,14 @@ void node_group_verify(struct bNodeTree *ntree, struct bNode *node, struct ID *i { /* check inputs and outputs, and remove or insert them */ if (id == node->id) { - bNodeTree *ngroup = (bNodeTree *)node->id; - group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN); - group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT); + if (id == NULL) { + nodeRemoveAllSockets(ntree, node); + } + else { + bNodeTree *ngroup = (bNodeTree *)node->id; + group_verify_socket_list(ntree, node, &ngroup->inputs, &node->inputs, SOCK_IN); + group_verify_socket_list(ntree, node, &ngroup->outputs, &node->outputs, SOCK_OUT); + } } } From 369872a2c50e95eee822512018cc282ef5fcfdd1 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 19 Nov 2016 12:20:29 +0100 Subject: [PATCH 259/590] Fix T49991: reloading librairies doesn't update node groups. We need to check node tree links are still valid, after we remapped some NodeGroup. Note: In fact, we have to run that for *all* ID types, since nodes may use any kind of data-block (in theory)... :/ --- source/blender/blenkernel/intern/library_remap.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 40441034171..62f59832481 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -378,6 +378,18 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), O } } +static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id) +{ + /* Verify all nodetree user nodes. */ + ntreeVerifyNodes(bmain, new_id); + + /* Update node trees as necessary. */ + FOREACH_NODETREE(bmain, ntree, id) { + /* make an update call for the tree */ + ntreeUpdateTree(bmain, ntree); + } FOREACH_NODETREE_END +} + /** * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks). * @@ -551,6 +563,8 @@ void BKE_libblock_remap_locked( default: break; } + /* Node trees may virtually use any kind of data-block... */ + libblock_remap_data_postprocess_nodetree_update(bmain, new_id); /* Full rebuild of DAG! */ DAG_relations_tag_update(bmain); From 8c93178c964bac93684fe7ed5d9c4a7c4d9e572a Mon Sep 17 00:00:00 2001 From: Luca Rood Date: Sat, 19 Nov 2016 19:18:10 +0100 Subject: [PATCH 260/590] Fix T50078: Vertex Groups not copied over when making proxy. Reviewers: mont29 Reviewed By: mont29 Differential Revision: https://developer.blender.org/D2368 --- source/blender/blenkernel/intern/object.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 5bcf31ba45b..4489ca907f6 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1347,7 +1347,10 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) ob->type = target->type; ob->data = target->data; id_us_plus((ID *)ob->data); /* ensures lib data becomes LIB_TAG_EXTERN */ - + + /* copy vertex groups */ + defgroup_copy_list(&ob->defbase, &target->defbase); + /* copy material and index information */ ob->actcol = ob->totcol = 0; if (ob->mat) MEM_freeN(ob->mat); From dd82d70bc5eade5dddd6d20ef81eb81ba43463da Mon Sep 17 00:00:00 2001 From: Antonioya Date: Sat, 19 Nov 2016 22:41:37 +0100 Subject: [PATCH 261/590] Fix T50081: Grease pencil parented rotation problem When the parent object matrix change after the layer was parented, the inverse matrix for strokes must be updated when editing strokes or the transformations will be wrong. --- source/blender/editors/gpencil/gpencil_edit.c | 6 ++- .../blender/editors/gpencil/gpencil_utils.c | 40 +++++++++++++++++++ source/blender/editors/include/ED_gpencil.h | 2 + 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 12d837dfb29..15f65b394a9 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -96,7 +96,11 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* Just toggle editmode flag... */ gpd->flag ^= GP_DATA_STROKE_EDITMODE; - + /* recalculate parent matrix */ + if (gpd->flag & GP_DATA_STROKE_EDITMODE) { + ED_gpencil_reset_layers_parent(gpd); + } + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 564ba639983..8073b13ba10 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -997,6 +997,46 @@ void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4]) } } +/* reset parent matrix for all layers */ +void ED_gpencil_reset_layers_parent(bGPdata *gpd) +{ + bGPDspoint *pt; + int i; + float diff_mat[4][4]; + float cur_mat[4][4]; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->parent != NULL) { + /* calculate new matrix */ + if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) { + invert_m4_m4(cur_mat, gpl->parent->obmat); + } + else if (gpl->partype == PARBONE) { + bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr); + if (pchan) { + float tmp_mat[4][4]; + mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat); + invert_m4_m4(cur_mat, tmp_mat); + } + } + + /* only redo if any change */ + if (!equals_m4m4(gpl->inverse, cur_mat)) { + /* first apply current transformation to all strokes */ + ED_gpencil_parent_location(gpl, diff_mat); + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + mul_m4_v3(diff_mat, &pt->x); + } + } + } + /* set new parent matrix */ + copy_m4_m4(gpl->inverse, cur_mat); + } + } + } +} /* ******************************************************** */ bool ED_gpencil_stroke_minmax( const bGPDstroke *gps, const bool use_select, diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index bc93b5622cb..74d9ad0886d 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -185,6 +185,8 @@ int ED_undo_gpencil_step(struct bContext *C, int step, const char *name); /* get difference matrix using parent */ void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]); +/* reset parent matrix for all layers */ +void ED_gpencil_reset_layers_parent(struct bGPdata *gpd); #endif /* __ED_GPENCIL_H__ */ From 53a1b48321b73b7b6dd3e8fde5f1b58decbf20d7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 20 Nov 2016 08:58:41 +1100 Subject: [PATCH 262/590] GHOST/X11: Incorrect WM_STATE access This worked by accident because of struct padding, treat state as a CARD32 as documented. Matches wine-x11 usage. --- intern/ghost/intern/GHOST_WindowX11.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index ec2b65e67d0..47fbe1256b1 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -861,24 +861,32 @@ void GHOST_WindowX11::icccmSetState(int state) int GHOST_WindowX11::icccmGetState(void) const { - Atom *prop_ret; + struct { + CARD32 state; + XID icon; + } *prop_ret; unsigned long bytes_after, num_ret; Atom type_ret; - int format_ret, st; + int ret, format_ret; + CARD32 st; prop_ret = NULL; - st = XGetWindowProperty( + ret = XGetWindowProperty( m_display, m_window, m_system->m_atom.WM_STATE, 0, 2, False, m_system->m_atom.WM_STATE, &type_ret, &format_ret, &num_ret, &bytes_after, ((unsigned char **)&prop_ret)); - if ((st == Success) && (prop_ret) && (num_ret == 2)) - st = prop_ret[0]; - else + if ((ret == Success) && (prop_ret != NULL) && (num_ret == 2)) { + st = prop_ret->state; + } + else { st = NormalState; + } - if (prop_ret) + if (prop_ret) { XFree(prop_ret); - return (st); + } + + return st; } void GHOST_WindowX11::netwmMaximized(bool set) From 2c26a7b71e05bdbb4509f55ceba79f167b323ed7 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 20 Nov 2016 09:11:26 +1100 Subject: [PATCH 263/590] Cleanup: harmless mistake in rangetree --- extern/rangetree/intern/range_tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/rangetree/intern/range_tree.c b/extern/rangetree/intern/range_tree.c index 4c81036dceb..77496e32fa3 100644 --- a/extern/rangetree/intern/range_tree.c +++ b/extern/rangetree/intern/range_tree.c @@ -808,7 +808,7 @@ bool range_tree_uint_retake(RangeTreeUInt *rt, const uint value) uint range_tree_uint_take_any(RangeTreeUInt *rt) { - Node *node = node = rt->list.first; + Node *node = rt->list.first; uint value = node->min; if (value == node->max) { rt_node_remove(rt, node); From e8641d44740ed0e2c4a2a7bc4fb61aacec203c48 Mon Sep 17 00:00:00 2001 From: Carlo Andreacchio Date: Sun, 13 Nov 2016 00:16:50 +0100 Subject: [PATCH 264/590] Cycles: distance culling for objects. This can be used together with camera culling to keep nearby objects visible in reflections, using a minimum distance within which objects are visible. It is also useful to cull small objects far from the camera. Reviewed By: brecht Differential Revision: https://developer.blender.org/D2332 --- intern/cycles/blender/addon/properties.py | 19 ++++++++ intern/cycles/blender/addon/ui.py | 17 ++++--- intern/cycles/blender/blender_object.cpp | 55 +++++++++++++++++++++-- intern/cycles/blender/blender_sync.h | 2 + 4 files changed, 85 insertions(+), 8 deletions(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index a7dff1f79f3..575a3f9b6c5 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -566,6 +566,19 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): min=0.0, max=5.0 ) + cls.use_distance_cull = BoolProperty( + name="Use Distance Cull", + description="Allow objects to be culled based on the distance from camera", + default=False, + ) + + cls.distance_cull_margin = FloatProperty( + name="Cull Distance", + description="Cull objects which are further away from camera then this distance", + default=50, + min=0.0 + ) + cls.motion_blur_position = EnumProperty( name="Motion Blur Position", default='CENTER', @@ -1016,6 +1029,12 @@ class CyclesObjectSettings(bpy.types.PropertyGroup): default=False, ) + cls.use_distance_cull = BoolProperty( + name="Use Distance Cull", + description="Allow this object and its duplicators to be culled by distance from camera", + default=False, + ) + cls.use_adaptive_subdivision = BoolProperty( name="Use Adaptive Subdivision", description="Use adaptive render time subdivision", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index f435af178b5..6296d6787e5 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -769,6 +769,8 @@ class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel): row = col.row() row.active = scene.render.use_simplify and cscene.use_camera_cull row.prop(cob, "use_camera_cull") + row.active = scene.render.use_simplify and cscene.use_distance_cull + row.prop(cob, "use_distance_cull") class CYCLES_OT_use_shading_nodes(Operator): @@ -1597,12 +1599,17 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel): col.prop(rd, "simplify_subdivision_render", text="Subdivision") col.prop(rd, "simplify_child_particles_render", text="Child Particles") - col = layout.column() - col.prop(cscene, "use_camera_cull") - subsub = col.column() - subsub.active = cscene.use_camera_cull - subsub.prop(cscene, "camera_cull_margin") + layout.separator() + split = layout.split() + + col = split.column() + col.prop(cscene, "use_camera_cull") + col.prop(cscene, "camera_cull_margin", text="Margin") + + col = split.column() + col.prop(cscene, "use_distance_cull") + col.prop(cscene, "distance_cull_margin", text="Distance") def draw_device(self, context): scene = context.scene diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 0d961c5bf88..84701a22d0a 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -284,6 +284,31 @@ static bool object_boundbox_clip(Scene *scene, return true; } +static bool object_distance_clip(Scene *scene, + BL::Object& b_ob, + Transform& tfm, + float margin) +{ + BL::Array boundbox = b_ob.bound_box(); + float3 camera_position = transform_get_column(&scene->camera->matrix, 3); + + float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), + bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + /* Find min & max points for x & y & z on bounding box */ + for(int i = 0; i < 8; ++i) { + float3 p = make_float3(boundbox[3 * i + 0], + boundbox[3 * i + 1], + boundbox[3 * i + 2]); + p = transform_point(&tfm, p); + bb_min = min(bb_min, p); + bb_max = max(bb_max, p); + } + + float3 closest_point = max(min(bb_max,camera_position),bb_min); + return (len_squared(camera_position - closest_point) > margin * margin); +} + Object *BlenderSync::sync_object(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject& b_dupli_ob, @@ -292,7 +317,9 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, float motion_time, bool hide_tris, bool use_camera_cull, + bool use_distance_cull, float camera_cull_margin, + float distance_cull_margin, bool *use_portal) { BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent); @@ -311,8 +338,14 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, if(!object_is_mesh(b_ob)) return NULL; - /* Perform camera space culling. */ - if(use_camera_cull && object_boundbox_clip(scene, b_ob, tfm, camera_cull_margin)) { + /* Perform object culling. */ + bool camera_culled = use_camera_cull && object_boundbox_clip(scene, b_ob, tfm, camera_cull_margin); + bool distance_culled = use_distance_cull && object_distance_clip(scene, b_ob, tfm, distance_cull_margin); + + if ((camera_culled && distance_culled) || + (camera_culled && !use_distance_cull) || + (distance_culled && !use_camera_cull)) + { return NULL; } @@ -549,15 +582,26 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) } bool allow_camera_cull = false; + bool allow_distance_cull = false; float camera_cull_margin = 0.0f; + float distance_cull_margin = 0.0f; if(b_scene.render().use_simplify()) { PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); allow_camera_cull = scene->camera->type != CAMERA_PANORAMA && !b_scene.render().use_multiview() && get_boolean(cscene, "use_camera_cull"); + allow_distance_cull = scene->camera->type != CAMERA_PANORAMA && + !b_scene.render().use_multiview() && + get_boolean(cscene, "use_distance_cull"); if(allow_camera_cull) { camera_cull_margin = get_float(cscene, "camera_cull_margin"); } + if(allow_distance_cull) { + distance_cull_margin = get_float(cscene, "distance_cull_margin"); + if (distance_cull_margin == 0.0f) { + allow_distance_cull = false; + } + } } /* object loop */ @@ -592,7 +636,8 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); bool use_camera_cull = allow_camera_cull && get_boolean(cobject, "use_camera_cull"); - if(use_camera_cull) { + bool use_distance_cull = allow_distance_cull && get_boolean(cobject, "use_distance_cull"); + if(use_camera_cull || use_distance_cull) { /* Need to have proper projection matrix. */ scene->camera->update(); } @@ -623,7 +668,9 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) motion_time, hide_tris, use_camera_cull, + use_distance_cull, camera_cull_margin, + distance_cull_margin, &use_portal); /* sync possible particle data, note particle_id @@ -653,7 +700,9 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) motion_time, hide_tris, use_camera_cull, + use_distance_cull, camera_cull_margin, + distance_cull_margin, &use_portal); } } diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index 9a01b4f2b6e..aa6b0d66e80 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -123,7 +123,9 @@ private: float motion_time, bool hide_tris, bool use_camera_cull, + bool use_distance_cull, float camera_cull_margin, + float distance_cull_margin, bool *use_portal); void sync_light(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], From aea4ed00d5a7fe661f12fbe1a16ad6574d9be8ea Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 13 Nov 2016 00:45:16 +0100 Subject: [PATCH 265/590] Cycles: refactor culling code into utility class. --- intern/cycles/blender/blender_object.cpp | 271 +++++++++++++---------- intern/cycles/blender/blender_sync.h | 6 +- 2 files changed, 150 insertions(+), 127 deletions(-) diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 84701a22d0a..681a22e1f07 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -88,6 +88,143 @@ static uint object_ray_visibility(BL::Object& b_ob) return flag; } +/* Culling */ + +class BlenderObjectCulling +{ +public: + BlenderObjectCulling(Scene *scene, BL::Scene& b_scene) + : use_scene_camera_cull(false), + use_camera_cull(false), + camera_cull_margin(0.0f), + use_scene_distance_cull(false), + use_distance_cull(false), + distance_cull_margin(0.0f) + { + if(b_scene.render().use_simplify()) { + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + + use_scene_camera_cull = scene->camera->type != CAMERA_PANORAMA && + !b_scene.render().use_multiview() && + get_boolean(cscene, "use_camera_cull"); + use_scene_distance_cull = scene->camera->type != CAMERA_PANORAMA && + !b_scene.render().use_multiview() && + get_boolean(cscene, "use_distance_cull"); + + camera_cull_margin = get_float(cscene, "camera_cull_margin"); + distance_cull_margin = get_float(cscene, "distance_cull_margin"); + + if (distance_cull_margin == 0.0f) { + use_scene_distance_cull = false; + } + } + } + + void init_object(Scene *scene, BL::Object& b_ob) + { + if(!use_scene_camera_cull && !use_scene_distance_cull) { + return; + } + + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + + use_camera_cull = use_scene_camera_cull && get_boolean(cobject, "use_camera_cull"); + use_distance_cull = use_scene_distance_cull && get_boolean(cobject, "use_distance_cull"); + + if(use_camera_cull || use_distance_cull) { + /* Need to have proper projection matrix. */ + scene->camera->update(); + } + } + + bool test(Scene *scene, BL::Object& b_ob, Transform& tfm) + { + if(!use_camera_cull && !use_distance_cull) { + return false; + } + + /* Compute world space bounding box corners. */ + float3 bb[8]; + BL::Array boundbox = b_ob.bound_box(); + for(int i = 0; i < 8; ++i) { + float3 p = make_float3(boundbox[3 * i + 0], + boundbox[3 * i + 1], + boundbox[3 * i + 2]); + bb[i] = transform_point(&tfm, p); + } + + bool camera_culled = use_camera_cull && test_camera(scene, bb); + bool distance_culled = use_distance_cull && test_distance(scene, bb); + + return ((camera_culled && distance_culled) || + (camera_culled && !use_distance_cull) || + (distance_culled && !use_camera_cull)); + } + +private: + /* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order + * to reduce number of objects which are wrongly considered visible. + */ + bool test_camera(Scene *scene, float3 bb[8]) + { + Camera *cam = scene->camera; + Transform& worldtondc = cam->worldtondc; + float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), + bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + bool all_behind = true; + for(int i = 0; i < 8; ++i) { + float3 p = bb[i]; + float4 b = make_float4(p.x, p.y, p.z, 1.0f); + float4 c = make_float4(dot(worldtondc.x, b), + dot(worldtondc.y, b), + dot(worldtondc.z, b), + dot(worldtondc.w, b)); + p = float4_to_float3(c / c.w); + if(c.z < 0.0f) { + p.x = 1.0f - p.x; + p.y = 1.0f - p.y; + } + if(c.z >= -camera_cull_margin) { + all_behind = false; + } + bb_min = min(bb_min, p); + bb_max = max(bb_max, p); + } + if(all_behind) { + return true; + } + return (bb_min.x >= 1.0f + camera_cull_margin || + bb_min.y >= 1.0f + camera_cull_margin || + bb_max.x <= -camera_cull_margin || + bb_max.y <= -camera_cull_margin); + } + + bool test_distance(Scene *scene, float3 bb[8]) + { + float3 camera_position = transform_get_column(&scene->camera->matrix, 3); + float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), + bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + /* Find min & max points for x & y & z on bounding box */ + for(int i = 0; i < 8; ++i) { + float3 p = bb[i]; + bb_min = min(bb_min, p); + bb_max = max(bb_max, p); + } + + float3 closest_point = max(min(bb_max,camera_position),bb_min); + return (len_squared(camera_position - closest_point) > + distance_cull_margin * distance_cull_margin); + } + + bool use_scene_camera_cull; + bool use_camera_cull; + float camera_cull_margin; + bool use_scene_distance_cull; + bool use_distance_cull; + float distance_cull_margin; +}; + /* Light */ void BlenderSync::sync_light(BL::Object& b_parent, @@ -235,80 +372,6 @@ void BlenderSync::sync_background_light(bool use_portal) /* Object */ -/* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order - * to reduce number of objects which are wrongly considered visible. - */ -static bool object_boundbox_clip(Scene *scene, - BL::Object& b_ob, - Transform& tfm, - float margin) -{ - Camera *cam = scene->camera; - Transform& worldtondc = cam->worldtondc; - BL::Array boundbox = b_ob.bound_box(); - float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), - bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - bool all_behind = true; - for(int i = 0; i < 8; ++i) { - float3 p = make_float3(boundbox[3 * i + 0], - boundbox[3 * i + 1], - boundbox[3 * i + 2]); - p = transform_point(&tfm, p); - - float4 b = make_float4(p.x, p.y, p.z, 1.0f); - float4 c = make_float4(dot(worldtondc.x, b), - dot(worldtondc.y, b), - dot(worldtondc.z, b), - dot(worldtondc.w, b)); - p = float4_to_float3(c / c.w); - if(c.z < 0.0f) { - p.x = 1.0f - p.x; - p.y = 1.0f - p.y; - } - if(c.z >= -margin) { - all_behind = false; - } - bb_min = min(bb_min, p); - bb_max = max(bb_max, p); - } - if(!all_behind) { - if(bb_min.x >= 1.0f + margin || - bb_min.y >= 1.0f + margin || - bb_max.x <= -margin || - bb_max.y <= -margin) - { - return true; - } - return false; - } - return true; -} - -static bool object_distance_clip(Scene *scene, - BL::Object& b_ob, - Transform& tfm, - float margin) -{ - BL::Array boundbox = b_ob.bound_box(); - float3 camera_position = transform_get_column(&scene->camera->matrix, 3); - - float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), - bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - - /* Find min & max points for x & y & z on bounding box */ - for(int i = 0; i < 8; ++i) { - float3 p = make_float3(boundbox[3 * i + 0], - boundbox[3 * i + 1], - boundbox[3 * i + 2]); - p = transform_point(&tfm, p); - bb_min = min(bb_min, p); - bb_max = max(bb_max, p); - } - - float3 closest_point = max(min(bb_max,camera_position),bb_min); - return (len_squared(camera_position - closest_point) > margin * margin); -} - Object *BlenderSync::sync_object(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], BL::DupliObject& b_dupli_ob, @@ -316,10 +379,7 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, uint layer_flag, float motion_time, bool hide_tris, - bool use_camera_cull, - bool use_distance_cull, - float camera_cull_margin, - float distance_cull_margin, + BlenderObjectCulling& culling, bool *use_portal) { BL::Object b_ob = (b_dupli_ob ? b_dupli_ob.object() : b_parent); @@ -335,17 +395,12 @@ Object *BlenderSync::sync_object(BL::Object& b_parent, } /* only interested in object that we can create meshes from */ - if(!object_is_mesh(b_ob)) + if(!object_is_mesh(b_ob)) { return NULL; + } /* Perform object culling. */ - bool camera_culled = use_camera_cull && object_boundbox_clip(scene, b_ob, tfm, camera_cull_margin); - bool distance_culled = use_distance_cull && object_distance_clip(scene, b_ob, tfm, distance_cull_margin); - - if ((camera_culled && distance_culled) || - (camera_culled && !use_distance_cull) || - (distance_culled && !use_camera_cull)) - { + if(culling.test(scene, b_ob, tfm)) { return NULL; } @@ -581,28 +636,8 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) mesh_motion_synced.clear(); } - bool allow_camera_cull = false; - bool allow_distance_cull = false; - float camera_cull_margin = 0.0f; - float distance_cull_margin = 0.0f; - if(b_scene.render().use_simplify()) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - allow_camera_cull = scene->camera->type != CAMERA_PANORAMA && - !b_scene.render().use_multiview() && - get_boolean(cscene, "use_camera_cull"); - allow_distance_cull = scene->camera->type != CAMERA_PANORAMA && - !b_scene.render().use_multiview() && - get_boolean(cscene, "use_distance_cull"); - if(allow_camera_cull) { - camera_cull_margin = get_float(cscene, "camera_cull_margin"); - } - if(allow_distance_cull) { - distance_cull_margin = get_float(cscene, "distance_cull_margin"); - if (distance_cull_margin == 0.0f) { - allow_distance_cull = false; - } - } - } + /* initialize culling */ + BlenderObjectCulling culling(scene, b_scene); /* object loop */ BL::Scene::object_bases_iterator b_base; @@ -634,13 +669,9 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) if(!hide) { progress.set_sync_status("Synchronizing object", b_ob.name()); - PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); - bool use_camera_cull = allow_camera_cull && get_boolean(cobject, "use_camera_cull"); - bool use_distance_cull = allow_distance_cull && get_boolean(cobject, "use_distance_cull"); - if(use_camera_cull || use_distance_cull) { - /* Need to have proper projection matrix. */ - scene->camera->update(); - } + /* load per-object culling data */ + culling.init_object(scene, b_ob); + if(b_ob.is_duplicator() && !object_render_hide_duplis(b_ob)) { /* dupli objects */ b_ob.dupli_list_create(b_scene, dupli_settings); @@ -667,10 +698,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) ob_layer, motion_time, hide_tris, - use_camera_cull, - use_distance_cull, - camera_cull_margin, - distance_cull_margin, + culling, &use_portal); /* sync possible particle data, note particle_id @@ -699,10 +727,7 @@ void BlenderSync::sync_objects(BL::SpaceView3D& b_v3d, float motion_time) ob_layer, motion_time, hide_tris, - use_camera_cull, - use_distance_cull, - camera_cull_margin, - distance_cull_margin, + culling, &use_portal); } } diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index aa6b0d66e80..6984cbda259 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -35,6 +35,7 @@ CCL_NAMESPACE_BEGIN class Background; +class BlenderObjectCulling; class Camera; class Film; class Light; @@ -122,10 +123,7 @@ private: uint layer_flag, float motion_time, bool hide_tris, - bool use_camera_cull, - bool use_distance_cull, - float camera_cull_margin, - float distance_cull_margin, + BlenderObjectCulling& culling, bool *use_portal); void sync_light(BL::Object& b_parent, int persistent_id[OBJECT_PERSISTENT_ID_SIZE], From f68ef05a56b7b3dca4825513b257441739c373b9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 19 Nov 2016 01:15:08 +0100 Subject: [PATCH 266/590] Cycles: add basic backwards compatibility for device selection, move to System tab. For the multi-GPU case users still have to reconfigure the devices they want to use. Based on patch from Lukas Stockner. Differential Revision: https://developer.blender.org/D2347 --- intern/cycles/blender/addon/properties.py | 12 +++++----- intern/cycles/blender/addon/ui.py | 8 +++---- intern/cycles/blender/addon/version_update.py | 12 ++++++++++ .../scripts/startup/bl_ui/space_userpref.py | 3 +++ .../editors/space_outliner/outliner_tree.c | 8 +++++-- source/blender/makesdna/DNA_userdef_types.h | 8 ------- source/blender/makesrna/intern/rna_main.c | 2 +- source/blender/makesrna/intern/rna_userdef.c | 22 +++++++++++++++++++ 8 files changed, 52 insertions(+), 23 deletions(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 575a3f9b6c5..b53f85c3266 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -30,7 +30,7 @@ import _cycles enum_devices = ( ('CPU', "CPU", "Use CPU for rendering"), - ('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in user preferences"), + ('GPU', "GPU Compute", "Use GPU compute device for rendering, configured in the system tab in the user preferences"), ) if _cycles.with_network: @@ -1188,7 +1188,7 @@ class CyclesPreferences(bpy.types.AddonPreferences): def get_devices(self): import _cycles - # Layout of the device tuples: (Name, Type, Internal ID, Persistent ID) + # Layout of the device tuples: (Name, Type, Persistent ID) device_list = _cycles.available_devices() cuda_devices = [] @@ -1236,21 +1236,19 @@ class CyclesPreferences(bpy.types.AddonPreferences): def draw_impl(self, layout, context): - layout.label(text="Compute Device:") + layout.label(text="Cycles Compute Device:") layout.row().prop(self, "compute_device_type", expand=True) cuda_devices, opencl_devices = self.get_devices() row = layout.row() - if cuda_devices: + if self.compute_device_type == 'CUDA' and cuda_devices: col = row.column(align=True) - col.label(text="CUDA devices:") for device in cuda_devices: col.prop(device, "use", text=device.name, toggle=True) - if opencl_devices: + if self.compute_device_type == 'OPENCL' and opencl_devices: col = row.column(align=True) - col.label(text="OpenCL devices:") for device in opencl_devices: col.prop(device, "use", text=device.name, toggle=True) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 6296d6787e5..1856b278c89 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1623,11 +1623,9 @@ def draw_device(self, context): split = layout.split(percentage=1/3) split.label("Device:") - row = split.row(align=True) - sub = row.split(align=True) - sub.active = show_device_selection(context) - sub.prop(cscene, "device", text="") - row.operator("wm.addon_userpref_show", text="", icon='PREFERENCES').module = __package__ + row = split.row() + row.active = show_device_selection(context) + row.prop(cscene, "device", text="") if engine.with_osl() and use_cpu(context): layout.prop(cscene, "shading_system") diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index 951afd37a92..136080efadc 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -172,6 +172,18 @@ def custom_bake_remap(scene): @persistent def do_versions(self): + if bpy.context.user_preferences.version <= (2, 78, 1): + prop = bpy.context.user_preferences.addons[__package__].preferences + system = bpy.context.user_preferences.system + if not prop.is_property_set("compute_device_type"): + if system.legacy_compute_device_type == 1: + prop.compute_device_type = 'OPENCL' + elif system.legacy_compute_device_type == 2: + prop.compute_device_type = 'CUDA' + else: + prop.compute_device_type = 'NONE' + prop.get_devices() + # We don't modify startup file because it assumes to # have all the default values only. if not bpy.data.is_saved: diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index ab3ec3559e5..bdbb6330232 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -429,6 +429,9 @@ class USERPREF_PT_system(Panel): col.separator() + if userpref.addons.find('cycles') != -1: + userpref.addons['cycles'].preferences.draw_impl(col, context) + if hasattr(system, "opensubdiv_compute_type"): col.label(text="OpenSubdiv compute:") col.row().prop(system, "opensubdiv_compute_type", text="") diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 015988efc42..20f7ca4db16 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1108,8 +1108,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i tselem->flag &= ~TSE_CLOSED; if (TSELEM_OPEN(tselem, soops)) { - for (a = 0; a < tot; a++) - outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a); + for (a = 0; a < tot; a++) { + RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr); + if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) { + outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a); + } + } } else if (tot) te->flag |= TE_LAZY_CLOSED; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index e018b66dd60..0ad4482708f 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -867,14 +867,6 @@ typedef enum eNdof_Flag { #define NDOF_PIXELS_PER_SECOND 600.0f -/* compute_device_type */ -typedef enum eCompute_Device_Type { - USER_COMPUTE_DEVICE_NONE = 0, - USER_COMPUTE_DEVICE_OPENCL = 1, - USER_COMPUTE_DEVICE_CUDA = 2, -} eCompute_Device_Type; - - typedef enum eMultiSample_Type { USER_MULTISAMPLE_NONE = 0, USER_MULTISAMPLE_2 = 2, diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c index d432f086dba..94687b6fd46 100644 --- a/source/blender/makesrna/intern/rna_main.c +++ b/source/blender/makesrna/intern/rna_main.c @@ -399,7 +399,7 @@ void RNA_def_main(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Use Autopack", "Automatically pack all external data into .blend file"); prop = RNA_def_int_vector(srna, "version", 3, NULL, 0, INT_MAX, - "Version", "Version of the blender the .blend was saved with", 0, INT_MAX); + "Version", "Version of Blender the .blend was saved with", 0, INT_MAX); RNA_def_property_int_funcs(prop, "rna_Main_version_get", NULL, NULL); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_flag(prop, PROP_THICK_WRAP); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 10807c32b91..ffdc5bb0592 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -124,6 +124,14 @@ static EnumPropertyItem rna_enum_language_default_items[] = { #endif +static void rna_userdef_version_get(PointerRNA *ptr, int *value) +{ + UserDef *userdef = (UserDef *)ptr->data; + value[0] = userdef->versionfile / 100; + value[1] = userdef->versionfile % 100; + value[2] = userdef->subversionfile; +} + static void rna_userdef_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { WM_main_add_notifier(NC_WINDOW, NULL); @@ -4194,6 +4202,14 @@ static void rna_def_userdef_system(BlenderRNA *brna) RNA_def_property_ui_text(prop, "OpenSubdiv Compute Type", "Type of computer back-end used with OpenSubdiv"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_PROPERTIES, "rna_userdef_opensubdiv_update"); #endif + +#ifdef WITH_CYCLES + prop = RNA_def_property(srna, "legacy_compute_device_type", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "compute_device_type"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_HIDDEN); + RNA_def_property_ui_text(prop, "Legacy Compute Device Type", "For backwards compatibility only"); +#endif } static void rna_def_userdef_input(BlenderRNA *brna) @@ -4711,6 +4727,12 @@ void RNA_def_userdef(BlenderRNA *brna) RNA_def_property_pointer_funcs(prop, "rna_UserDef_system_get", NULL, NULL, NULL); RNA_def_property_ui_text(prop, "System & OpenGL", "Graphics driver and operating system settings"); + prop = RNA_def_int_vector(srna, "version", 3, NULL, 0, INT_MAX, + "Version", "Version of Blender the userpref.blend was saved with", 0, INT_MAX); + RNA_def_property_int_funcs(prop, "rna_userdef_version_get", NULL, NULL); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_flag(prop, PROP_THICK_WRAP); + rna_def_userdef_view(brna); rna_def_userdef_edit(brna); rna_def_userdef_input(brna); From b86c6aa6be2989019148303d54f8991a28802635 Mon Sep 17 00:00:00 2001 From: Mai Lavelle Date: Sun, 20 Nov 2016 11:46:43 -0500 Subject: [PATCH 267/590] Cycles: Don't shadow loop variable --- intern/cycles/render/mesh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index ac369a0d5f8..32dba532f2b 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1084,7 +1084,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce } /* terminator */ - for(int i = 0; i < ATTR_PRIM_TYPES; i++) { + for(int j = 0; j < ATTR_PRIM_TYPES; j++) { attr_map[index].x = ATTR_STD_NONE; attr_map[index].y = 0; attr_map[index].z = 0; From 83b1f24140f63b35f93457d03f779b964ffad8ca Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 20 Nov 2016 17:46:29 +0100 Subject: [PATCH 268/590] Fix Xcode link error, missing definitions in RNA C++ API that other compilers ignored. --- source/blender/makesrna/intern/makesrna.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 569c1ee5f3f..309d39a379f 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -1536,7 +1536,11 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp) const char *nextfunc = (const char *)cprop->next; const char *item_type = (const char *)cprop->item_type; - if (dp->dnatype && STREQ(dp->dnatype, "ListBase")) { + if (cprop->length) { + /* always generate if we have a manual implementation */ + cprop->length = (void *)rna_def_property_length_func(f, srna, prop, dp, (const char *)cprop->length); + } + else if (dp->dnatype && STREQ(dp->dnatype, "ListBase")) { /* pass */ } else if (dp->dnalengthname || dp->dnalengthfixed) { From b3c8ee891ab95db75e1fc1493a916fa5349d0daa Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 21 Nov 2016 11:05:56 +0100 Subject: [PATCH 269/590] Depsgraph: use more explicit parenthesis --- source/blender/depsgraph/intern/builder/deg_builder.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 8a0bec5ed1d..51d1e08d70a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -153,8 +153,8 @@ void deg_graph_build_finalize(Depsgraph *graph) GHASH_FOREACH_END(); ID *id = id_node->id; - if (id->tag & LIB_TAG_ID_RECALC_ALL && - id->tag & LIB_TAG_DOIT) + if ((id->tag & LIB_TAG_ID_RECALC_ALL) && + (id->tag & LIB_TAG_DOIT)) { id_node->tag_update(graph); id->tag &= ~LIB_TAG_DOIT; From 5eab3b079f939c4c0cc0c84f9bf8c5dcb0c0b77f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 21 Nov 2016 12:00:09 +0100 Subject: [PATCH 270/590] Depsgraph: Fix infinite viewport object update in CYcles render mode The issue was caused by wrong object re-tag needed to have proper dependnecies update for OpenSubdiv. --- source/blender/depsgraph/intern/builder/deg_builder.cc | 2 ++ source/blender/depsgraph/intern/depsgraph.cc | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index 51d1e08d70a..aedd00685b3 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -48,6 +48,8 @@ #include "util/deg_util_foreach.h" +#include + namespace DEG { string deg_fcurve_id_name(const FCurve *fcu) diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 3502267d9ca..9a4a35a5a35 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -371,8 +371,7 @@ DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from, if (comp_node->type == DEPSNODE_TYPE_GEOMETRY) { IDDepsNode *id_to = to->owner->owner; IDDepsNode *id_from = from->owner->owner; - Object *object_to = (Object *)id_to->id; - if (id_to != id_from && (object_to->recalc & OB_RECALC_ALL)) { + if (id_to != id_from && (id_to->id->tag & LIB_TAG_ID_RECALC_ALL)) { if ((id_from->eval_flags & DAG_EVAL_NEED_CPU) == 0) { id_from->tag_update(this); id_from->eval_flags |= DAG_EVAL_NEED_CPU; From af7343ae22ee1f2f31a7e47a86e43dda4bbaa6d6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 21 Nov 2016 13:32:41 +0100 Subject: [PATCH 271/590] Cycles: Attempt to fix compilation error on ppc64el There is some define conflict between system headers and clew, so delay include of clew.h as much as possible.] This is something which needed to be done in the code before the refactor, hopefully such change will still work. --- intern/cycles/device/opencl/opencl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/cycles/device/opencl/opencl.h b/intern/cycles/device/opencl/opencl.h index 054ac9014f0..4023ba89a10 100644 --- a/intern/cycles/device/opencl/opencl.h +++ b/intern/cycles/device/opencl/opencl.h @@ -16,14 +16,14 @@ #ifdef WITH_OPENCL -#include "clew.h" - #include "device.h" #include "util_map.h" #include "util_param.h" #include "util_string.h" +#include "clew.h" + CCL_NAMESPACE_BEGIN #define CL_MEM_PTR(p) ((cl_mem)(uintptr_t)(p)) From 25c534f20a0a15a4b07d61fb447740dc22049eed Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 21 Nov 2016 14:36:36 +0100 Subject: [PATCH 272/590] Fix T49981: New Depsgraph - When camera is on inactive layer, it does not evaluate constraints --- .../intern/builder/deg_builder_nodes.cc | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 4de82dd63e4..e312c4e0dcb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -372,19 +372,26 @@ SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group) void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob) { - if (ob->id.tag & LIB_TAG_DOIT) { - IDDepsNode *id_node = m_graph->find_id_node(&ob->id); - if (base != NULL) { - id_node->layers |= base->lay; - } - return; - } - ob->id.tag |= LIB_TAG_DOIT; - - IDDepsNode *id_node = add_id_node(&ob->id); + const bool has_object = (ob->id.tag & LIB_TAG_DOIT); + IDDepsNode *id_node = (has_object) + ? m_graph->find_id_node(&ob->id) + : add_id_node(&ob->id); + /* Update node layers. + * Do it for both new and existing ID nodes. This is so because several + * bases might be sharing same object. + */ if (base != NULL) { id_node->layers |= base->lay; } + if (ob == scene->camera) { + /* Camera should always be updated, it used directly by viewport. */ + id_node->layers |= (unsigned int)(-1); + } + /* Skip rest of components if the ID node was already there. */ + if (has_object) { + return; + } + ob->id.tag |= LIB_TAG_DOIT; ob->customdata_mask = 0; /* Standard components. */ From 2a78635dea1a8e8e54f5350c9856ecc69f2b1751 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 21 Nov 2016 14:26:35 +0100 Subject: [PATCH 273/590] Cleanup: get rid of unused `BKE_constraints_relink()`. Libquery/generic ID remapping code handles this now. --- source/blender/blenkernel/BKE_constraint.h | 1 - source/blender/blenkernel/intern/constraint.c | 21 ------------------- 2 files changed, 22 deletions(-) diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index f3cfb901154..047d1787f76 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -120,7 +120,6 @@ void BKE_constraint_unique_name(struct bConstraint *con, struct ListBase *list); void BKE_constraints_free(struct ListBase *list); void BKE_constraints_free_ex(struct ListBase *list, bool do_id_user); void BKE_constraints_copy(struct ListBase *dst, const struct ListBase *src, bool do_extern); -void BKE_constraints_relink(struct ListBase *list); void BKE_constraints_id_loop(struct ListBase *list, ConstraintIDFunc func, void *userdata); void BKE_constraint_free_data(struct bConstraint *con); void BKE_constraint_free_data_ex(struct bConstraint *con, bool do_id_user); diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index b85f1b838ff..9d4de30aa2c 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4705,27 +4705,6 @@ bConstraint *BKE_constraint_add_for_object(Object *ob, const char *name, short t /* ......... */ -/* helper for BKE_constraints_relink() - call ID_NEW() on every ID reference the constraint has */ -static void con_relink_id_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userdata)) -{ - /* ID_NEW() expects a struct with inline "id" member as first - * since we've got the actual ID block, let's just inline this - * code. - * - * See ID_NEW(a) in DNA_ID.h - */ - if ((*idpoin) && (*idpoin)->newid) - (*idpoin) = (void *)(*idpoin)->newid; -} - -/* Reassign links that constraints have to other data (called during file loading?) */ -void BKE_constraints_relink(ListBase *conlist) -{ - /* just a wrapper around ID-loop for just calling ID_NEW() on all ID refs */ - BKE_constraints_id_loop(conlist, con_relink_id_cb, NULL); -} - - /* Run the given callback on all ID-blocks in list of constraints */ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *userdata) { From b97c567c1df1e5c38833c4af8a95962e0ece4c61 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 21 Nov 2016 15:19:34 +0100 Subject: [PATCH 274/590] Fix two very bad issues in new ID.make_local RNA function. I) `clear_proxy` parameter was not assigned to parm in RNA define code, so 'pyfunc optional' flag was set to `new_id` parameter of `user_remap` func - super ugly! II) `clear_proxy` parameter itself, when set to False, would allow to leave .blend file in invalid state (more than one proxy of same object), this should never, ever be allowed in RNA API imho. Left the PAI untouched for now, just disabled any effect from this parameter (hence always clearing proxy when copying). --- source/blender/makesrna/intern/rna_ID.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 5174c957834..b5015c3fbde 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -348,13 +348,21 @@ static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id) } } -static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int clear_proxy) +static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int UNUSED(clear_proxy)) { + /* XXX This is *very, very bad*, since it may leave Main in invalid state (two objects, one local and one linked, + * proxies of same reference linked object). + * This can be allowed in C code (with extensive warning and documentation), + * but is totally fully forbidden in our RNA API! + * So disabling for now. */ +#if 0 /* Special case, as we can't rely on id_make_local(); it clears proxies. */ if (!clear_proxy && GS(self->name) == ID_OB) { BKE_object_make_local_ex(bmain, (Object *)self, false, clear_proxy); } - else { + else +#endif + { id_make_local(bmain, self, false, false); } @@ -1018,9 +1026,7 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_function_ui_description(func, "Make this datablock local, return local one " "(may be a copy of the original, in case it is also indirectly used)"); RNA_def_function_flag(func, FUNC_USE_MAIN); - RNA_def_boolean(func, "clear_proxy", true, "", - "Whether to clear proxies (the default behavior); can cause proxies to be duplicated" - " when still referred to from another library"); + parm = RNA_def_boolean(func, "clear_proxy", true, "", "DO NOT USE! - has no effect at all"); RNA_def_property_flag(parm, PROP_PYFUNC_OPTIONAL); parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied"); RNA_def_function_return(func, parm); From 94d8e6fc6cdef926e930ca22a5c689193760c705 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 21 Nov 2016 20:57:02 +0100 Subject: [PATCH 275/590] Partly revert own rBb97c567c1df1e, clear_proxy is actually safe. This is very confusing, in fact, and rna tooltip was wrong, BKE_object_make_local_ex actually ensures we never have several proxies of same object, since it always clears proxy when it has to copy object to make it local... What that RNA function is probably missing, though, is same logic as in BKE_library_make_local to actually remap proxy from old linked object to new local one. --- source/blender/makesrna/intern/rna_ID.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index b5015c3fbde..87fb45a4419 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -348,21 +348,13 @@ static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id) } } -static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int UNUSED(clear_proxy)) +static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int clear_proxy) { - /* XXX This is *very, very bad*, since it may leave Main in invalid state (two objects, one local and one linked, - * proxies of same reference linked object). - * This can be allowed in C code (with extensive warning and documentation), - * but is totally fully forbidden in our RNA API! - * So disabling for now. */ -#if 0 /* Special case, as we can't rely on id_make_local(); it clears proxies. */ if (!clear_proxy && GS(self->name) == ID_OB) { BKE_object_make_local_ex(bmain, (Object *)self, false, clear_proxy); } - else -#endif - { + else { id_make_local(bmain, self, false, false); } @@ -1026,7 +1018,9 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_function_ui_description(func, "Make this datablock local, return local one " "(may be a copy of the original, in case it is also indirectly used)"); RNA_def_function_flag(func, FUNC_USE_MAIN); - parm = RNA_def_boolean(func, "clear_proxy", true, "", "DO NOT USE! - has no effect at all"); + parm = RNA_def_boolean(func, "clear_proxy", true, "", + "Whether to clear proxies (the default behavior, " + "note that if object has to be duplicated to be made local, proxies are always cleared)"); RNA_def_property_flag(parm, PROP_PYFUNC_OPTIONAL); parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied"); RNA_def_function_return(func, parm); From dd51ec592f51c3f5787fe7527a81aae93a0b4b7c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 21 Nov 2016 21:03:34 +0100 Subject: [PATCH 276/590] CLEW: Workaround compilation error on ppc64el Something was conflicting here, causing C++ to consider bool as a __vector(4) bool. --- extern/clew/include/clew.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extern/clew/include/clew.h b/extern/clew/include/clew.h index 1f79c12481b..2a583c81599 100644 --- a/extern/clew/include/clew.h +++ b/extern/clew/include/clew.h @@ -369,7 +369,8 @@ typedef unsigned int cl_GLenum; #endif /* Define basic vector types */ -#if defined( __VEC__ ) +/* WOrkaround for ppc64el platform: conflicts with bool from C++. */ +#if defined( __VEC__ ) && !(defined(__PPC64__) && defined(__LITTLE_ENDIAN__)) #include /* may be omitted depending on compiler. AltiVec spec provides no way to detect whether the header is required. */ typedef vector unsigned char __cl_uchar16; typedef vector signed char __cl_char16; From bd8cbf5c079b4cffb3652195ba8a9c92d8a60d15 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 21 Nov 2016 21:04:48 +0100 Subject: [PATCH 277/590] Glog: Fix compilation error on ppc64el This was fixed in upstream already. Time to re-bundle? --- extern/glog/src/stacktrace_powerpc-inl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/glog/src/stacktrace_powerpc-inl.h b/extern/glog/src/stacktrace_powerpc-inl.h index 1090ddedbc7..03b91089aad 100644 --- a/extern/glog/src/stacktrace_powerpc-inl.h +++ b/extern/glog/src/stacktrace_powerpc-inl.h @@ -111,7 +111,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) { result[n++] = *(sp+2); #elif defined(_CALL_SYSV) result[n++] = *(sp+1); -#elif defined(__APPLE__) || (defined(__linux) && defined(__PPC64__)) +#elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__)) // This check is in case the compiler doesn't define _CALL_AIX/etc. result[n++] = *(sp+2); #elif defined(__linux) From 927a168b077fa5182168068315c4fb0ea998edb6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 22 Nov 2016 11:38:27 +0100 Subject: [PATCH 278/590] GPU: Consider latest Gallium driver an official ATI/AMD This will make triple buffer used by default for such configuration. Ideally we would switch to triple buffer on all platforms, but let's do it in 2.8 branch and don't open can of worms in master now. This should solve issues like T49945. --- source/blender/gpu/intern/gpu_extensions.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 26e86fe61b8..e0ce87d0e68 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -173,7 +173,10 @@ void gpu_extensions_init(void) GG.device = GPU_DEVICE_INTEL; GG.driver = GPU_DRIVER_OFFICIAL; } - else if (strstr(renderer, "Mesa DRI R") || (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI "))) { + else if ((strstr(renderer, "Mesa DRI R")) || + (strstr(renderer, "Gallium ") && strstr(renderer, " on ATI ")) || + (strstr(renderer, "Gallium ") && strstr(renderer, " on AMD "))) + { GG.device = GPU_DEVICE_ATI; GG.driver = GPU_DRIVER_OPENSOURCE; } From 272412f9c0d26f630c5e1e7d07d4ff417b7218e5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 17 Nov 2016 12:13:22 +0100 Subject: [PATCH 279/590] Cycles: Implement texture size limit simplify option Main intention is to give some quick way to control scene's memory usage by clamping textures which are too big. This is really handy on the early production stages when you first create really nice looking hi-res textures and only when it all works and approved start investing time on optimizing your scene. This is a new option in Scene Simplify panel and it acts as following: when texture size is bigger than the given value it'll be scaled down by half for until it fits into given limit. There are various possible improvements, such as: - Use threaded scaling using our own task manager. This is actually one of the main reasons why image resize is manually-implemented instead of using OIIO's resize. Other reason here is that API seems limited to construct 3D texture description easily. - Vectorization of uchar4/float4/half4 textures. - Use something smarter than box filter. Was playing with some other filters, but not sure they are really better: they kind of causes more fuzzy edges. Even with such a TODOs in the code the option is already quite useful. Reviewers: brecht Reviewed By: brecht Subscribers: jtheninja, Blendify, gregzaal, venomgfx Differential Revision: https://developer.blender.org/D2362 --- intern/cycles/blender/addon/properties.py | 24 ++++ intern/cycles/blender/addon/ui.py | 37 +++-- intern/cycles/blender/blender_sync.cpp | 14 ++ intern/cycles/render/image.cpp | 108 +++++++++++--- intern/cycles/render/image.h | 29 +++- intern/cycles/render/mesh.cpp | 2 + intern/cycles/render/scene.cpp | 2 +- intern/cycles/render/scene.h | 5 +- intern/cycles/util/CMakeLists.txt | 1 + intern/cycles/util/util_image.h | 14 ++ intern/cycles/util/util_image_impl.h | 167 ++++++++++++++++++++++ 11 files changed, 364 insertions(+), 39 deletions(-) create mode 100644 intern/cycles/util/util_image_impl.h diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index b53f85c3266..fed1524a816 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -129,6 +129,16 @@ enum_device_type = ( ('OPENCL', "OpenCL", "OpenCL", 2) ) +enum_texture_limit = ( + ('OFF', "No Limit", "No texture size limit", 0), + ('128', "128", "Limit texture size to 128 pixels", 1), + ('256', "256", "Limit texture size to 256 pixels", 2), + ('512', "512", "Limit texture size to 512 pixels", 3), + ('1024', "1024", "Limit texture size to 1024 pixels", 4), + ('2048', "2048", "Limit texture size to 2048 pixels", 5), + ('4096', "4096", "Limit texture size to 4096 pixels", 6), + ('8192', "8192", "Limit texture size to 8192 pixels", 7), + ) class CyclesRenderSettings(bpy.types.PropertyGroup): @classmethod @@ -608,6 +618,20 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): min=0.0, max=1.0, ) + cls.texture_limit = EnumProperty( + name="Viewport Texture Limit", + default='OFF', + description="Limit texture size used by viewport rendering", + items=enum_texture_limit + ) + + cls.texture_limit_render = EnumProperty( + name="Render Texture Limit", + default='OFF', + description="Limit texture size used by final rendering", + items=enum_texture_limit + ) + # Various fine-tuning debug flags def devices_update_callback(self, context): diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 1856b278c89..3f7730efbb0 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -1587,29 +1587,40 @@ class CyclesScene_PT_simplify(CyclesButtonsPanel, Panel): cscene = scene.cycles layout.active = rd.use_simplify - split = layout.split() - col = split.column() - col.label(text="Viewport:") - col.prop(rd, "simplify_subdivision", text="Subdivision") - col.prop(rd, "simplify_child_particles", text="Child Particles") + col = layout.column(align=True) + col.label(text="Subdivision") + row = col.row(align=True) + row.prop(rd, "simplify_subdivision", text="Viewport") + row.prop(rd, "simplify_subdivision_render", text="Render") - col = split.column() - col.label(text="Render:") - col.prop(rd, "simplify_subdivision_render", text="Subdivision") - col.prop(rd, "simplify_child_particles_render", text="Child Particles") + col = layout.column(align=True) + col.label(text="Child Particles") + row = col.row(align=True) + row.prop(rd, "simplify_child_particles", text="Viewport") + row.prop(rd, "simplify_child_particles_render", text="Render") - layout.separator() + col = layout.column(align=True) + split = col.split() + sub = split.column() + sub.label(text="Texture Limit Viewport") + sub.prop(cscene, "texture_limit", text="") + sub = split.column() + sub.label(text="Texture Limit Render") + sub.prop(cscene, "texture_limit_render", text="") split = layout.split() - col = split.column() col.prop(cscene, "use_camera_cull") - col.prop(cscene, "camera_cull_margin", text="Margin") + row = col.row() + row.active = cscene.use_camera_cull + row.prop(cscene, "camera_cull_margin") col = split.column() col.prop(cscene, "use_distance_cull") - col.prop(cscene, "distance_cull_margin", text="Distance") + row = col.row() + row.active = cscene.use_distance_cull + row.prop(cscene, "distance_cull_margin", text="Distance") def draw_device(self, context): scene = context.scene diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 6118cc72239..38b2ce19e8a 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -504,6 +504,20 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, else params.persistent_data = false; + int texture_limit; + if(background) { + texture_limit = RNA_enum_get(&cscene, "texture_limit_render"); + } + else { + texture_limit = RNA_enum_get(&cscene, "texture_limit"); + } + if(texture_limit > 0 && b_scene.render().use_simplify()) { + params.texture_limit = 1 << (texture_limit + 6); + } + else { + params.texture_limit = 0; + } + #if !(defined(__GNUC__) && (defined(i386) || defined(_M_IX86))) if(is_cpu) { params.use_qbvh = DebugFlags().cpu.qbvh && system_cpu_support_sse2(); diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 7465fbd43a7..11193bf4974 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -19,6 +19,7 @@ #include "scene.h" #include "util_foreach.h" +#include "util_logging.h" #include "util_path.h" #include "util_progress.h" #include "util_texture.h" @@ -476,6 +477,7 @@ template bool ImageManager::file_load_image(Image *img, ImageDataType type, + int texture_limit, device_vector& tex_img) { const StorageType alpha_one = (FileFormat == TypeDesc::UINT8)? 255 : 1; @@ -485,9 +487,15 @@ bool ImageManager::file_load_image(Image *img, return false; } /* Read RGBA pixels. */ - StorageType *pixels = (StorageType*)tex_img.resize(width, height, depth); - if(pixels == NULL) { - return false; + vector pixels_storage; + StorageType *pixels; + const size_t max_size = max(max(width, height), depth); + if(texture_limit > 0 && max_size > texture_limit) { + pixels_storage.resize(((size_t)width)*height*depth*4); + pixels = &pixels_storage[0]; + } + else { + pixels = (StorageType*)tex_img.resize(width, height, depth); } bool cmyk = false; if(in) { @@ -526,12 +534,12 @@ bool ImageManager::file_load_image(Image *img, if(FileFormat == TypeDesc::FLOAT) { builtin_image_float_pixels_cb(img->filename, img->builtin_data, - (float*)pixels); + (float*)&pixels[0]); } else if(FileFormat == TypeDesc::UINT8) { builtin_image_pixels_cb(img->filename, img->builtin_data, - (uchar*)pixels); + (uchar*)&pixels[0]); } else { /* TODO(dingto): Support half for ImBuf. */ @@ -540,10 +548,10 @@ bool ImageManager::file_load_image(Image *img, /* Check if we actually have a float4 slot, in case components == 1, * but device doesn't support single channel textures. */ - if(type == IMAGE_DATA_TYPE_FLOAT4 || - type == IMAGE_DATA_TYPE_HALF4 || - type == IMAGE_DATA_TYPE_BYTE4) - { + bool is_rgba = (type == IMAGE_DATA_TYPE_FLOAT4 || + type == IMAGE_DATA_TYPE_HALF4 || + type == IMAGE_DATA_TYPE_BYTE4); + if(is_rgba) { size_t num_pixels = ((size_t)width) * height * depth; if(cmyk) { /* CMYK */ @@ -587,14 +595,41 @@ bool ImageManager::file_load_image(Image *img, } } } + if(pixels_storage.size() > 0) { + float scale_factor = 1.0f; + while(max_size * scale_factor > texture_limit) { + scale_factor *= 0.5f; + } + VLOG(1) << "Scaling image " << img->filename + << " by a factor of " << scale_factor << "."; + vector scaled_pixels; + size_t scaled_width, scaled_height, scaled_depth; + util_image_resize_pixels(pixels_storage, + width, height, depth, + is_rgba ? 4 : 1, + scale_factor, + &scaled_pixels, + &scaled_width, &scaled_height, &scaled_depth); + StorageType *texture_pixels = (StorageType*)tex_img.resize(scaled_width, + scaled_height, + scaled_depth); + memcpy(texture_pixels, + &scaled_pixels[0], + scaled_pixels.size() * sizeof(StorageType)); + } return true; } -void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progress) +void ImageManager::device_load_image(Device *device, + DeviceScene *dscene, + Scene *scene, + ImageDataType type, + int slot, + Progress *progress) { if(progress->get_cancel()) return; - + Image *img = images[type][slot]; if(osl_texture_system && !img->builtin_data) @@ -603,6 +638,8 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD string filename = path_filename(images[type][slot]->filename); progress->set_status("Updating Images", "Loading " + filename); + const int texture_limit = scene->params.texture_limit; + /* Slot assignment */ int flat_slot = type_index_to_flattened_slot(slot, type); @@ -622,7 +659,11 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image(img, type, tex_img)) { + if(!file_load_image(img, + type, + texture_limit, + tex_img)) + { /* on failure to load, we set a 1x1 pixels pink image */ float *pixels = (float*)tex_img.resize(1, 1); @@ -648,7 +689,11 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image(img, type, tex_img)) { + if(!file_load_image(img, + type, + texture_limit, + tex_img)) + { /* on failure to load, we set a 1x1 pixels pink image */ float *pixels = (float*)tex_img.resize(1, 1); @@ -671,7 +716,11 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image(img, type, tex_img)) { + if(!file_load_image(img, + type, + texture_limit, + tex_img)) + { /* on failure to load, we set a 1x1 pixels pink image */ uchar *pixels = (uchar*)tex_img.resize(1, 1); @@ -697,7 +746,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image(img, type, tex_img)) { + if(!file_load_image(img, + type, + texture_limit, + tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ uchar *pixels = (uchar*)tex_img.resize(1, 1); @@ -720,7 +772,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image(img, type, tex_img)) { + if(!file_load_image(img, + type, + texture_limit, + tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ half *pixels = (half*)tex_img.resize(1, 1); @@ -746,7 +801,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD device->tex_free(tex_img); } - if(!file_load_image(img, type, tex_img)) { + if(!file_load_image(img, + type, + texture_limit, + tex_img)) { /* on failure to load, we set a 1x1 pixels pink image */ half *pixels = (half*)tex_img.resize(1, 1); @@ -842,7 +900,10 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD } } -void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& progress) +void ImageManager::device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress) { if(!need_update) return; @@ -859,7 +920,14 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& } else if(images[type][slot]->need_load) { if(!osl_texture_system || images[type][slot]->builtin_data) - pool.push(function_bind(&ImageManager::device_load_image, this, device, dscene, (ImageDataType)type, slot, &progress)); + pool.push(function_bind(&ImageManager::device_load_image, + this, + device, + dscene, + scene, + (ImageDataType)type, + slot, + &progress)); } } } @@ -874,6 +942,7 @@ void ImageManager::device_update(Device *device, DeviceScene *dscene, Progress& void ImageManager::device_update_slot(Device *device, DeviceScene *dscene, + Scene *scene, int flat_slot, Progress *progress) { @@ -890,6 +959,7 @@ void ImageManager::device_update_slot(Device *device, if(!osl_texture_system || image->builtin_data) device_load_image(device, dscene, + scene, type, slot, progress); diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 1dc4bf180f8..3da7338985c 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -30,6 +30,7 @@ CCL_NAMESPACE_BEGIN class Device; class DeviceScene; class Progress; +class Scene; class ImageManager { public: @@ -67,8 +68,15 @@ public: ExtensionType extension); ImageDataType get_image_metadata(const string& filename, void *builtin_data, bool& is_linear); - void device_update(Device *device, DeviceScene *dscene, Progress& progress); - void device_update_slot(Device *device, DeviceScene *dscene, int flat_slot, Progress *progress); + void device_update(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress); + void device_update_slot(Device *device, + DeviceScene *dscene, + Scene *scene, + int flat_slot, + Progress *progress); void device_free(Device *device, DeviceScene *dscene); void device_free_builtin(Device *device, DeviceScene *dscene); @@ -114,6 +122,7 @@ private: typename DeviceType> bool file_load_image(Image *img, ImageDataType type, + int texture_limit, device_vector& tex_img); int type_index_to_flattened_slot(int slot, ImageDataType type); @@ -122,10 +131,20 @@ private: uint8_t pack_image_options(ImageDataType type, size_t slot); - void device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progess); - void device_free_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot); + void device_load_image(Device *device, + DeviceScene *dscene, + Scene *scene, + ImageDataType type, + int slot, + Progress *progess); + void device_free_image(Device *device, + DeviceScene *dscene, + ImageDataType type, + int slot); - void device_pack_images(Device *device, DeviceScene *dscene, Progress& progess); + void device_pack_images(Device *device, + DeviceScene *dscene, + Progress& progess); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 32dba532f2b..df4327d021a 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1665,6 +1665,7 @@ void MeshManager::device_update_displacement_images(Device *device, */ image_manager->device_update(device, dscene, + scene, progress); return; } @@ -1682,6 +1683,7 @@ void MeshManager::device_update_displacement_images(Device *device, image_manager, device, dscene, + scene, slot, &progress)); } diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index b341837b7e8..68124e78cb5 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -187,7 +187,7 @@ void Scene::device_update(Device *device_, Progress& progress) if(progress.get_cancel() || device->have_error()) return; progress.set_status("Updating Images"); - image_manager->device_update(device, &dscene, progress); + image_manager->device_update(device, &dscene, this, progress); if(progress.get_cancel() || device->have_error()) return; diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 8fec171b6fb..df9363cc768 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -145,6 +145,7 @@ public: bool use_bvh_unaligned_nodes; bool use_qbvh; bool persistent_data; + int texture_limit; SceneParams() { @@ -154,6 +155,7 @@ public: use_bvh_unaligned_nodes = true; use_qbvh = false; persistent_data = false; + texture_limit = 0; } bool modified(const SceneParams& params) @@ -162,7 +164,8 @@ public: && use_bvh_spatial_split == params.use_bvh_spatial_split && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes && use_qbvh == params.use_qbvh - && persistent_data == params.persistent_data); } + && persistent_data == params.persistent_data + && texture_limit == params.texture_limit); } }; /* Scene */ diff --git a/intern/cycles/util/CMakeLists.txt b/intern/cycles/util/CMakeLists.txt index 02ee4cd6774..d8abf671bd6 100644 --- a/intern/cycles/util/CMakeLists.txt +++ b/intern/cycles/util/CMakeLists.txt @@ -45,6 +45,7 @@ set(SRC_HEADERS util_half.h util_hash.h util_image.h + util_image_impl.h util_list.h util_logging.h util_map.h diff --git a/intern/cycles/util/util_image.h b/intern/cycles/util/util_image.h index bb8a31c6fec..c8efc551d97 100644 --- a/intern/cycles/util/util_image.h +++ b/intern/cycles/util/util_image.h @@ -21,11 +21,25 @@ #include +#include "util_vector.h" + CCL_NAMESPACE_BEGIN OIIO_NAMESPACE_USING +template +void util_image_resize_pixels(const vector& input_pixels, + const size_t input_width, + const size_t input_height, + const size_t input_depth, + const size_t components, + vector *output_pixels, + size_t *output_width, + size_t *output_height, + size_t *output_depth); + CCL_NAMESPACE_END #endif /* __UTIL_IMAGE_H__ */ +#include "util_image_impl.h" diff --git a/intern/cycles/util/util_image_impl.h b/intern/cycles/util/util_image_impl.h new file mode 100644 index 00000000000..3429ee46e94 --- /dev/null +++ b/intern/cycles/util/util_image_impl.h @@ -0,0 +1,167 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __UTIL_IMAGE_IMPL_H__ +#define __UTIL_IMAGE_IMPL_H__ + +#include "util_debug.h" +#include "util_image.h" + +CCL_NAMESPACE_BEGIN + +namespace { + +template +const T *util_image_read(const vector& pixels, + const size_t width, + const size_t height, + const size_t /*depth*/, + const size_t components, + const size_t x, const size_t y, const size_t z) { + const size_t index = ((size_t)z * (width * height) + + (size_t)y * width + + (size_t)x) * components; + return &pixels[index]; +} + +template +void util_image_downscale_sample(const vector& pixels, + const size_t width, + const size_t height, + const size_t depth, + const size_t components, + const size_t kernel_size, + const float x, + const float y, + const float z, + T *result) +{ + assert(components <= 4); + const size_t ix = (size_t)x, + iy = (size_t)y, + iz = (size_t)z; + /* TODO(sergey): Support something smarter than box filer. */ + float accum[4] = {0}; + size_t count = 0; + for(size_t dz = 0; dz < kernel_size; ++dz) { + for(size_t dy = 0; dy < kernel_size; ++dy) { + for(size_t dx = 0; dx < kernel_size; ++dx) { + const size_t nx = ix + dx, + ny = iy + dy, + nz = iz + dz; + if(nx >= width || ny >= height || nz >= depth) { + continue; + } + const T *pixel = util_image_read(pixels, + width, height, depth, + components, + nx, ny, nz); + for(size_t k = 0; k < components; ++k) { + accum[k] += pixel[k]; + } + ++count; + } + } + } + const float inv_count = 1.0f / (float)count; + for(size_t k = 0; k < components; ++k) { + result[k] = T(accum[k] * inv_count); + } +} + +template +void util_image_downscale_pixels(const vector& input_pixels, + const size_t input_width, + const size_t input_height, + const size_t input_depth, + const size_t components, + const float inv_scale_factor, + const size_t output_width, + const size_t output_height, + const size_t output_depth, + vector *output_pixels) +{ + const size_t kernel_size = (size_t)(inv_scale_factor + 0.5f); + for(size_t z = 0; z < output_depth; ++z) { + for(size_t y = 0; y < output_height; ++y) { + for(size_t x = 0; x < output_width; ++x) { + const float input_x = (float)x * inv_scale_factor, + input_y = (float)y * inv_scale_factor, + input_z = (float)z * inv_scale_factor; + const size_t output_index = + (z * output_width * output_height + + y * output_width + x) * components; + util_image_downscale_sample(input_pixels, + input_width, input_height, input_depth, + components, + kernel_size, + input_x, input_y, input_z, + &output_pixels->at(output_index)); + } + } + } +} + +} /* namespace */ + +template +void util_image_resize_pixels(const vector& input_pixels, + const size_t input_width, + const size_t input_height, + const size_t input_depth, + const size_t components, + const float scale_factor, + vector *output_pixels, + size_t *output_width, + size_t *output_height, + size_t *output_depth) +{ + /* Early output for case when no scaling is applied. */ + if(scale_factor == 1.0f) { + *output_width = input_width; + *output_height = input_height; + *output_depth = input_depth; + *output_pixels = input_pixels; + return; + } + /* First of all, we calculate output image dimensions. + * We clamp them to be 1 pixel at least so we do not generate degenerate + * image. + */ + *output_width = max((size_t)((float)input_width * scale_factor), 1); + *output_height = max((size_t)((float)input_height * scale_factor), 1); + *output_depth = max((size_t)((float)input_depth * scale_factor), 1); + /* Prepare pixel storage for the result. */ + const size_t num_output_pixels = ((*output_width) * + (*output_height) * + (*output_depth)) * components; + output_pixels->resize(num_output_pixels); + if(scale_factor < 1.0f) { + const float inv_scale_factor = 1.0f / scale_factor; + util_image_downscale_pixels(input_pixels, + input_width, input_height, input_depth, + components, + inv_scale_factor, + *output_width, *output_height, *output_depth, + output_pixels); + } else { + /* TODO(sergey): Needs implementation. */ + } +} + +CCL_NAMESPACE_END + +#endif /* __UTIL_IMAGE_IMPL_H__ */ From af444e913fc29ec52f08e0290831b53f94f3fd8f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 22 Nov 2016 12:05:57 +0100 Subject: [PATCH 280/590] Cycles: Attempt to fix 32bit buildbot builds after recent commit --- intern/cycles/util/util_image_impl.h | 1 + 1 file changed, 1 insertion(+) diff --git a/intern/cycles/util/util_image_impl.h b/intern/cycles/util/util_image_impl.h index 3429ee46e94..58f85cf93d6 100644 --- a/intern/cycles/util/util_image_impl.h +++ b/intern/cycles/util/util_image_impl.h @@ -17,6 +17,7 @@ #ifndef __UTIL_IMAGE_IMPL_H__ #define __UTIL_IMAGE_IMPL_H__ +#include "util_algorithm.h" #include "util_debug.h" #include "util_image.h" From edc10f55291cc541e6f46354389baee34fbaba6b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 22 Nov 2016 12:11:08 +0100 Subject: [PATCH 281/590] Cycles: Another attempt to fix compilation on 32bit Linux --- intern/cycles/util/util_image_impl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/cycles/util/util_image_impl.h b/intern/cycles/util/util_image_impl.h index 58f85cf93d6..73ecfda0855 100644 --- a/intern/cycles/util/util_image_impl.h +++ b/intern/cycles/util/util_image_impl.h @@ -142,9 +142,9 @@ void util_image_resize_pixels(const vector& input_pixels, * We clamp them to be 1 pixel at least so we do not generate degenerate * image. */ - *output_width = max((size_t)((float)input_width * scale_factor), 1); - *output_height = max((size_t)((float)input_height * scale_factor), 1); - *output_depth = max((size_t)((float)input_depth * scale_factor), 1); + *output_width = max((size_t)((float)input_width * scale_factor), (size_t)1); + *output_height = max((size_t)((float)input_height * scale_factor), (size_t)1); + *output_depth = max((size_t)((float)input_depth * scale_factor), (size_t)1); /* Prepare pixel storage for the result. */ const size_t num_output_pixels = ((*output_width) * (*output_height) * From 1be717d00783160200b354a03d660661628ea24a Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 22 Nov 2016 12:21:25 +0100 Subject: [PATCH 282/590] Fix (unreported) crash when drawing armatures' poses in some cases. Was affecting armatures' pose drawing code, could try to draw with non-updated pose, which may contain NULL bone pointers (e.g. after some data-block management tool execution, like make local, remapping, etc.). --- source/blender/editors/space_view3d/drawarmature.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 1d9a515a5f2..95a2df68e4a 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -2723,6 +2723,11 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, else { /* Draw Pose */ if (ob->pose && ob->pose->chanbase.first) { + /* We can't safely draw non-updated pose, might contain NULL bone pointers... */ + if (ob->pose->flag & POSE_RECALC) { + BKE_pose_rebuild(ob, arm); + } + /* drawing posemode selection indices or colors only in these cases */ if (!(base->flag & OB_FROMDUPLI)) { if (G.f & G_PICKSEL) { From 4818b3c97e371bca708961598433cef6ee9cb3fd Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 22 Nov 2016 12:34:23 +0100 Subject: [PATCH 283/590] Cycles: Fix re-definition of some functions on x32 arch --- intern/cycles/util/util_simd.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/cycles/util/util_simd.h b/intern/cycles/util/util_simd.h index f4f460d6cf6..756bd15ed25 100644 --- a/intern/cycles/util/util_simd.h +++ b/intern/cycles/util/util_simd.h @@ -229,7 +229,7 @@ __forceinline int __btr(int v, int i) { int r = 0; asm ("btr %1,%0" : "=r"(r) : "r"(i), "0"(v) : "flags"); return r; } -#if defined(__KERNEL_64_BIT__) || defined(__APPLE__) +#if (defined(__KERNEL_64_BIT__) || defined(__APPLE__)) && !(defined(__ILP32__) && defined(__x86_64__)) __forceinline size_t __bsf(size_t v) { size_t r = 0; asm ("bsf %1,%0" : "=r"(r) : "r"(v)); return r; } @@ -271,7 +271,7 @@ __forceinline unsigned int bitscan(unsigned int v) { #endif } -#if defined(__KERNEL_64_BIT__) || defined(__APPLE__) +#if (defined(__KERNEL_64_BIT__) || defined(__APPLE__)) && !(defined(__ILP32__) && defined(__x86_64__)) __forceinline size_t bitscan(size_t v) { #if defined(__KERNEL_AVX2__) #if defined(__KERNEL_64_BIT__) @@ -313,7 +313,7 @@ __forceinline unsigned int __bscf(unsigned int& v) return i; } -#if defined(__KERNEL_64_BIT__) || defined(__APPLE__) +#if (defined(__KERNEL_64_BIT__) || defined(__APPLE__)) && !(defined(__ILP32__) && defined(__x86_64__)) __forceinline size_t __bscf(size_t& v) { size_t i = bitscan(v); From cb694d6595c78767874baf021096cc217858c85b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 22 Nov 2016 12:43:59 +0100 Subject: [PATCH 284/590] GLog: Workaround compilation error on Hurd There is syscall headers but no SYS_Write syscall. --- extern/glog/src/raw_logging.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extern/glog/src/raw_logging.cc b/extern/glog/src/raw_logging.cc index 7a7409bbf34..8517129fa81 100644 --- a/extern/glog/src/raw_logging.cc +++ b/extern/glog/src/raw_logging.cc @@ -59,7 +59,8 @@ # include #endif -#if defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H) +// Hurd does not have SYS_write. +#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && !defined(__GNU__) # define safe_write(fd, s, len) syscall(SYS_write, fd, s, len) #else // Not so safe, but what can you do? From 751573ce6fff547b6a53769245814bc2d3fed17f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 22 Nov 2016 16:03:16 +0100 Subject: [PATCH 285/590] Fix T50034: Blender changes processor affinity unauthorized --- intern/cycles/util/util_system.cpp | 14 ++++++++++++ intern/cycles/util/util_system.h | 4 ++++ intern/cycles/util/util_task.cpp | 34 ++++++++++++++++++++++++++--- intern/cycles/util/util_windows.cpp | 15 +++++++++++++ intern/cycles/util/util_windows.h | 4 ++++ 5 files changed, 68 insertions(+), 3 deletions(-) diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp index d5fac9a0e34..2c7abbaacbb 100644 --- a/intern/cycles/util/util_system.cpp +++ b/intern/cycles/util/util_system.cpp @@ -89,6 +89,20 @@ int system_cpu_thread_count() return count; } +unsigned short system_cpu_process_groups(unsigned short max_groups, + unsigned short *grpups) +{ +#ifdef _WIN32 + unsigned short group_count = max_groups; + if(!GetProcessGroupAffinity(GetCurrentProcess(), &group_count, grpups)) { + return 0; + } + return group_count; +#else + return 0; +#endif +} + #if !defined(_WIN32) || defined(FREE_WINDOWS) static void __cpuid(int data[4], int selector) { diff --git a/intern/cycles/util/util_system.h b/intern/cycles/util/util_system.h index 557aab6cbae..ff61b260bed 100644 --- a/intern/cycles/util/util_system.h +++ b/intern/cycles/util/util_system.h @@ -30,6 +30,10 @@ int system_cpu_group_thread_count(int group); /* Get total number of threads in all groups. */ int system_cpu_thread_count(); +/* Get current process groups. */ +unsigned short system_cpu_process_groups(unsigned short max_groups, + unsigned short *grpups); + string system_cpu_brand_string(); int system_cpu_bits(); bool system_cpu_support_sse2(); diff --git a/intern/cycles/util/util_task.cpp b/intern/cycles/util/util_task.cpp index 352ba81c95a..0d1fed3ebbf 100644 --- a/intern/cycles/util/util_task.cpp +++ b/intern/cycles/util/util_task.cpp @@ -195,7 +195,8 @@ void TaskScheduler::init(int num_threads) if(users == 0) { do_exit = false; - if(num_threads == 0) { + const bool use_auto_threads = (num_threads == 0); + if(use_auto_threads) { /* automatic number of threads */ num_threads = system_cpu_thread_count(); } @@ -204,7 +205,18 @@ void TaskScheduler::init(int num_threads) /* launch threads that will be waiting for work */ threads.resize(num_threads); - int num_groups = system_cpu_group_count(); + const int num_groups = system_cpu_group_count(); + unsigned short num_process_groups; + vector process_groups; + int current_group_threads; + if(num_groups > 1) { + process_groups.resize(num_groups); + num_process_groups = system_cpu_process_groups(num_groups, + &process_groups[0]); + if(num_process_groups == 1) { + current_group_threads = system_cpu_group_thread_count(process_groups[0]); + } + } int thread_index = 0; for(int group = 0; group < num_groups; ++group) { /* NOTE: That's not really efficient from threading point of view, @@ -218,9 +230,25 @@ void TaskScheduler::init(int num_threads) group_thread < num_group_threads && thread_index < threads.size(); ++group_thread, ++thread_index) { + /* NOTE: Thread group of -1 means we would not force thread affinity. */ + int thread_group; + if(num_groups == 1) { + /* Use default affinity if there's only one CPU group in the system. */ + thread_group = -1; + } + else if(use_auto_threads && + num_process_groups == 1 && + num_threads <= current_group_threads) + { + /* If we fit into curent CPU group we also don't force any affinity. */ + thread_group = -1; + } + else { + thread_group = group; + } threads[thread_index] = new thread(function_bind(&TaskScheduler::thread_run, thread_index + 1), - group); + thread_group); } } } diff --git a/intern/cycles/util/util_windows.cpp b/intern/cycles/util/util_windows.cpp index ee5b3fd73c0..4de8483564b 100644 --- a/intern/cycles/util/util_windows.cpp +++ b/intern/cycles/util/util_windows.cpp @@ -28,6 +28,7 @@ CCL_NAMESPACE_BEGIN tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount; tGetActiveProcessorCount *GetActiveProcessorCount; tSetThreadGroupAffinity *SetThreadGroupAffinity; +tGetProcessGroupAffinity *GetProcessGroupAffinity; #endif static WORD GetActiveProcessorGroupCount_stub() @@ -50,6 +51,18 @@ static BOOL SetThreadGroupAffinity_stub( return TRUE; } +static BOOL GetProcessGroupAffinity_stub(HANDLE hProcess, + PUSHORT GroupCount, + PUSHORT GroupArray) +{ + if(*GroupCount < 1) { + return FALSE; + } + *GroupCount = 1; + GroupArray[0] = 0; + return TRUE; +} + static bool supports_numa() { #ifndef _M_X64 @@ -72,6 +85,7 @@ void util_windows_init_numa_groups() GetActiveProcessorGroupCount = GetActiveProcessorGroupCount_stub; GetActiveProcessorCount = GetActiveProcessorCount_stub; SetThreadGroupAffinity = SetThreadGroupAffinity_stub; + GetProcessGroupAffinity = GetProcessGroupAffinity_stub; return; } HMODULE kernel = GetModuleHandleA("kernel32.dll"); @@ -79,6 +93,7 @@ void util_windows_init_numa_groups() READ_SYMBOL(GetActiveProcessorGroupCount); READ_SYMBOL(GetActiveProcessorCount); READ_SYMBOL(SetThreadGroupAffinity); + READ_SYMBOL(GetProcessGroupAffinity); # undef READ_SUMBOL #endif } diff --git a/intern/cycles/util/util_windows.h b/intern/cycles/util/util_windows.h index ac61d5348c3..7ea3e65c2c5 100644 --- a/intern/cycles/util/util_windows.h +++ b/intern/cycles/util/util_windows.h @@ -39,10 +39,14 @@ typedef DWORD tGetActiveProcessorCount(WORD GroupNumber); typedef BOOL tSetThreadGroupAffinity(HANDLE hThread, const GROUP_AFFINITY *GroupAffinity, PGROUP_AFFINITY PreviousGroupAffinity); +typedef BOOL tGetProcessGroupAffinity(HANDLE hProcess, + PUSHORT GroupCount, + PUSHORT GroupArray); extern tGetActiveProcessorGroupCount *GetActiveProcessorGroupCount; extern tGetActiveProcessorCount *GetActiveProcessorCount; extern tSetThreadGroupAffinity *SetThreadGroupAffinity; +extern tGetProcessGroupAffinity *GetProcessGroupAffinity; #endif /* Make sure NUMA and processor groups API is initialized. */ From 67b1979c91d8608f078efc138c96afd0f6014579 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 22 Nov 2016 16:04:43 +0100 Subject: [PATCH 286/590] Install_deps: fix warning message not showing up in case build fails. Kinda stupid, but big nice warning about need to try clean build if something fails was only showing in case install_deps completed successfully... :P --- build_files/build_environment/install_deps.sh | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 5a02a96bdff..573ea4577e2 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -713,6 +713,21 @@ if [ "$WITH_ALL" = true -a "$OPENCOLLADA_SKIP" = false ]; then fi +WARNING "****WARNING****" +PRINT "If you are experiencing issues building Blender, _*TRY A FRESH, CLEAN BUILD FIRST*_!" +PRINT "The same goes for install_deps itself, if you encounter issues, please first erase everything in $SRC and $INST" +PRINT "(provided obviously you did not add anything yourself in those dirs!), and run install_deps.sh again!" +PRINT "Often, changes in the libs built by this script, or in your distro package, cannot be handled simply, so..." +PRINT "" +PRINT "You may also try to use the '--build-foo' options to bypass your distribution's packages" +PRINT "for some troublesome/buggy libraries..." +PRINT "" +PRINT "" +PRINT "Ran with:" +PRINT " install_deps.sh $COMMANDLINE" +PRINT "" +PRINT "" + # This has to be done here, because user might force some versions... PYTHON_SOURCE=( "https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tgz" ) @@ -785,6 +800,8 @@ However, if you are experiencing linking errors (also when building Blender itse Please note that until the transition to C++11-built libraries if completed in your distribution, situation will remain fuzzy and incompatibilities may happen..." + PRINT "" + PRINT "" CXXFLAGS="$CXXFLAGS -std=c++11" export CXXFLAGS fi @@ -4162,16 +4179,6 @@ print_info_ffmpeglink() { } print_info() { - PRINT "" - PRINT "" - WARNING "****WARNING****" - PRINT "If you are experiencing issues building Blender, _*TRY A FRESH, CLEAN BUILD FIRST*_!" - PRINT "The same goes for install_deps itself, if you encounter issues, please first erase everything in $SRC and $INST" - PRINT "(provided obviously you did not add anything yourself in those dirs!), and run install_deps.sh again!" - PRINT "Often, changes in the libs built by this script, or in your distro package, cannot be handled simply, so..." - PRINT "" - PRINT "You may also try to use the '--build-foo' options to bypass your distribution's packages" - PRINT "for some troublesome/buggy libraries..." PRINT "" PRINT "" PRINT "Ran with:" From 9aa8d1bc45bad3298a220ae8d4d5a9f600e3e5a9 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 22 Nov 2016 16:38:37 +0100 Subject: [PATCH 287/590] Cycles: Fix strict compilation warnings Should be no functional changes. --- intern/cycles/device/device_cuda.cpp | 6 +++++- intern/cycles/device/opencl/opencl_util.cpp | 10 ++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index a4818aa3b8d..fbb97f78e70 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -1418,7 +1418,11 @@ void device_cuda_info(vector& devices) cuDeviceGetAttribute(&pci_location[0], CU_DEVICE_ATTRIBUTE_PCI_DOMAIN_ID, num); cuDeviceGetAttribute(&pci_location[1], CU_DEVICE_ATTRIBUTE_PCI_BUS_ID, num); cuDeviceGetAttribute(&pci_location[2], CU_DEVICE_ATTRIBUTE_PCI_DEVICE_ID, num); - info.id = string_printf("CUDA_%s_%04x:%02x:%02x", name, pci_location[0], pci_location[1], pci_location[2]); + info.id = string_printf("CUDA_%s_%04x:%02x:%02x", + name, + (unsigned int)pci_location[0], + (unsigned int)pci_location[1], + (unsigned int)pci_location[2]); /* if device has a kernel timeout, assume it is used for display */ if(cuDeviceGetAttribute(&attr, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT, num) == CUDA_SUCCESS && attr == 1) { diff --git a/intern/cycles/device/opencl/opencl_util.cpp b/intern/cycles/device/opencl/opencl_util.cpp index 36eb70b8c85..82e1640e508 100644 --- a/intern/cycles/device/opencl/opencl_util.cpp +++ b/intern/cycles/device/opencl/opencl_util.cpp @@ -667,7 +667,10 @@ string OpenCLInfo::get_hardware_id(string platform_name, cl_device_id device_id) /* Use cl_amd_device_topology extension. */ cl_char topology[24]; if(clGetDeviceInfo(device_id, 0x4037, sizeof(topology), topology, NULL) == CL_SUCCESS && topology[0] == 1) { - return string_printf("%02x:%02x.%01x", topology[21], topology[22], topology[23]); + return string_printf("%02x:%02x.%01x", + (unsigned int)topology[21], + (unsigned int)topology[22], + (unsigned int)topology[23]); } } else if(platform_name == "NVIDIA CUDA") { @@ -675,7 +678,10 @@ string OpenCLInfo::get_hardware_id(string platform_name, cl_device_id device_id) cl_int bus_id, slot_id; if(clGetDeviceInfo(device_id, 0x4008, sizeof(cl_int), &bus_id, NULL) == CL_SUCCESS && clGetDeviceInfo(device_id, 0x4009, sizeof(cl_int), &slot_id, NULL) == CL_SUCCESS) { - return string_printf("%02x:%02x.%01x", bus_id, slot_id>>3, slot_id & 0x7); + return string_printf("%02x:%02x.%01x", + (unsigned int)(bus_id), + (unsigned int)(slot_id >> 3), + (unsigned int)(slot_id & 0x7)); } } /* No general way to get a hardware ID from OpenCL => give up. */ From 99c5c8befcfc319a4700384ff41e69bda1c66625 Mon Sep 17 00:00:00 2001 From: Luca Rood Date: Tue, 22 Nov 2016 14:38:43 -0200 Subject: [PATCH 288/590] Fix T49718: Wrong "Make Duplicates Real" behavior with "Keep Hierarchy" All objects were being parented to a single instance of each parent object, instead of their respective instances, when using dupliverts or dupligroups. Behavior was caused by the `persistent_id[0]` (vertex/face id) being ignored when computing `parent_gh` hash, which caused all instances to have the same hash, and thus only the first one was included. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D2370 --- source/blender/editors/object/object_add.c | 55 +++++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 8e64cdc9751..6647102acad 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1253,10 +1253,10 @@ static void copy_object_set_idnew(bContext *C) /********************* Make Duplicates Real ************************/ /** - * \note regarding hashing dupli-objects, skip the first member of #DupliObject.persistent_id + * \note regarding hashing dupli-objects when using OB_DUPLIGROUP, skip the first member of #DupliObject.persistent_id * since its a unique index and we only want to know if the group objects are from the same dupli-group instance. */ -static unsigned int dupliobject_hash(const void *ptr) +static unsigned int dupliobject_group_hash(const void *ptr) { const DupliObject *dob = ptr; unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); @@ -1267,7 +1267,20 @@ static unsigned int dupliobject_hash(const void *ptr) return hash; } -static bool dupliobject_cmp(const void *a_, const void *b_) +/** + * \note regarding hashing dupli-objects when NOT using OB_DUPLIGROUP, include the first member of #DupliObject.persistent_id + * since its the index of the vertex/face the object is instantiated on and we want to identify objects on the same vertex/face. + */ +static unsigned int dupliobject_hash(const void *ptr) +{ + const DupliObject *dob = ptr; + unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); + hash ^= (dob->persistent_id[0] ^ 0); + return hash; +} + +/* Compare function that matches dupliobject_group_hash */ +static bool dupliobject_group_cmp(const void *a_, const void *b_) { const DupliObject *a = a_; const DupliObject *b = b_; @@ -1290,6 +1303,24 @@ static bool dupliobject_cmp(const void *a_, const void *b_) return false; } +/* Compare function that matches dupliobject_hash */ +static bool dupliobject_cmp(const void *a_, const void *b_) +{ + const DupliObject *a = a_; + const DupliObject *b = b_; + + if (a->ob != b->ob) { + return true; + } + + if (a->persistent_id[0] != b->persistent_id[0]) { + return true; + } + + /* matching */ + return false; +} + static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, const bool use_base_parent, const bool use_hierarchy) @@ -1308,7 +1339,12 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (use_hierarchy || use_base_parent) { dupli_gh = BLI_ghash_ptr_new(__func__); if (use_hierarchy) { - parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + if (base->object->transflag & OB_DUPLIGROUP) { + parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); + } + else { + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + } } } @@ -1376,9 +1412,14 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, * they won't be read, this is simply for a hash lookup. */ DupliObject dob_key; dob_key.ob = ob_src_par; - memcpy(&dob_key.persistent_id[1], - &dob->persistent_id[1], - sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); + if (base->object->transflag & OB_DUPLIGROUP) { + memcpy(&dob_key.persistent_id[1], + &dob->persistent_id[1], + sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); + } + else { + dob_key.persistent_id[0] = dob->persistent_id[0]; + } ob_dst_par = BLI_ghash_lookup(parent_gh, &dob_key); } From 57141ea30e9ebe2e690d729ae765f48b839a8038 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 20 Nov 2016 20:50:16 +0100 Subject: [PATCH 289/590] Fix spelling in Cycles distance culling description. --- intern/cycles/blender/addon/properties.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index fed1524a816..607aafbfa1d 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -584,7 +584,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): cls.distance_cull_margin = FloatProperty( name="Cull Distance", - description="Cull objects which are further away from camera then this distance", + description="Cull objects which are further away from camera than this distance", default=50, min=0.0 ) From 411836d97c0338a7003c64d317d66ce38c559be0 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Wed, 23 Nov 2016 00:03:06 +0100 Subject: [PATCH 290/590] Fix Cycles device backwards compatibility error if device type is unavailable. --- intern/cycles/blender/addon/version_update.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/intern/cycles/blender/addon/version_update.py b/intern/cycles/blender/addon/version_update.py index 136080efadc..b2a745500a1 100644 --- a/intern/cycles/blender/addon/version_update.py +++ b/intern/cycles/blender/addon/version_update.py @@ -176,12 +176,18 @@ def do_versions(self): prop = bpy.context.user_preferences.addons[__package__].preferences system = bpy.context.user_preferences.system if not prop.is_property_set("compute_device_type"): - if system.legacy_compute_device_type == 1: - prop.compute_device_type = 'OPENCL' - elif system.legacy_compute_device_type == 2: - prop.compute_device_type = 'CUDA' - else: - prop.compute_device_type = 'NONE' + # Device might not currently be available so this can fail + try: + if system.legacy_compute_device_type == 1: + prop.compute_device_type = 'OPENCL' + elif system.legacy_compute_device_type == 2: + prop.compute_device_type = 'CUDA' + else: + prop.compute_device_type = 'NONE' + except: + pass + + # Init device list for UI prop.get_devices() # We don't modify startup file because it assumes to From a537e7b426b0d26c824e60b2efd6dba8ae0997bd Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 23 Nov 2016 10:59:54 +0100 Subject: [PATCH 291/590] Cycles: Fix strict compilation warnings --- intern/cycles/util/util_system.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/intern/cycles/util/util_system.cpp b/intern/cycles/util/util_system.cpp index 2c7abbaacbb..87d885c44cf 100644 --- a/intern/cycles/util/util_system.cpp +++ b/intern/cycles/util/util_system.cpp @@ -90,15 +90,17 @@ int system_cpu_thread_count() } unsigned short system_cpu_process_groups(unsigned short max_groups, - unsigned short *grpups) + unsigned short *groups) { #ifdef _WIN32 unsigned short group_count = max_groups; - if(!GetProcessGroupAffinity(GetCurrentProcess(), &group_count, grpups)) { + if(!GetProcessGroupAffinity(GetCurrentProcess(), &group_count, groups)) { return 0; } return group_count; #else + (void) max_groups; + (void) groups; return 0; #endif } From f2b57c35327eda6399659f42c326b96b8af49d82 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 23 Nov 2016 11:09:05 +0100 Subject: [PATCH 292/590] Depsgraph: Fix matrix_world driver source Reported by Dalai in IRC, thanks! --- source/blender/depsgraph/intern/depsgraph.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index 9a4a35a5a35..5604044e123 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -189,16 +189,23 @@ static bool pointer_to_component_node_criteria(const PointerRNA *ptr, /* Transforms props? */ if (prop) { const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop); - + /* TODO(sergey): How to optimize this? */ if (strstr(prop_identifier, "location") || strstr(prop_identifier, "rotation") || - strstr(prop_identifier, "scale")) + strstr(prop_identifier, "scale") || + strstr(prop_identifier, "matrix_")) { *type = DEPSNODE_TYPE_TRANSFORM; return true; } + else if (strstr(prop_identifier, "data")) { + /* We access object.data, most likely a geometry. + * Might be a bone tho.. + */ + *type = DEPSNODE_TYPE_GEOMETRY; + return true; + } } - // ... } else if (ptr->type == &RNA_ShapeKey) { Key *key = (Key *)ptr->id.data; From def365e252524915f1c02bc7172e0113c21f5ada Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 23 Nov 2016 11:33:09 +0100 Subject: [PATCH 293/590] Fix T50100: Cycles SeparateRGBNode Red socket defined wrong Spotted by David (bocs), thanks! --- intern/cycles/render/nodes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index f293af3c40a..3fb2bb1cf92 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -3993,7 +3993,7 @@ NODE_DEFINE(SeparateRGBNode) SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_FLOAT(g, "R"); + SOCKET_OUT_FLOAT(r, "R"); SOCKET_OUT_FLOAT(g, "G"); SOCKET_OUT_FLOAT(b, "B"); From 403f00e558992dd040f9d13c142e28781f7cfe84 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 24 Nov 2016 11:14:45 +1100 Subject: [PATCH 294/590] Fix prefs UI when built w/o Cycles --- release/scripts/startup/bl_ui/space_userpref.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index bdbb6330232..e5b6a94c1ab 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -429,8 +429,11 @@ class USERPREF_PT_system(Panel): col.separator() - if userpref.addons.find('cycles') != -1: - userpref.addons['cycles'].preferences.draw_impl(col, context) + if bpy.app.build_options.cycles: + addon = userpref.addons.get("cycles") + if addon is not None: + addon.preferences.draw_impl(col, context) + del addon if hasattr(system, "opensubdiv_compute_type"): col.label(text="OpenSubdiv compute:") From 4d3d2d02993488dda03094ecc580fe26ebec4f39 Mon Sep 17 00:00:00 2001 From: Martijn Berger Date: Thu, 24 Nov 2016 13:43:29 +0100 Subject: [PATCH 295/590] Remove unused vector icons from RNA --- source/blender/editors/include/UI_icons.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index e016e014a1a..8579778ff79 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -1005,15 +1005,6 @@ DEF_ICON(MATCAP_23) DEF_ICON(MATCAP_24) /* vector icons, VICO_ prefix added */ -DEF_VICO(VIEW3D_VEC) -DEF_VICO(EDIT_VEC) -DEF_VICO(EDITMODE_VEC_DEHLT) -DEF_VICO(EDITMODE_VEC_HLT) -DEF_VICO(DISCLOSURE_TRI_RIGHT_VEC) -DEF_VICO(DISCLOSURE_TRI_DOWN_VEC) -DEF_VICO(MOVE_UP_VEC) -DEF_VICO(MOVE_DOWN_VEC) -DEF_VICO(X_VEC) DEF_VICO(SMALL_TRI_RIGHT_VEC) DEF_VICO(KEYTYPE_KEYFRAME_VEC) From 729affe7c99a3fef892ec0810fc89dbead10db8e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 24 Nov 2016 16:37:27 +0100 Subject: [PATCH 296/590] Cycles: Avoid divisions by zero in volume sampling code Was giving huge artifacts in the barber shop file here in the studio, Maybe not fully optimal solution, but committing it for now to have closer look later. --- intern/cycles/kernel/kernel_volume.h | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index 0f45b0e7d60..dd7b0d9812d 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -245,11 +245,18 @@ ccl_device float kernel_volume_equiangular_sample(Ray *ray, float3 light_P, floa float t = ray->t; float delta = dot((light_P - ray->P) , ray->D); - float D = sqrtf(len_squared(light_P - ray->P) - delta * delta); + float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta); + if(UNLIKELY(D == 0.0f)) { + *pdf = 0.0f; + return 0.0f; + } float theta_a = -atan2f(delta, D); float theta_b = atan2f(t - delta, D); float t_ = D * tanf((xi * theta_b) + (1 - xi) * theta_a); - + if(UNLIKELY(theta_b == theta_a)) { + *pdf = 0.0f; + return 0.0f; + } *pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_)); return min(t, delta + t_); /* min is only for float precision errors */ @@ -258,13 +265,19 @@ ccl_device float kernel_volume_equiangular_sample(Ray *ray, float3 light_P, floa ccl_device float kernel_volume_equiangular_pdf(Ray *ray, float3 light_P, float sample_t) { float delta = dot((light_P - ray->P) , ray->D); - float D = sqrtf(len_squared(light_P - ray->P) - delta * delta); + float D = safe_sqrtf(len_squared(light_P - ray->P) - delta * delta); + if(UNLIKELY(D == 0.0f)) { + return 0.0f; + } float t = ray->t; float t_ = sample_t - delta; float theta_a = -atan2f(delta, D); float theta_b = atan2f(t - delta, D); + if(UNLIKELY(theta_b == theta_a)) { + return 0.0f; + } float pdf = D / ((theta_b - theta_a) * (D * D + t_ * t_)); @@ -958,6 +971,9 @@ ccl_device VolumeIntegrateResult kernel_volume_decoupled_scatter( mis_weight = 2.0f*power_heuristic(pdf, distance_pdf); } } + if(sample_t < 1e-6f) { + return VOLUME_PATH_SCATTERED; + } /* compute transmittance up to this step */ if(step != segment->steps) From 4f4e0ecdcfea277e2b310e1abbe1f570a4e997f6 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Nov 2016 11:34:15 +1100 Subject: [PATCH 297/590] Remove eekadoodle workaround for add torus This is no longer needed since moving to MPoly/MLoop data structure. Also use 3x3 matrix for transforming instead of quaternion (slightly better performance). --- .../startup/bl_operators/add_mesh_torus.py | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index f12e7484e64..1f0acba7e52 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -32,25 +32,24 @@ from bpy_extras import object_utils def add_torus(major_rad, minor_rad, major_seg, minor_seg): from math import cos, sin, pi - from mathutils import Vector, Quaternion + from mathutils import Vector, Matrix - PI_2 = pi * 2.0 - z_axis = 0.0, 0.0, 1.0 + pi_2 = pi * 2.0 verts = [] faces = [] i1 = 0 tot_verts = major_seg * minor_seg for major_index in range(major_seg): - quat = Quaternion(z_axis, (major_index / major_seg) * PI_2) + matrix = Matrix.Rotation((major_index / major_seg) * pi_2, 3, 'Z') for minor_index in range(minor_seg): - angle = 2 * pi * minor_index / minor_seg + angle = pi_2 * minor_index / minor_seg - vec = quat * Vector((major_rad + (cos(angle) * minor_rad), - 0.0, - (sin(angle) * minor_rad), - )) + vec = matrix * Vector((major_rad + (cos(angle) * minor_rad), + 0.0, + sin(angle) * minor_rad, + )) verts.extend(vec[:]) @@ -58,7 +57,6 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg): i2 = (major_index) * minor_seg i3 = i1 + minor_seg i4 = i2 + minor_seg - else: i2 = i1 + 1 i3 = i1 + minor_seg @@ -71,11 +69,7 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg): if i4 >= tot_verts: i4 = i4 - tot_verts - # stupid eekadoodle - if i2: - faces.extend([i1, i3, i4, i2]) - else: - faces.extend([i2, i1, i3, i4]) + faces.extend([i1, i3, i4, i2]) i1 += 1 From d30a0239a2fb1bf28befc547d9c4986b6be4d662 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Nov 2016 14:20:45 +1100 Subject: [PATCH 298/590] Fix Torus default UV's offset outside 0-1 bounds When major/minor segments didn't fit evenly into 4, the UV's would move outside the UV bounds. --- .../startup/bl_operators/add_mesh_torus.py | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/release/scripts/startup/bl_operators/add_mesh_torus.py b/release/scripts/startup/bl_operators/add_mesh_torus.py index 1f0acba7e52..247b91e147f 100644 --- a/release/scripts/startup/bl_operators/add_mesh_torus.py +++ b/release/scripts/startup/bl_operators/add_mesh_torus.py @@ -77,31 +77,56 @@ def add_torus(major_rad, minor_rad, major_seg, minor_seg): def add_uvs(mesh, minor_seg, major_seg): + from math import fmod + mesh.uv_textures.new() uv_data = mesh.uv_layers.active.data polygons = mesh.polygons u_step = 1.0 / major_seg v_step = 1.0 / minor_seg + + # Round UV's, needed when segments aren't divisible by 4. + u_init = 0.5 + fmod(0.5, u_step) + v_init = 0.5 + fmod(0.5, v_step) + + # Calculate wrapping value under 1.0 to prevent + # float precision errors wrapping at the wrong step. + u_wrap = 1.0 - (u_step / 2.0) + v_wrap = 1.0 - (v_step / 2.0) + vertex_index = 0 - u = 0.5 + u_prev = u_init + u_next = u_prev + u_step for major_index in range(major_seg): - v = 0.5 + v_prev = v_init + v_next = v_prev + v_step for minor_index in range(minor_seg): loops = polygons[vertex_index].loop_indices if minor_index == minor_seg - 1 and major_index == 0: - uv_data[loops[1]].uv = (u, v) - uv_data[loops[2]].uv = (u + u_step, v) - uv_data[loops[0]].uv = (u, v + v_step) - uv_data[loops[3]].uv = (u + u_step, v + v_step) + uv_data[loops[1]].uv = u_prev, v_prev + uv_data[loops[2]].uv = u_next, v_prev + uv_data[loops[0]].uv = u_prev, v_next + uv_data[loops[3]].uv = u_next, v_next else: - uv_data[loops[0]].uv = (u, v) - uv_data[loops[1]].uv = (u + u_step, v) - uv_data[loops[3]].uv = (u, v + v_step) - uv_data[loops[2]].uv = (u + u_step, v + v_step) - v = (v + v_step) % 1.0 + uv_data[loops[0]].uv = u_prev, v_prev + uv_data[loops[1]].uv = u_next, v_prev + uv_data[loops[3]].uv = u_prev, v_next + uv_data[loops[2]].uv = u_next, v_next + + if v_next > v_wrap: + v_prev = v_next - 1.0 + else: + v_prev = v_next + v_next = v_prev + v_step + vertex_index += 1 - u = (u + u_step) % 1.0 + + if u_next > u_wrap: + u_prev = u_next - 1.0 + else: + u_prev = u_next + u_next = u_prev + u_step class AddTorus(Operator, object_utils.AddObjectHelper): From e1e49fd1a8a5bca7f95ba230a7daf12fb059779b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Nov 2016 16:20:30 +1100 Subject: [PATCH 299/590] Math Lib: rotate matrix cleanup - Remove 'rotate_m2', unlike 'rotate_m4' it created a new matrix duplicating 'angle_to_mat2' - now used instead. (better avoid matching functions having different behavior). - Add 'axis_angle_to_mat4_single', convenience wrapper for 'axis_angle_to_mat3_single'. - Replace 'unit_m4(), rotate_m4()' with a single call to 'axis_angle_to_mat4_single'. --- source/blender/alembic/intern/abc_transform.cc | 3 +-- source/blender/alembic/intern/abc_util.cc | 3 +-- source/blender/blenkernel/intern/object_dupli.c | 3 +-- .../blender/blenkernel/intern/tracking_stabilize.c | 4 ++-- source/blender/blenlib/BLI_math_matrix.h | 1 - source/blender/blenlib/BLI_math_rotation.h | 3 ++- source/blender/blenlib/intern/math_geom.c | 3 +-- source/blender/blenlib/intern/math_matrix.c | 14 +++++++------- source/blender/blenlib/intern/math_rotation.c | 7 +++++++ source/blender/collada/collada_internal.cpp | 7 ++----- source/blender/editors/mesh/editmesh_knife.c | 2 +- source/blender/editors/object/object_warp.c | 3 +-- source/blender/editors/sculpt_paint/sculpt.c | 7 +++---- .../blender/editors/uvedit/uvedit_smart_stitch.c | 2 +- source/blender/modifiers/intern/MOD_screw.c | 6 ++---- 15 files changed, 32 insertions(+), 36 deletions(-) diff --git a/source/blender/alembic/intern/abc_transform.cc b/source/blender/alembic/intern/abc_transform.cc index 7f8984f9970..e2fc7674c4e 100644 --- a/source/blender/alembic/intern/abc_transform.cc +++ b/source/blender/alembic/intern/abc_transform.cc @@ -92,8 +92,7 @@ void AbcTransformWriter::do_write() /* Only apply rotation to root camera, parenting will propagate it. */ if (m_object->type == OB_CAMERA && !has_parent_camera(m_object)) { float rot_mat[4][4]; - unit_m4(rot_mat); - rotate_m4(rot_mat, 'X', -M_PI_2); + axis_angle_to_mat4_single(rot_mat, 'X', -M_PI_2); mul_m4_m4m4(mat, mat, rot_mat); } diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index f87d18605d4..979a72fcf4e 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -221,8 +221,7 @@ void convert_matrix(const Imath::M44d &xform, Object *ob, if (ob->type == OB_CAMERA) { float cam_to_yup[4][4]; - unit_m4(cam_to_yup); - rotate_m4(cam_to_yup, 'X', M_PI_2); + axis_angle_to_mat4_single(cam_to_yup, 'X', M_PI_2); mul_m4_m4m4(r_mat, r_mat, cam_to_yup); } diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 14cc5ec0849..e3b801b3193 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -642,8 +642,7 @@ static void make_duplis_font(const DupliContext *ctx) float rmat[4][4]; zero_v3(obmat[3]); - unit_m4(rmat); - rotate_m4(rmat, 'Z', -ct->rot); + axis_angle_to_mat4_single(rmat, 'Z', -ct->rot); mul_m4_m4m4(obmat, obmat, rmat); } diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c index b8949f9a0de..36b24fbb2dc 100644 --- a/source/blender/blenkernel/intern/tracking_stabilize.c +++ b/source/blender/blenkernel/intern/tracking_stabilize.c @@ -587,7 +587,7 @@ static void compensate_rotation_center(const int size, float aspect, copy_v2_v2(intended_pivot, pivot); copy_v2_v2(rotated_pivot, pivot); - rotate_m2(rotation_mat, +angle); + angle_to_mat2(rotation_mat, +angle); sub_v2_v2(rotated_pivot, origin); mul_m2v2(rotation_mat, rotated_pivot); mul_v2_fl(rotated_pivot, scale); @@ -967,7 +967,7 @@ static void initialize_track_for_stabilization(StabContext *ctx, pos[0] *= aspect; angle = average_angle - atan2f(pos[1],pos[0]); - rotate_m2(local_data->stabilization_rotation_base, angle); + angle_to_mat2(local_data->stabilization_rotation_base, angle); /* Per track baseline value for zoom. */ len = len_v2(pos) + SCALE_ERROR_LIMIT_BIAS; diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 8124e07dd47..d0dfad2a02f 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -219,7 +219,6 @@ void mat4_to_size(float r[3], float M[4][4]); void translate_m4(float mat[4][4], float tx, float ty, float tz); void rotate_m4(float mat[4][4], const char axis, const float angle); -void rotate_m2(float mat[2][2], const float angle); void transform_pivot_set_m4(float mat[4][4], const float pivot[3]); void mat3_to_rot_size(float rot[3][3], float size[3], float mat3[3][3]); diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h index 24c20ee7b50..d60be30e10d 100644 --- a/source/blender/blenlib/BLI_math_rotation.h +++ b/source/blender/blenlib/BLI_math_rotation.h @@ -122,8 +122,9 @@ void mat3_to_axis_angle(float axis[3], float *angle, float M[3][3]); void mat4_to_axis_angle(float axis[3], float *angle, float M[4][4]); void quat_to_axis_angle(float axis[3], float *angle, const float q[4]); -void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle); void angle_to_mat2(float R[2][2], const float angle); +void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle); +void axis_angle_to_mat4_single(float R[4][4], const char axis, const float angle); void axis_angle_to_quat_single(float q[4], const char axis, const float angle); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index f31d0935b77..0790d65345d 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -3917,10 +3917,9 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py float sine, cosine, hyp, hyp1, dx, dy, dz; float mat1[4][4]; - unit_m4(mat); unit_m4(mat1); - rotate_m4(mat, 'Z', -twist); + axis_angle_to_mat3_single(mat, 'Z', -twist); dx = px - vx; dy = py - vy; diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index c9c61d5c878..7176686df54 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -1625,6 +1625,13 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz) mat[3][2] += (Tx * mat[0][2] + Ty * mat[1][2] + Tz * mat[2][2]); } +/** + * Rotate a matrix in-place. + * + * \note To create a new rotation matrix see: + * #axis_angle_to_mat4_single, #axis_angle_to_mat3_single, #angle_to_mat2 + * (axis & angle args are compatible). + */ void rotate_m4(float mat[4][4], const char axis, const float angle) { int col; @@ -1665,13 +1672,6 @@ void rotate_m4(float mat[4][4], const char axis, const float angle) } } -void rotate_m2(float mat[2][2], const float angle) -{ - mat[0][0] = mat[1][1] = cosf(angle); - mat[0][1] = sinf(angle); - mat[1][0] = -mat[0][1]; -} - /** * Scale or rotate around a pivot point, * a convenience function to avoid having to do inline. diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index b285a74b8ac..9b5dad3f767 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -1009,6 +1009,13 @@ void mat4_to_axis_angle(float axis[3], float *angle, float mat[4][4]) quat_to_axis_angle(axis, angle, q); } +void axis_angle_to_mat4_single(float mat[4][4], const char axis, const float angle) +{ + float mat3[3][3]; + axis_angle_to_mat3_single(mat3, axis, angle); + copy_m4_m3(mat, mat3); +} + /* rotation matrix from a single axis */ void axis_angle_to_mat3_single(float mat[3][3], const char axis, const float angle) { diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp index 38855013ee1..e1a13559b08 100644 --- a/source/blender/collada/collada_internal.cpp +++ b/source/blender/collada/collada_internal.cpp @@ -33,11 +33,8 @@ UnitConverter::UnitConverter() : unit(), up_axis(COLLADAFW::FileInfo::Z_UP) { - unit_m4(x_up_mat4); - rotate_m4(x_up_mat4, 'Y', -0.5 * M_PI); - - unit_m4(y_up_mat4); - rotate_m4(y_up_mat4, 'X', 0.5 * M_PI); + axis_angle_to_mat4_single(x_up_mat4, 'Y', -0.5 * M_PI); + axis_angle_to_mat4_single(y_up_mat4, 'X', 0.5 * M_PI); unit_m4(z_up_mat4); unit_m4(scale_mat4); diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index a84b8d9dcc8..44453d03ade 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -2140,7 +2140,7 @@ static float snap_v2_angle(float r[2], const float v[2], const float v_ref[2], f normalize_v2_v2(v_unit, v); angle = angle_signed_v2v2(v_unit, v_ref); angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle; - rotate_m2(m2, angle_delta); + angle_to_mat2(m2, angle_delta); mul_v2_m2v2(r, m2, v); return angle + angle_delta; diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c index 9f4da87903d..92b82e2a31b 100644 --- a/source/blender/editors/object/object_warp.c +++ b/source/blender/editors/object/object_warp.c @@ -53,8 +53,7 @@ static void object_warp_calc_view_matrix(float r_mat_view[4][4], float r_center_ float viewmat_roll[4][4]; /* apply the rotation offset by rolling the view */ - unit_m4(mat_offset); - rotate_m4(mat_offset, 'Z', offset_angle); + axis_angle_to_mat4_single(mat_offset, 'Z', offset_angle); mul_m4_m4m4(viewmat_roll, mat_offset, viewmat); /* apply the view and the object matrix */ diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 53434b18d06..ef2f2d36ab7 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -821,10 +821,9 @@ static float calc_overlap(StrokeCache *cache, const char symm, const char axis, flip_v3_v3(mirror, cache->true_location, symm); if (axis != 0) { - float mat[4][4]; - unit_m4(mat); - rotate_m4(mat, axis, angle); - mul_m4_v3(mat, mirror); + float mat[3][3]; + axis_angle_to_mat3_single(mat, axis, angle); + mul_m3_v3(mat, mirror); } /* distsq = len_squared_v3v3(mirror, cache->traced_location); */ diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 59442e89787..50aec737c8e 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -459,7 +459,7 @@ static void stitch_calculate_island_snapping( island_stitch_data[i].num_rot_elements_neg) / totelem; } - rotate_m2(rotation_mat, rotation); + angle_to_mat2(rotation_mat, rotation); numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); element = &state->element_map->buf[state->element_map->islandIndices[i]]; for (j = 0; j < numOfIslandUVs; j++, element++) { diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c index df94975e274..290e19736bb 100644 --- a/source/blender/modifiers/intern/MOD_screw.c +++ b/source/blender/modifiers/intern/MOD_screw.c @@ -798,13 +798,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, if (ltmd->ob_axis) { axis_angle_normalized_to_mat3(mat3, axis_vec, step_angle); - copy_m4_m3(mat, mat3); } else { - unit_m4(mat); - rotate_m4(mat, axis_char, step_angle); - copy_m3_m4(mat3, mat); + axis_angle_to_mat3_single(mat3, axis_char, step_angle); } + copy_m4_m3(mat, mat3); if (screw_ofs) madd_v3_v3fl(mat[3], axis_vec, screw_ofs * ((float)step / (float)(step_tot - 1))); From bcd0d8584fbd000a4b2b835f33b7c89fe15609fc Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 25 Nov 2016 21:00:32 +1100 Subject: [PATCH 300/590] Math Lib: avoid temp array for rotate_m4 No need to have temp array storage, avoid 2x loops. --- source/blender/blenlib/intern/math_matrix.c | 34 +++++++++------------ 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 7176686df54..9a60c670ec7 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -1634,39 +1634,33 @@ void translate_m4(float mat[4][4], float Tx, float Ty, float Tz) */ void rotate_m4(float mat[4][4], const char axis, const float angle) { - int col; - float temp[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - float cosine, sine; + const float angle_cos = cosf(angle); + const float angle_sin = sinf(angle); assert(axis >= 'X' && axis <= 'Z'); - cosine = cosf(angle); - sine = sinf(angle); switch (axis) { case 'X': - for (col = 0; col < 4; col++) - temp[col] = cosine * mat[1][col] + sine * mat[2][col]; - for (col = 0; col < 4; col++) { - mat[2][col] = -sine * mat[1][col] + cosine * mat[2][col]; - mat[1][col] = temp[col]; + for (int col = 0; col < 4; col++) { + float temp = angle_cos * mat[1][col] + angle_sin * mat[2][col]; + mat[2][col] = -angle_sin * mat[1][col] + angle_cos * mat[2][col]; + mat[1][col] = temp; } break; case 'Y': - for (col = 0; col < 4; col++) - temp[col] = cosine * mat[0][col] - sine * mat[2][col]; - for (col = 0; col < 4; col++) { - mat[2][col] = sine * mat[0][col] + cosine * mat[2][col]; - mat[0][col] = temp[col]; + for (int col = 0; col < 4; col++) { + float temp = angle_cos * mat[0][col] - angle_sin * mat[2][col]; + mat[2][col] = angle_sin * mat[0][col] + angle_cos * mat[2][col]; + mat[0][col] = temp; } break; case 'Z': - for (col = 0; col < 4; col++) - temp[col] = cosine * mat[0][col] + sine * mat[1][col]; - for (col = 0; col < 4; col++) { - mat[1][col] = -sine * mat[0][col] + cosine * mat[1][col]; - mat[0][col] = temp[col]; + for (int col = 0; col < 4; col++) { + float temp = angle_cos * mat[0][col] + angle_sin * mat[1][col]; + mat[1][col] = -angle_sin * mat[0][col] + angle_cos * mat[1][col]; + mat[0][col] = temp; } break; } From 265e5def76cc08f633e8851236af1ee903d87ff0 Mon Sep 17 00:00:00 2001 From: lazydodo Date: Fri, 25 Nov 2016 12:02:37 -0700 Subject: [PATCH 301/590] Fix T50104, Race condition in SVMShaderManager::device_update_shader --- intern/cycles/render/svm.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/intern/cycles/render/svm.cpp b/intern/cycles/render/svm.cpp index 9d3f49a3c84..955b892f4c3 100644 --- a/intern/cycles/render/svm.cpp +++ b/intern/cycles/render/svm.cpp @@ -71,14 +71,13 @@ void SVMShaderManager::device_update_shader(Scene *scene, scene->light_manager->need_update = true; } - /* We only calculate offset and do re-allocation from the locked block, - * actual copy we do after the lock is releases to hopefully gain some - * percent of performance. + /* The copy needs to be done inside the lock, if another thread resizes the array + * while memcpy is running, it'll be copying into possibly invalid/freed ram. */ nodes_lock_.lock(); size_t global_nodes_size = global_svm_nodes->size(); global_svm_nodes->resize(global_nodes_size + svm_nodes.size()); - nodes_lock_.unlock(); + /* Offset local SVM nodes to a global address space. */ int4& jump_node = global_svm_nodes->at(shader->id); jump_node.y = svm_nodes[0].y + global_nodes_size - 1; @@ -88,6 +87,7 @@ void SVMShaderManager::device_update_shader(Scene *scene, memcpy(&global_svm_nodes->at(global_nodes_size), &svm_nodes[1], sizeof(int4) * (svm_nodes.size() - 1)); + nodes_lock_.unlock(); } void SVMShaderManager::device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) From d464a7c4418608baae4946429c16a2925aed4ba7 Mon Sep 17 00:00:00 2001 From: Gaia Clary Date: Sat, 26 Nov 2016 18:48:50 +0100 Subject: [PATCH 302/590] fix T50118: Added missing assignment of Bone Roll --- source/blender/collada/ArmatureImporter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp index ae43c0a69d2..17334ca326c 100644 --- a/source/blender/collada/ArmatureImporter.cpp +++ b/source/blender/collada/ArmatureImporter.cpp @@ -169,6 +169,7 @@ int ArmatureImporter::create_bone(SkinInfo *skin, COLLADAFW::Node *node, EditBon float angle; mat4_to_loc_rot_size(loc, rot, size, mat); mat3_to_vec_roll(rot, NULL, &angle); + bone->roll = angle; } copy_v3_v3(bone->head, mat[3]); add_v3_v3v3(bone->tail, bone->head, tail); //tail must be non zero From ce3cae81f67243b6d87d32c14dc84be57c969026 Mon Sep 17 00:00:00 2001 From: lazydodo Date: Sat, 26 Nov 2016 17:00:25 -0700 Subject: [PATCH 303/590] [msvc2015] Fix cmake warnings regarding backslashes in path of the run-time libraries --- source/creator/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index aa0a213cf64..04a79f6498f 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -1185,7 +1185,7 @@ if(WIN32 AND NOT WITH_PYTHON_MODULE) message(FATAL_ERROR "Windows 10 SDK directory not found") endif() endif() - + FILE(TO_CMAKE_PATH ${KITSPATH} KITSPATH) install( FILES ${KITSPATH}/api-ms-win-core-file-l1-2-0.dll From d20f5b7de0975a9f18d4ab34a5d9f5092c7e9900 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sat, 26 Nov 2016 16:47:54 +1300 Subject: [PATCH 304/590] Typo fix --- source/blender/editors/gpencil/gpencil_utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 8073b13ba10..76e85f20c36 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -915,7 +915,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) { From e2d223461efeea4792defb254c692828266478d1 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 28 Nov 2016 02:28:12 +1300 Subject: [PATCH 305/590] Fix T50123 - GreasePencil: Modifying name of new color in new palette via bpy segfaults When there were no prior palettes, creating a new one didn't automatically make it active. This caused problems when trying to rename the color, as the RNA code assumed that if there's a color, it must come from the active palette. This commit partially fixes the problem by ensuring that if there are no palettes, the first one will always be made active. --- source/blender/blenkernel/intern/gpencil.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 2242113b79b..c22fd0e5a3c 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -382,7 +382,8 @@ bGPDpalette *BKE_gpencil_palette_addnew(bGPdata *gpd, const char *name, bool set sizeof(palette->info)); /* make this one the active one */ - if (setactive) { + /* NOTE: Always make this active if there's nothing else yet (T50123) */ + if ((setactive) || (gpd->palettes.first == gpd->palettes.last)) { BKE_gpencil_palette_setactive(gpd, palette); } From 452028c77ccea3846c7e1104c50e682b9b957ecc Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 28 Nov 2016 02:32:03 +1300 Subject: [PATCH 306/590] GPencil RNA API: "set_active" option for layer.new() and palette.new() is now true/enabled by default To bring the API more into line with the UI (and the general expected behaviour of Blender when it comes to adding stuff), newly created layers and palettes will be made the active ones by default. It's possible to override this behaviour still (e.g. in cases where you're auto-generating a large number of them), but otherwise, this change will help prevent errors like T50123. --- source/blender/makesrna/intern/rna_gpencil.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 7ba89538b18..6abead48d99 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1354,7 +1354,7 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a new grease pencil layer"); parm = RNA_def_string(func, "name", "GPencilLayer", MAX_NAME, "Name", "Name of the layer"); RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created layer to the active layer"); + RNA_def_boolean(func, "set_active", true, "Set Active", "Set the newly created layer to the active layer"); parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "The newly created layer"); RNA_def_function_return(func, parm); @@ -1557,7 +1557,7 @@ static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a new grease pencil palette"); parm = RNA_def_string(func, "name", "GPencilPalette", MAX_NAME, "Name", "Name of the palette"); RNA_def_property_flag(parm, PROP_REQUIRED); - RNA_def_boolean(func, "set_active", 0, "Set Active", "Activate the newly created palette"); + RNA_def_boolean(func, "set_active", true, "Set Active", "Activate the newly created palette"); parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The newly created palette"); RNA_def_function_return(func, parm); From 841f3e49725685b64f54c8dff6f29dab7bc223ee Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 28 Nov 2016 02:33:11 +1300 Subject: [PATCH 307/590] A number of other minor RNA fixes and precautionary safeguards against further crashes here --- source/blender/blenkernel/intern/gpencil.c | 12 ++++++++++-- source/blender/makesrna/intern/rna_gpencil.c | 6 +++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index c22fd0e5a3c..cd2eac078cf 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -1264,7 +1264,11 @@ void BKE_gpencil_palettecolor_changename(bGPdata *gpd, char *oldname, const char bGPDlayer *gpl; bGPDframe *gpf; bGPDstroke *gps; - + + /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */ + if (ELEM(NULL, gpd, oldname, newname)) + return; + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { for (gps = gpf->strokes.first; gps; gps = gps->next) { @@ -1283,7 +1287,11 @@ void BKE_gpencil_palettecolor_delete_strokes(struct bGPdata *gpd, char *name) bGPDlayer *gpl; bGPDframe *gpf; bGPDstroke *gps, *gpsn; - + + /* Sanity checks (gpd may not be set in the RNA pointers sometimes) */ + if (ELEM(NULL, gpd, name)) + return; + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { for (gps = gpf->strokes.first; gps; gps = gpsn) { diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 6abead48d99..16aa60e1b91 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -585,11 +585,11 @@ static bGPDframe *rna_GPencil_frame_copy(bGPDlayer *layer, bGPDframe *src) static bGPDlayer *rna_GPencil_layer_new(bGPdata *gpd, const char *name, int setactive) { - bGPDlayer *gl = BKE_gpencil_layer_addnew(gpd, name, setactive != 0); + bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, name, setactive != 0); WM_main_add_notifier(NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - return gl; + return gpl; } static void rna_GPencil_layer_remove(bGPdata *gpd, ReportList *reports, PointerRNA *layer_ptr) @@ -1443,7 +1443,7 @@ static void rna_def_gpencil_palettecolor(BlenderRNA *brna) prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PC_COLOR_ONIONSKIN); RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0); - RNA_def_property_ui_text(prop, "Ghost", "Display the color in onion skinning"); + RNA_def_property_ui_text(prop, "Show in Ghosts", "Display strokes using this color when showing onion skins"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); /* Draw Style */ From 96ed2b0ce05ae46d81c38476133768d8b07fdc71 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 28 Nov 2016 17:29:27 +1100 Subject: [PATCH 308/590] Remove sensor-size to int conversion Currently harmless since the value is always set at its default (32). Even so, it's confusing since its used with floats after. --- source/blender/blenkernel/intern/camera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 85ce399b770..30f17582bf5 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -252,7 +252,7 @@ void BKE_camera_params_from_view3d(CameraParams *params, const View3D *v3d, cons } else if (rv3d->persp == RV3D_ORTHO) { /* orthographic view */ - int sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y); + float sensor_size = BKE_camera_sensor_size(params->sensor_fit, params->sensor_x, params->sensor_y); params->clipend *= 0.5f; // otherwise too extreme low zbuffer quality params->clipsta = -params->clipend; From 3340acd46b6bb4ab34f16b1dcd25850c92b353c4 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Mon, 28 Nov 2016 17:23:44 +0100 Subject: [PATCH 309/590] Fix T50065: Audaspace: some values of the lower limit of Factory.limit causes the factory not to play Backport of upstream audaspace bugfix (ddd9a4d). --- intern/audaspace/FX/AUD_LimiterReader.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/audaspace/FX/AUD_LimiterReader.cpp b/intern/audaspace/FX/AUD_LimiterReader.cpp index 9c1d4443b06..7d850ac7b5f 100644 --- a/intern/audaspace/FX/AUD_LimiterReader.cpp +++ b/intern/audaspace/FX/AUD_LimiterReader.cpp @@ -110,10 +110,10 @@ void AUD_LimiterReader::read(int& length, bool& eos, sample_t* buffer) eos = true; } - if(position < m_start * rate) + if(position < int(m_start * rate)) { int len2 = length; - for(int len = m_start * rate - position; + for(int len = int(m_start * rate) - position; len2 == length && !eos; len -= length) { From df687837f822352de3a052b0abc8e1976c583aef Mon Sep 17 00:00:00 2001 From: lazydodo Date: Mon, 28 Nov 2016 10:12:21 -0700 Subject: [PATCH 310/590] [msvc2017] remove eigen vector workaround for msvc2017. --- extern/Eigen3/Eigen/src/StlSupport/StdVector.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extern/Eigen3/Eigen/src/StlSupport/StdVector.h b/extern/Eigen3/Eigen/src/StlSupport/StdVector.h index 611664a2e8a..1894af6b779 100644 --- a/extern/Eigen3/Eigen/src/StlSupport/StdVector.h +++ b/extern/Eigen3/Eigen/src/StlSupport/StdVector.h @@ -77,7 +77,7 @@ namespace std { void resize(size_type new_size) { resize(new_size, T()); } -#if defined(_VECTOR_) +#if defined(_VECTOR_) && (_MSC_VER<1910) // workaround MSVC std::vector implementation void resize(size_type new_size, const value_type& x) { @@ -110,7 +110,7 @@ namespace std { vector_base::insert(vector_base::end(), new_size - vector_base::size(), x); } #else - // either GCC 4.1 or non-GCC + // either GCC 4.1, MSVC2017 or non-GCC // default implementation which should always work. void resize(size_type new_size, const value_type& x) { From e0307113a5dcc4a1bff2b8e639205c8d2070f52b Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 28 Nov 2016 18:59:31 +0100 Subject: [PATCH 311/590] UI: Add 'x' icon to text buttons to clear content This is useful e.g. for search buttons to quickly clear the filter string. We might want to make this optional for python scripts. --- source/blender/editors/include/UI_interface.h | 2 +- source/blender/editors/interface/interface.c | 41 ++++++--- .../editors/interface/interface_eyedropper.c | 2 +- .../editors/interface/interface_handlers.c | 90 +++++++++++-------- .../editors/interface/interface_intern.h | 2 +- .../editors/interface/interface_layout.c | 2 +- .../editors/interface/interface_regions.c | 6 +- .../editors/interface/interface_utils.c | 1 + .../editors/interface/interface_widgets.c | 10 +-- 9 files changed, 94 insertions(+), 62 deletions(-) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index fd5351394c3..9fbce7dd203 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -181,7 +181,7 @@ enum { UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */ UI_BUT_UPDATE_DELAY = (1 << 28), /* don't run updates while dragging (needed in rare cases). */ UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */ - UI_BUT_SEARCH_UNLINK = (1 << 30), /* show unlink for search button */ + UI_BUT_VALUE_CLEAR = (1 << 30), /* show 'x' icon to clear/unlink value of text or search button */ }; #define UI_PANEL_WIDTH 340 diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 6bba35e821f..a913421d12c 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1987,22 +1987,29 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but) /** \name Check to show extra icons * * Extra icons are shown on the right hand side of buttons. + * This could (should!) definitely become more generic, but for now this is good enough. * \{ */ +static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but) +{ + BLI_assert(but->type == UI_BTYPE_TEXT); + return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr && but->drawstr[0]); +} + static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but) { BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); return ((but->editstr == NULL) && (but->drawstr[0] != '\0') && - (but->flag & UI_BUT_SEARCH_UNLINK)); + (but->flag & UI_BUT_VALUE_CLEAR)); } -static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but) +static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but) { StructRNA *type; short idcode; - BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_SEARCH_UNLINK)); + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_VALUE_CLEAR)); if (but->rnaprop == NULL) { return false; @@ -2011,21 +2018,31 @@ static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but) type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop); idcode = RNA_type_to_ID_code(type); - return ((but->editstr == NULL) && (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode))); } uiButExtraIconType ui_but_icon_extra_get(uiBut *but) { - if ((but->flag & UI_BUT_SEARCH_UNLINK) == 0) { - /* pass */ - } - else if (ui_but_icon_extra_is_visible_search_unlink(but)) { - return UI_BUT_ICONEXTRA_UNLINK; - } - else if (ui_but_icon_extra_is_visible_eyedropper(but)) { - return UI_BUT_ICONEXTRA_EYEDROPPER; + switch (but->type) { + case UI_BTYPE_TEXT: + if (ui_but_icon_extra_is_visible_text_clear(but)) { + return UI_BUT_ICONEXTRA_CLEAR; + } + break; + case UI_BTYPE_SEARCH_MENU: + if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) { + /* pass */ + } + else if (ui_but_icon_extra_is_visible_search_unlink(but)) { + return UI_BUT_ICONEXTRA_CLEAR; + } + else if (ui_but_icon_extra_is_visible_search_eyedropper(but)) { + return UI_BUT_ICONEXTRA_EYEDROPPER; + } + break; + default: + break; } return UI_BUT_ICONEXTRA_NONE; diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index d7f06b7db13..5f7a018e4c2 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -748,7 +748,7 @@ static int datadropper_poll(bContext *C) if ((CTX_wm_window(C) != NULL) && (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && (but->type == UI_BTYPE_SEARCH_MENU) && - (but->flag & UI_BUT_SEARCH_UNLINK)) + (but->flag & UI_BUT_VALUE_CLEAR)) { if (prop && RNA_property_type(prop) == PROP_POINTER) { StructRNA *type = RNA_property_pointer_type(&ptr, prop); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index fc511d61e2b..33f1d5e93cb 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2563,6 +2563,18 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *bu } } +static void ui_but_text_clear(bContext *C, uiBut *but, uiHandleButtonData *data) +{ + /* most likely NULL, but let's check, and give it temp zero string */ + if (!data->str) { + data->str = MEM_callocN(1, "temp str"); + } + data->str[0] = 0; + + ui_apply_but_TEX(C, but, data); + button_activate_state(C, but, BUTTON_STATE_EXIT); +} + /* ************* in-button text selection/editing ************* */ @@ -3842,6 +3854,21 @@ static int ui_do_but_KEYEVT( return WM_UI_HANDLER_CONTINUE; } +static bool ui_but_is_mouse_over_icon_extra(const ARegion *region, uiBut *but, const int mouse_xy[2]) +{ + int x = mouse_xy[0], y = mouse_xy[1]; + rcti icon_rect; + + BLI_assert(ui_but_icon_extra_get(but) != UI_BUT_ICONEXTRA_NONE); + + ui_window_to_block(region, but->block, &x, &y); + + BLI_rcti_rctf_copy(&icon_rect, &but->rect); + icon_rect.xmin = icon_rect.xmax - (BLI_rcti_size_y(&icon_rect)); + + return BLI_rcti_isect_pt(&icon_rect, x, y); +} + static int ui_do_but_TEX( bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) @@ -3855,7 +3882,14 @@ static int ui_do_but_TEX( /* pass */ } else { - button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); + const bool has_icon_extra = ui_but_icon_extra_get(but) == UI_BUT_ICONEXTRA_CLEAR; + + if (has_icon_extra && ui_but_is_mouse_over_icon_extra(data->region, but, &event->x)) { + ui_but_text_clear(C, but, data); + } + else { + button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); + } return WM_UI_HANDLER_BREAK; } } @@ -3876,47 +3910,29 @@ static int ui_do_but_SEARCH_UNLINK( bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { - uiButExtraIconType extra_icon_type; + const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but); + const bool has_icon_extra = (extra_icon_type != UI_BUT_ICONEXTRA_NONE); /* unlink icon is on right */ if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) && - ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE)) + (has_icon_extra == true) && + (ui_but_is_mouse_over_icon_extra(data->region, but, &event->x) == true)) { - ARegion *ar = data->region; - rcti rect; - int x = event->x, y = event->y; - - ui_window_to_block(ar, but->block, &x, &y); - - BLI_rcti_rctf_copy(&rect, &but->rect); - - rect.xmin = rect.xmax - (BLI_rcti_size_y(&rect)); - /* handle click on unlink/eyedropper icon */ - if (BLI_rcti_isect_pt(&rect, x, y)) { - /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */ - if (event->val == KM_RELEASE) { - /* unlink */ - if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) { - /* most likely NULL, but let's check, and give it temp zero string */ - if (data->str == NULL) { - data->str = MEM_callocN(1, "temp str"); - } - data->str[0] = 0; - - ui_apply_but_TEX(C, but, data); - button_activate_state(C, but, BUTTON_STATE_EXIT); - } - /* eyedropper */ - else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) { - WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL); - } - else { - BLI_assert(0); - } + /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */ + if (event->val == KM_RELEASE) { + /* unlink */ + if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) { + ui_but_text_clear(C, but, data); + } + /* eyedropper */ + else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) { + WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL); + } + else { + BLI_assert(0); } - - return WM_UI_HANDLER_BREAK; } + return WM_UI_HANDLER_BREAK; } return ui_do_but_TEX(C, block, but, data, event); } @@ -7091,7 +7107,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case UI_BTYPE_TEXT: case UI_BTYPE_SEARCH_MENU: if ((but->type == UI_BTYPE_SEARCH_MENU) && - (but->flag & UI_BUT_SEARCH_UNLINK)) + (but->flag & UI_BUT_VALUE_CLEAR)) { retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event); if (retval & WM_UI_HANDLER_BREAK) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index fcf827bdbe6..d8f9fdcbaae 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -127,7 +127,7 @@ enum { * (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */ typedef enum uiButExtraIconType { UI_BUT_ICONEXTRA_NONE = 1, - UI_BUT_ICONEXTRA_UNLINK, + UI_BUT_ICONEXTRA_CLEAR, UI_BUT_ICONEXTRA_EYEDROPPER, } uiButExtraIconType; diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 875522e01c6..b128bf47b5f 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1659,7 +1659,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN but->rnasearchprop = searchprop; but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT; if (RNA_property_is_unlink(prop)) { - but->flag |= UI_BUT_SEARCH_UNLINK; + but->flag |= UI_BUT_VALUE_CLEAR; } if (RNA_property_type(prop) == PROP_ENUM) { diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index cdf34642a8d..466978272bc 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -851,7 +851,7 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step) } else { /* only let users step into an 'unset' state for unlink buttons */ - data->active = (but->flag & UI_BUT_SEARCH_UNLINK) ? -1 : 0; + data->active = (but->flag & UI_BUT_VALUE_CLEAR) ? -1 : 0; } } @@ -922,8 +922,8 @@ bool ui_searchbox_apply(uiBut *but, ARegion *ar) return true; } - else if (but->flag & UI_BUT_SEARCH_UNLINK) { - /* It is valid for _UNLINK flavor to have no active element (it's a valid way to unlink). */ + else if (but->flag & UI_BUT_VALUE_CLEAR) { + /* It is valid for _VALUE_CLEAR flavor to have no active element (it's a valid way to unlink). */ but->editstr[0] = '\0'; return true; diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 1d51c0588b6..f4df3d4ec2e 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -119,6 +119,7 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind else but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL); + UI_but_flag_enable(but, UI_BUT_VALUE_CLEAR); /* might want to make this optional? */ if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) { UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE); } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index c285d753b96..d43a94c5514 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1508,10 +1508,10 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b /* draws text and icons for buttons */ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect) { + const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but); const bool show_menu_icon = ui_but_draw_menu_icon(but); float alpha = (float)wcol->text[3] / 255.0f; char password_str[UI_MAX_DRAW_STR]; - uiButExtraIconType extra_icon_type; ui_but_text_password_hide(password_str, but, false); @@ -1577,15 +1577,13 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect; } - /* unlink icon for this button type */ - if ((but->type == UI_BTYPE_SEARCH_MENU) && - ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE)) - { + /* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */ + if (extra_icon_type != UI_BUT_ICONEXTRA_NONE) { rcti temp = *rect; temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f); - if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) { + if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) { widget_draw_icon(but, ICON_X, alpha, &temp, false); } else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) { From 6278adc3cab7911d11b64f3ae795dc527041343d Mon Sep 17 00:00:00 2001 From: lazydodo Date: Mon, 28 Nov 2016 13:22:10 -0700 Subject: [PATCH 312/590] [msvc] change linker options from /opt:noref to /opt:ref, saves about 20% off the executable size Nobody appears to know why this option was on (and just on for just x64 at that) --- build_files/cmake/platform/platform_win32_msvc.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_files/cmake/platform/platform_win32_msvc.cmake b/build_files/cmake/platform/platform_win32_msvc.cmake index 6ca0568b5fd..d630ae78424 100644 --- a/build_files/cmake/platform/platform_win32_msvc.cmake +++ b/build_files/cmake/platform/platform_win32_msvc.cmake @@ -112,7 +112,7 @@ set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") # MSVC only, Mingw doesnt need if(CMAKE_CL_64) - set(PLATFORM_LINKFLAGS "/MACHINE:X64 /OPT:NOREF ${PLATFORM_LINKFLAGS}") + set(PLATFORM_LINKFLAGS "/MACHINE:X64 /OPT:REF ${PLATFORM_LINKFLAGS}") else() set(PLATFORM_LINKFLAGS "/MACHINE:IX86 /LARGEADDRESSAWARE ${PLATFORM_LINKFLAGS}") endif() From dd34b7a71c2e8cfc490070c68bf293fb6e1734f4 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 29 Nov 2016 13:12:26 +1100 Subject: [PATCH 313/590] Comment: explain viewport & render pixel-size It wasn't all that clear why both pixel-sizes are needed. --- source/blender/blenkernel/intern/camera.c | 2 ++ .../blender/editors/space_view3d/view3d_draw.c | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 30f17582bf5..9cb553aa27b 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -337,6 +337,8 @@ void BKE_camera_params_compute_viewplane(CameraParams *params, int winx, int win viewplane.ymin *= pixsize; viewplane.ymax *= pixsize; + /* Used for rendering (offset by near-clip with perspective views), passed to RE_SetPixelSize. + * For viewport drawing 'RegionView3D.pixsize'. */ params->viewdx = pixsize; params->viewdy = params->ycor * pixsize; params->viewplane = viewplane; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 000d1fe4810..f23e587e55d 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -2658,7 +2658,6 @@ CustomDataMask ED_view3d_screen_datamask(const bScreen *screen) void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) { RegionView3D *rv3d = ar->regiondata; - rctf cameraborder; /* setup window matrices */ if (winmat) @@ -2672,7 +2671,7 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view else view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - /* update utilitity matrices */ + /* update utility matrices */ mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); invert_m4_m4(rv3d->persinv, rv3d->persmat); invert_m4_m4(rv3d->viewinv, rv3d->viewmat); @@ -2681,6 +2680,7 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view /* store window coordinates scaling/offset */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + rctf cameraborder; ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false); rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); @@ -2692,8 +2692,17 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f; rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f; } - - /* calculate pixelsize factor once, is used for lamps and obcenters */ + + /** + * Calculate pixel-size factor once, is used for lamps and object centers. + * Used by #ED_view3d_pixel_size and typically not accessed directly. + * + * \note #BKE_camera_params_compute_viewplane' also calculates a pixel-size value, + * passed to #RE_SetPixelSize, in ortho mode this is compatible with this value, + * but in perspective mode its offset by the near-clip. + * + * 'RegionView3D.pixsize' is used for viewport drawing, not rendering. + */ { /* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])' * because of float point precision problems at large values [#23908] */ From 9bea39c474f768ce6559dfe0315157db6e16f44c Mon Sep 17 00:00:00 2001 From: lazydodo Date: Mon, 28 Nov 2016 19:55:07 -0700 Subject: [PATCH 314/590] [msvc] remove /opt all together and revert to the default behavior /opt:ref for release builds, /opt:noref for debug builds. --- build_files/cmake/platform/platform_win32_msvc.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_files/cmake/platform/platform_win32_msvc.cmake b/build_files/cmake/platform/platform_win32_msvc.cmake index d630ae78424..96c9ec91d11 100644 --- a/build_files/cmake/platform/platform_win32_msvc.cmake +++ b/build_files/cmake/platform/platform_win32_msvc.cmake @@ -112,7 +112,7 @@ set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /ignore:4221") # MSVC only, Mingw doesnt need if(CMAKE_CL_64) - set(PLATFORM_LINKFLAGS "/MACHINE:X64 /OPT:REF ${PLATFORM_LINKFLAGS}") + set(PLATFORM_LINKFLAGS "/MACHINE:X64 ${PLATFORM_LINKFLAGS}") else() set(PLATFORM_LINKFLAGS "/MACHINE:IX86 /LARGEADDRESSAWARE ${PLATFORM_LINKFLAGS}") endif() From 3b467b35a85153e9435a1fbcba2e9c1770c1192a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 29 Nov 2016 19:31:46 +1100 Subject: [PATCH 315/590] Fix T50029: BVHTree.FromPolygons memory leak --- source/blender/python/mathutils/mathutils_bvhtree.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/python/mathutils/mathutils_bvhtree.c b/source/blender/python/mathutils/mathutils_bvhtree.c index ff1761eb6d7..1eb8644a9a6 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.c +++ b/source/blender/python/mathutils/mathutils_bvhtree.c @@ -817,13 +817,14 @@ static PyObject *C_BVHTree_FromPolygons(PyObject *UNUSED(cls), PyObject *args, P PyErr_Format(PyExc_ValueError, "%s: index %d must be less than %d", error_prefix, plink->poly[j], coords_len); - - Py_DECREF(py_tricoords_fast); + /* decref below */ valid = false; break; } } + Py_DECREF(py_tricoords_fast); + if (py_tricoords_len >= 3) { tris_len += (py_tricoords_len - 2); } From cc1a64be36f3dc862ad83ee3f4730a2b4c5649fd Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 29 Nov 2016 10:31:54 +0100 Subject: [PATCH 316/590] Math lib: Fix use function of wrong dimension Seems to be a typo in recent commit e1e49fd. --- source/blender/blenlib/intern/math_geom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 0790d65345d..38947e139ff 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -3919,7 +3919,7 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py unit_m4(mat1); - axis_angle_to_mat3_single(mat, 'Z', -twist); + axis_angle_to_mat4_single(mat, 'Z', -twist); dx = px - vx; dy = py - vy; From 7ea2dedd59cbe009313a96421d70dc38f04f2096 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 29 Nov 2016 11:03:11 +0100 Subject: [PATCH 317/590] Cycles: Pass extra array size argument to builtin image pixels functions This is a way to avoid possible memory corruption when render threads works in parallel with UI thread. Not guarantees complete safe, but makes things easier to check anyway. --- intern/cycles/blender/blender_session.cpp | 86 ++++++++++++++--------- intern/cycles/blender/blender_session.h | 18 ++++- intern/cycles/render/image.cpp | 8 ++- intern/cycles/render/image.h | 22 +++++- 4 files changed, 90 insertions(+), 44 deletions(-) diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 171153dd440..e16cea0ebaf 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -126,8 +126,8 @@ void BlenderSession::create_session() /* setup callbacks for builtin image support */ scene->image_manager->builtin_image_info_cb = function_bind(&BlenderSession::builtin_image_info, this, _1, _2, _3, _4, _5, _6, _7); - scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3); - scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3); + scene->image_manager->builtin_image_pixels_cb = function_bind(&BlenderSession::builtin_image_pixels, this, _1, _2, _3, _4); + scene->image_manager->builtin_image_float_pixels_cb = function_bind(&BlenderSession::builtin_image_float_pixels, this, _1, _2, _3, _4); /* create session */ session = new Session(session_params); @@ -1080,7 +1080,13 @@ int BlenderSession::builtin_image_frame(const string &builtin_name) return atoi(builtin_name.substr(last + 1, builtin_name.size() - last - 1).c_str()); } -void BlenderSession::builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels) +void BlenderSession::builtin_image_info(const string &builtin_name, + void *builtin_data, + bool &is_float, + int &width, + int &height, + int &depth, + int &channels) { /* empty image */ is_float = false; @@ -1158,60 +1164,67 @@ void BlenderSession::builtin_image_info(const string &builtin_name, void *builti } } -bool BlenderSession::builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels) +bool BlenderSession::builtin_image_pixels(const string &builtin_name, + void *builtin_data, + unsigned char *pixels, + const size_t pixels_size) { - if(!builtin_data) + if(!builtin_data) { return false; + } - int frame = builtin_image_frame(builtin_name); + const int frame = builtin_image_frame(builtin_name); PointerRNA ptr; RNA_id_pointer_create((ID*)builtin_data, &ptr); BL::Image b_image(ptr); - int width = b_image.size()[0]; - int height = b_image.size()[1]; - int channels = b_image.channels(); + const int width = b_image.size()[0]; + const int height = b_image.size()[1]; + const int channels = b_image.channels(); - unsigned char *image_pixels; - image_pixels = image_get_pixels_for_frame(b_image, frame); - size_t num_pixels = ((size_t)width) * height; + unsigned char *image_pixels = image_get_pixels_for_frame(b_image, frame); + const size_t num_pixels = ((size_t)width) * height; - if(image_pixels) { - memcpy(pixels, image_pixels, num_pixels * channels * sizeof(unsigned char)); + if(image_pixels && num_pixels * channels == pixels_size) { + memcpy(pixels, image_pixels, pixels_size * sizeof(unsigned char)); MEM_freeN(image_pixels); } else { if(channels == 1) { - memset(pixels, 0, num_pixels * sizeof(unsigned char)); + memset(pixels, 0, pixels_size * sizeof(unsigned char)); } else { + const size_t num_pixels_safe = pixels_size / channels; unsigned char *cp = pixels; - for(size_t i = 0; i < num_pixels; i++, cp += channels) { + for(size_t i = 0; i < num_pixels_safe; i++, cp += channels) { cp[0] = 255; cp[1] = 0; cp[2] = 255; - if(channels == 4) + if(channels == 4) { cp[3] = 255; + } } } } - - /* premultiply, byte images are always straight for blender */ + /* Premultiply, byte images are always straight for Blender. */ unsigned char *cp = pixels; for(size_t i = 0; i < num_pixels; i++, cp += channels) { cp[0] = (cp[0] * cp[3]) >> 8; cp[1] = (cp[1] * cp[3]) >> 8; cp[2] = (cp[2] * cp[3]) >> 8; } - return true; } -bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels) +bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, + void *builtin_data, + float *pixels, + const size_t pixels_size) { - if(!builtin_data) + if(!builtin_data) { return false; + } PointerRNA ptr; RNA_id_pointer_create((ID*)builtin_data, &ptr); @@ -1222,16 +1235,16 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void BL::Image b_image(b_id); int frame = builtin_image_frame(builtin_name); - int width = b_image.size()[0]; - int height = b_image.size()[1]; - int channels = b_image.channels(); + const int width = b_image.size()[0]; + const int height = b_image.size()[1]; + const int channels = b_image.channels(); float *image_pixels; image_pixels = image_get_float_pixels_for_frame(b_image, frame); - size_t num_pixels = ((size_t)width) * height; + const size_t num_pixels = ((size_t)width) * height; - if(image_pixels) { - memcpy(pixels, image_pixels, num_pixels * channels * sizeof(float)); + if(image_pixels && num_pixels * channels == pixels_size) { + memcpy(pixels, image_pixels, pixels_size * sizeof(float)); MEM_freeN(image_pixels); } else { @@ -1239,13 +1252,15 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void memset(pixels, 0, num_pixels * sizeof(float)); } else { + const size_t num_pixels_safe = pixels_size / channels; float *fp = pixels; - for(int i = 0; i < num_pixels; i++, fp += channels) { + for(int i = 0; i < num_pixels_safe; i++, fp += channels) { fp[0] = 1.0f; fp[1] = 0.0f; fp[2] = 1.0f; - if(channels == 4) + if(channels == 4) { fp[3] = 1.0f; + } } } } @@ -1257,8 +1272,9 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void BL::Object b_ob(b_id); BL::SmokeDomainSettings b_domain = object_smoke_domain_find(b_ob); - if(!b_domain) + if(!b_domain) { return false; + } int3 resolution = get_int3(b_domain.domain_resolution()); int length, amplify = (b_domain.use_high_resolution())? b_domain.amplify() + 1: 1; @@ -1270,10 +1286,10 @@ bool BlenderSession::builtin_image_float_pixels(const string &builtin_name, void amplify = 1; } - int width = resolution.x * amplify; - int height = resolution.y * amplify; - int depth = resolution.z * amplify; - size_t num_pixels = ((size_t)width) * height * depth; + const int width = resolution.x * amplify; + const int height = resolution.y * amplify; + const int depth = resolution.z * amplify; + const size_t num_pixels = ((size_t)width) * height * depth; if(builtin_name == Attribute::standard_name(ATTR_STD_VOLUME_DENSITY)) { SmokeDomainSettings_density_grid_get_length(&b_domain.ptr, &length); diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index 66a6945cbc1..82fe218b4ce 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -145,9 +145,21 @@ protected: void do_write_update_render_tile(RenderTile& rtile, bool do_update_only); int builtin_image_frame(const string &builtin_name); - void builtin_image_info(const string &builtin_name, void *builtin_data, bool &is_float, int &width, int &height, int &depth, int &channels); - bool builtin_image_pixels(const string &builtin_name, void *builtin_data, unsigned char *pixels); - bool builtin_image_float_pixels(const string &builtin_name, void *builtin_data, float *pixels); + void builtin_image_info(const string &builtin_name, + void *builtin_data, + bool &is_float, + int &width, + int &height, + int &depth, + int &channels); + bool builtin_image_pixels(const string &builtin_name, + void *builtin_data, + unsigned char *pixels, + const size_t pixels_size); + bool builtin_image_float_pixels(const string &builtin_name, + void *builtin_data, + float *pixels, + const size_t pixels_size); /* Update tile manager to reflect resumable render settings. */ void update_resumable_tile_manager(int num_samples); diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 11193bf4974..ab830b19c57 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -498,6 +498,7 @@ bool ImageManager::file_load_image(Image *img, pixels = (StorageType*)tex_img.resize(width, height, depth); } bool cmyk = false; + const size_t num_pixels = ((size_t)width) * height * depth; if(in) { StorageType *readpixels = pixels; vector tmppixels; @@ -534,12 +535,14 @@ bool ImageManager::file_load_image(Image *img, if(FileFormat == TypeDesc::FLOAT) { builtin_image_float_pixels_cb(img->filename, img->builtin_data, - (float*)&pixels[0]); + (float*)&pixels[0], + num_pixels * components); } else if(FileFormat == TypeDesc::UINT8) { builtin_image_pixels_cb(img->filename, img->builtin_data, - (uchar*)&pixels[0]); + (uchar*)&pixels[0], + num_pixels * components); } else { /* TODO(dingto): Support half for ImBuf. */ @@ -552,7 +555,6 @@ bool ImageManager::file_load_image(Image *img, type == IMAGE_DATA_TYPE_HALF4 || type == IMAGE_DATA_TYPE_BYTE4); if(is_rgba) { - size_t num_pixels = ((size_t)width) * height * depth; if(cmyk) { /* CMYK */ for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 3da7338985c..47bbd92347c 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -86,9 +86,25 @@ public: bool need_update; - function builtin_image_info_cb; - function builtin_image_pixels_cb; - function builtin_image_float_pixels_cb; + /* NOTE: Here pixels_size is a size of storage, which equals to + * width * height * depth. + * Use this to avoid some nasty memory corruptions. + */ + function builtin_image_info_cb; + function builtin_image_pixels_cb; + function builtin_image_float_pixels_cb; struct Image { string filename; From 1ec5edcc9669f46b1f0fd29c765a326ea525e7f3 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 29 Nov 2016 11:39:14 +0100 Subject: [PATCH 318/590] Fix T50094: Crash when viewport rendering point density texture The idea is simple: cache PD resolution from cache_point_density() RNA function because that one is supposed to be called while database is locked for original synchronization. Ideally we would also pass array size to the sampling function, but it turned out to be quite problematic because API only accepts int type and passing size_t might cause some weird behavior. --- source/blender/makesdna/DNA_node_types.h | 3 +++ source/blender/makesrna/intern/rna_nodetree.c | 12 ++++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 46b30f41f5b..3a7e2b6f7f8 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -811,7 +811,10 @@ typedef struct NodeShaderTexPointDensity { short color_source; short ob_color_source; char vertex_attribute_name[64]; /* vertex attribute layer for color source, MAX_CUSTOMDATA_LAYER_NAME */ + /* Used at runtime only by sampling RNA API. */ PointDensity pd; + int cached_resolution; + int pad2; } NodeShaderTexPointDensity; /* TEX_output */ diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 47e9d989dbf..34002f8d550 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3107,6 +3107,9 @@ void rna_ShaderNodePointDensity_density_cache(bNode *self, sizeof(pd->vertex_attribute_name)); } + /* Store resolution, so it can be changed in the UI. */ + shader_point_density->cached_resolution = shader_point_density->resolution; + /* Single-threaded sampling of the voxel domain. */ RE_point_density_cache(scene, pd, @@ -3121,15 +3124,15 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self, { NodeShaderTexPointDensity *shader_point_density = self->storage; PointDensity *pd = &shader_point_density->pd; + const int resolution = shader_point_density->cached_resolution; if (scene == NULL) { *length = 0; return; } - *length = 4 * shader_point_density->resolution * - shader_point_density->resolution * - shader_point_density->resolution; + /* TODO(sergey): Will likely overflow, but how to pass size_t via RNA? */ + *length = 4 * resolution * resolution * resolution; if (*values == NULL) { *values = MEM_mallocN(sizeof(float) * (*length), "point density dynamic array"); @@ -3137,13 +3140,14 @@ void rna_ShaderNodePointDensity_density_calc(bNode *self, /* Single-threaded sampling of the voxel domain. */ RE_point_density_sample(scene, pd, - shader_point_density->resolution, + resolution, settings == 1, *values); /* We're done, time to clean up. */ BKE_texture_pointdensity_free_data(pd); memset(pd, 0, sizeof(*pd)); + shader_point_density->cached_resolution = 0.0f; } void rna_ShaderNodePointDensity_density_minmax(bNode *self, From bd5ae46c1968526058a98bfc99abbcbb3d7de69b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 29 Nov 2016 12:40:38 +0100 Subject: [PATCH 319/590] Fix compilation error with latest OIIO 1.7.8 There are some changes in OIIO includes so now need to do some things differently. --- source/blender/imbuf/intern/oiio/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/imbuf/intern/oiio/CMakeLists.txt b/source/blender/imbuf/intern/oiio/CMakeLists.txt index c873fa3f32d..a4fb9c5aee1 100644 --- a/source/blender/imbuf/intern/oiio/CMakeLists.txt +++ b/source/blender/imbuf/intern/oiio/CMakeLists.txt @@ -49,6 +49,11 @@ if(WITH_OPENIMAGEIO) ${OPENIMAGEIO_INCLUDE_DIRS} ${BOOST_INCLUDE_DIR} ) + if(WITH_IMAGE_OPENEXR) + list(APPEND INC_SYS + ${OPENEXR_INCLUDE_DIRS} + ) + endif() add_definitions(-DWITH_OPENIMAGEIO) endif() From 514db9f014110da442f13c5a84f9e895dabbf305 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 29 Nov 2016 23:41:20 +0100 Subject: [PATCH 320/590] UI: Remove 'x' icon from paths and lists --- source/blender/editors/interface/interface_utils.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index f4df3d4ec2e..8dfbbdd02eb 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -119,7 +119,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind else but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL); - UI_but_flag_enable(but, UI_BUT_VALUE_CLEAR); /* might want to make this optional? */ + PropertySubType subtype = RNA_property_subtype(prop); + if (!(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME) || (block->flag & UI_BLOCK_LIST_ITEM))) { + UI_but_flag_enable(but, UI_BUT_VALUE_CLEAR); + } if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) { UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE); } From 66a367190447773f87cb31854a39f67b91d519f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Wed, 30 Nov 2016 09:20:45 +0100 Subject: [PATCH 321/590] Fix T49813: crash after changing Alembic cache topology. Crash is due by mismatching loops and faces counts between the Alembic data and the Blender derivedmesh which does not appear so straightforward to fix (the crash happens deep in the derivedmesh code). So for now, try to detect if the topology has changed and if so, both only read vertices (vertex colors and UVs won't be read, as tied to face loops) and add a warning message in the modifier's UI to let the user know. --- source/blender/alembic/intern/abc_curves.cc | 2 +- source/blender/alembic/intern/abc_curves.h | 2 +- source/blender/alembic/intern/abc_mesh.cc | 38 +++++++++++++++++-- source/blender/alembic/intern/abc_mesh.h | 4 +- source/blender/alembic/intern/abc_object.h | 3 +- source/blender/alembic/intern/abc_points.cc | 4 +- source/blender/alembic/intern/abc_points.h | 2 +- source/blender/alembic/intern/alembic_capi.cc | 8 ++-- 8 files changed, 47 insertions(+), 16 deletions(-) diff --git a/source/blender/alembic/intern/abc_curves.cc b/source/blender/alembic/intern/abc_curves.cc index 7e5ea3b1853..4ecb9d944f2 100644 --- a/source/blender/alembic/intern/abc_curves.cc +++ b/source/blender/alembic/intern/abc_curves.cc @@ -361,7 +361,7 @@ void read_curve_sample(Curve *cu, const ICurvesSchema &schema, const float time) * object directly and create a new DerivedMesh from that. Also we might need to * create new or delete existing NURBS in the curve. */ -DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/) +DerivedMesh *AbcCurveReader::read_derivedmesh(DerivedMesh */*dm*/, const float time, int /*read_flag*/, const char **/*err_str*/) { ISampleSelector sample_sel(time); const ICurvesSchema::Sample sample = m_curves_schema.getValue(sample_sel); diff --git a/source/blender/alembic/intern/abc_curves.h b/source/blender/alembic/intern/abc_curves.h index 979ee8af639..2757d179a47 100644 --- a/source/blender/alembic/intern/abc_curves.h +++ b/source/blender/alembic/intern/abc_curves.h @@ -56,7 +56,7 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); - DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int); + DerivedMesh *read_derivedmesh(DerivedMesh *, const float time, int read_flag, const char **err_str); }; /* ************************************************************************** */ diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index 5b282e3c5bb..395c3e666f7 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -896,7 +896,7 @@ void AbcMeshReader::readObjectData(Main *bmain, float time) const ISampleSelector sample_sel(time); DerivedMesh *dm = CDDM_from_mesh(mesh); - DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL, NULL); if (ndm != dm) { dm->release(dm); @@ -978,7 +978,7 @@ CDStreamConfig get_config(DerivedMesh *dm) return config; } -DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) +DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str) { ISampleSelector sample_sel(time); const IPolyMeshSchema::Sample sample = m_schema.getValue(sample_sel); @@ -1003,6 +1003,21 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, settings.read_flag |= MOD_MESHSEQ_READ_ALL; } + else { + /* If the face count changed (e.g. by triangulation), only read points. + * This prevents crash from T49813 + * TODO(kevin): perhaps find a better way to do this? */ + if (face_counts->size() != dm->getNumPolys(dm) || + face_indices->size() != dm->getNumLoops(dm)) + { + settings.read_flag = MOD_MESHSEQ_READ_VERT; + + if (err_str) { + *err_str = "Topology has changed, perhaps by triangulating the" + " mesh. Only vertices will be read!"; + } + } + } CDStreamConfig config = get_config(new_dm ? new_dm : dm); config.time = time; @@ -1177,7 +1192,7 @@ void AbcSubDReader::readObjectData(Main *bmain, float time) m_object->data = mesh; DerivedMesh *dm = CDDM_from_mesh(mesh); - DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL, NULL); if (ndm != dm) { dm->release(dm); @@ -1257,7 +1272,7 @@ void read_subd_sample(ImportSettings *settings, /* TODO: face sets */ } -DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) +DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str) { ISampleSelector sample_sel(time); const ISubDSchema::Sample sample = m_schema.getValue(sample_sel); @@ -1281,6 +1296,21 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, settings.read_flag |= MOD_MESHSEQ_READ_ALL; } + else { + /* If the face count changed (e.g. by triangulation), only read points. + * This prevents crash from T49813 + * TODO(kevin): perhaps find a better way to do this? */ + if (face_counts->size() != dm->getNumPolys(dm) || + face_indices->size() != dm->getNumLoops(dm)) + { + settings.read_flag = MOD_MESHSEQ_READ_VERT; + + if (err_str) { + *err_str = "Topology has changed, perhaps by triangulating the" + " mesh. Only vertices will be read!"; + } + } + } /* Only read point data when streaming meshes, unless we need to create new ones. */ CDStreamConfig config = get_config(new_dm ? new_dm : dm); diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h index 66e6585a3d3..28d17105480 100644 --- a/source/blender/alembic/intern/abc_mesh.h +++ b/source/blender/alembic/intern/abc_mesh.h @@ -102,7 +102,7 @@ public: void readObjectData(Main *bmain, float time); - DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str); private: void readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_start, @@ -128,7 +128,7 @@ public: bool valid() const; void readObjectData(Main *bmain, float time); - DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str); }; void read_subd_sample(ImportSettings *settings, diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h index 7ff927b4d33..d1bcbbe6cbe 100644 --- a/source/blender/alembic/intern/abc_object.h +++ b/source/blender/alembic/intern/abc_object.h @@ -165,10 +165,11 @@ public: virtual void readObjectData(Main *bmain, float time) = 0; - virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag) + virtual DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str) { (void)time; (void)read_flag; + (void)err_str; return dm; } diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc index c16da621c77..6ddba350b0a 100644 --- a/source/blender/alembic/intern/abc_points.cc +++ b/source/blender/alembic/intern/abc_points.cc @@ -156,7 +156,7 @@ void AbcPointsReader::readObjectData(Main *bmain, float time) Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); DerivedMesh *dm = CDDM_from_mesh(mesh); - DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, 0, NULL); if (ndm != dm) { dm->release(dm); @@ -199,7 +199,7 @@ void read_points_sample(const IPointsSchema &schema, read_mverts(config.mvert, positions, vnormals); } -DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/) +DerivedMesh *AbcPointsReader::read_derivedmesh(DerivedMesh *dm, const float time, int /*read_flag*/, const char **/*err_str*/) { ISampleSelector sample_sel(time); const IPointsSchema::Sample sample = m_schema.getValue(sample_sel); diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h index 54873eed346..792283f04d3 100644 --- a/source/blender/alembic/intern/abc_points.h +++ b/source/blender/alembic/intern/abc_points.h @@ -61,7 +61,7 @@ public: void readObjectData(Main *bmain, float time); - DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag); + DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str); }; void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema, diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index e690a255505..d0eb9900f4f 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -816,7 +816,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader, return NULL; } - return abc_reader->read_derivedmesh(dm, time, read_flag); + return abc_reader->read_derivedmesh(dm, time, read_flag, err_str); } else if (ISubD::matches(header)) { if (ob->type != OB_MESH) { @@ -824,7 +824,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader, return NULL; } - return abc_reader->read_derivedmesh(dm, time, read_flag); + return abc_reader->read_derivedmesh(dm, time, read_flag, err_str); } else if (IPoints::matches(header)) { if (ob->type != OB_MESH) { @@ -832,7 +832,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader, return NULL; } - return abc_reader->read_derivedmesh(dm, time, read_flag); + return abc_reader->read_derivedmesh(dm, time, read_flag, err_str); } else if (ICurves::matches(header)) { if (ob->type != OB_CURVE) { @@ -840,7 +840,7 @@ DerivedMesh *ABC_read_mesh(CacheReader *reader, return NULL; } - return abc_reader->read_derivedmesh(dm, time, read_flag); + return abc_reader->read_derivedmesh(dm, time, read_flag, err_str); } *err_str = "Unsupported object type: verify object path"; // or poke developer From 2ac8c9b42ec3ea44c4abfb835f732c3c72f1dc4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Wed, 30 Nov 2016 09:33:47 +0100 Subject: [PATCH 322/590] Alembic: slight cleanup, reorder mesh code a bit. --- source/blender/alembic/intern/abc_mesh.cc | 252 +++++++++++----------- source/blender/alembic/intern/abc_mesh.h | 11 - 2 files changed, 127 insertions(+), 136 deletions(-) diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index 395c3e666f7..4fe1f2b51d0 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -868,53 +868,6 @@ ABC_INLINE void read_normals_params(AbcMeshData &abc_data, } } -/* ************************************************************************** */ - -AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings) - : AbcObjectReader(object, settings) -{ - m_settings->read_flag |= MOD_MESHSEQ_READ_ALL; - - IPolyMesh ipoly_mesh(m_iobject, kWrapExisting); - m_schema = ipoly_mesh.getSchema(); - - get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); -} - -bool AbcMeshReader::valid() const -{ - return m_schema.valid(); -} - -void AbcMeshReader::readObjectData(Main *bmain, float time) -{ - Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); - - m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); - m_object->data = mesh; - - const ISampleSelector sample_sel(time); - - DerivedMesh *dm = CDDM_from_mesh(mesh); - DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL, NULL); - - if (ndm != dm) { - dm->release(dm); - } - - DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); - - if (m_settings->validate_meshes) { - BKE_mesh_validate(mesh, false, false); - } - - readFaceSetsSample(bmain, mesh, 0, sample_sel); - - if (has_animations(m_schema, m_settings)) { - addCacheModifier(); - } -} - static bool check_smooth_poly_flag(DerivedMesh *dm) { MPoly *mpolys = dm->getPolyArray(dm); @@ -962,6 +915,66 @@ static void *add_customdata_cb(void *user_data, const char *name, int data_type) return cd_ptr; } +static void get_weight_and_index(CDStreamConfig &config, + Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling, + size_t samples_number) +{ + Alembic::AbcGeom::index_t i0, i1; + + config.weight = get_weight_and_index(config.time, + time_sampling, + samples_number, + i0, + i1); + + config.index = i0; + config.ceil_index = i1; +} + +static void read_mesh_sample(ImportSettings *settings, + const IPolyMeshSchema &schema, + const ISampleSelector &selector, + CDStreamConfig &config, + bool &do_normals) +{ + const IPolyMeshSchema::Sample sample = schema.getValue(selector); + + AbcMeshData abc_mesh_data; + abc_mesh_data.face_counts = sample.getFaceCounts(); + abc_mesh_data.face_indices = sample.getFaceIndices(); + abc_mesh_data.positions = sample.getPositions(); + + read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector); + + do_normals = (abc_mesh_data.face_normals != NULL); + + get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); + + if (config.weight != 0.0f) { + Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample; + schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast(config.ceil_index))); + abc_mesh_data.ceil_positions = ceil_sample.getPositions(); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { + read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { + read_mverts(config, abc_mesh_data); + } + + if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { + read_mpolys(config, abc_mesh_data); + } + + if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { + read_custom_data(schema.getArbGeomParams(), config, selector); + } + + /* TODO: face sets */ +} + CDStreamConfig get_config(DerivedMesh *dm) { CDStreamConfig config; @@ -978,6 +991,53 @@ CDStreamConfig get_config(DerivedMesh *dm) return config; } +/* ************************************************************************** */ + +AbcMeshReader::AbcMeshReader(const IObject &object, ImportSettings &settings) + : AbcObjectReader(object, settings) +{ + m_settings->read_flag |= MOD_MESHSEQ_READ_ALL; + + IPolyMesh ipoly_mesh(m_iobject, kWrapExisting); + m_schema = ipoly_mesh.getSchema(); + + get_min_max_time(m_iobject, m_schema, m_min_time, m_max_time); +} + +bool AbcMeshReader::valid() const +{ + return m_schema.valid(); +} + +void AbcMeshReader::readObjectData(Main *bmain, float time) +{ + Mesh *mesh = BKE_mesh_add(bmain, m_data_name.c_str()); + + m_object = BKE_object_add_only_object(bmain, OB_MESH, m_object_name.c_str()); + m_object->data = mesh; + + const ISampleSelector sample_sel(time); + + DerivedMesh *dm = CDDM_from_mesh(mesh); + DerivedMesh *ndm = this->read_derivedmesh(dm, time, MOD_MESHSEQ_READ_ALL, NULL); + + if (ndm != dm) { + dm->release(dm); + } + + DM_to_mesh(ndm, mesh, m_object, CD_MASK_MESH, true); + + if (m_settings->validate_meshes) { + BKE_mesh_validate(mesh, false, false); + } + + readFaceSetsSample(bmain, mesh, 0, sample_sel); + + if (has_animations(m_schema, m_settings)) { + addCacheModifier(); + } +} + DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str) { ISampleSelector sample_sel(time); @@ -1005,7 +1065,7 @@ DerivedMesh *AbcMeshReader::read_derivedmesh(DerivedMesh *dm, const float time, } else { /* If the face count changed (e.g. by triangulation), only read points. - * This prevents crash from T49813 + * This prevents crash from T49813. * TODO(kevin): perhaps find a better way to do this? */ if (face_counts->size() != dm->getNumPolys(dm) || face_indices->size() != dm->getNumLoops(dm)) @@ -1093,43 +1153,39 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_star utils::assign_materials(bmain, m_object, mat_map); } -static void get_weight_and_index(CDStreamConfig &config, - Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling, - size_t samples_number) +/* ************************************************************************** */ + +ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) { - Alembic::AbcGeom::index_t i0, i1; + for (int i = 0, e = totedge; i < e; ++i) { + MEdge &edge = edges[i]; - config.weight = get_weight_and_index(config.time, - time_sampling, - samples_number, - i0, - i1); + if (edge.v1 == v1 && edge.v2 == v2) { + return &edge; + } + } - config.index = i0; - config.ceil_index = i1; + return NULL; } -void read_mesh_sample(ImportSettings *settings, - const IPolyMeshSchema &schema, - const ISampleSelector &selector, - CDStreamConfig &config, - bool &do_normals) +static void read_subd_sample(ImportSettings *settings, + const ISubDSchema &schema, + const ISampleSelector &selector, + CDStreamConfig &config) { - const IPolyMeshSchema::Sample sample = schema.getValue(selector); + const ISubDSchema::Sample sample = schema.getValue(selector); AbcMeshData abc_mesh_data; abc_mesh_data.face_counts = sample.getFaceCounts(); abc_mesh_data.face_indices = sample.getFaceIndices(); + abc_mesh_data.vertex_normals = N3fArraySamplePtr(); + abc_mesh_data.face_normals = N3fArraySamplePtr(); abc_mesh_data.positions = sample.getPositions(); - read_normals_params(abc_mesh_data, schema.getNormalsParam(), selector); - - do_normals = (abc_mesh_data.face_normals != NULL); - get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); if (config.weight != 0.0f) { - Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample; + Alembic::AbcGeom::ISubDSchema::Sample ceil_sample; schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast(config.ceil_index))); abc_mesh_data.ceil_positions = ceil_sample.getPositions(); } @@ -1155,19 +1211,6 @@ void read_mesh_sample(ImportSettings *settings, /* ************************************************************************** */ -ABC_INLINE MEdge *find_edge(MEdge *edges, int totedge, int v1, int v2) -{ - for (int i = 0, e = totedge; i < e; ++i) { - MEdge &edge = edges[i]; - - if (edge.v1 == v1 && edge.v2 == v2) { - return &edge; - } - } - - return NULL; -} - AbcSubDReader::AbcSubDReader(const IObject &object, ImportSettings &settings) : AbcObjectReader(object, settings) { @@ -1231,47 +1274,6 @@ void AbcSubDReader::readObjectData(Main *bmain, float time) } } -void read_subd_sample(ImportSettings *settings, - const ISubDSchema &schema, - const ISampleSelector &selector, - CDStreamConfig &config) -{ - const ISubDSchema::Sample sample = schema.getValue(selector); - - AbcMeshData abc_mesh_data; - abc_mesh_data.face_counts = sample.getFaceCounts(); - abc_mesh_data.face_indices = sample.getFaceIndices(); - abc_mesh_data.vertex_normals = N3fArraySamplePtr(); - abc_mesh_data.face_normals = N3fArraySamplePtr(); - abc_mesh_data.positions = sample.getPositions(); - - get_weight_and_index(config, schema.getTimeSampling(), schema.getNumSamples()); - - if (config.weight != 0.0f) { - Alembic::AbcGeom::ISubDSchema::Sample ceil_sample; - schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast(config.ceil_index))); - abc_mesh_data.ceil_positions = ceil_sample.getPositions(); - } - - if ((settings->read_flag & MOD_MESHSEQ_READ_UV) != 0) { - read_uvs_params(config, abc_mesh_data, schema.getUVsParam(), selector); - } - - if ((settings->read_flag & MOD_MESHSEQ_READ_VERT) != 0) { - read_mverts(config, abc_mesh_data); - } - - if ((settings->read_flag & MOD_MESHSEQ_READ_POLY) != 0) { - read_mpolys(config, abc_mesh_data); - } - - if ((settings->read_flag & (MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)) != 0) { - read_custom_data(schema.getArbGeomParams(), config, selector); - } - - /* TODO: face sets */ -} - DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str) { ISampleSelector sample_sel(time); @@ -1298,7 +1300,7 @@ DerivedMesh *AbcSubDReader::read_derivedmesh(DerivedMesh *dm, const float time, } else { /* If the face count changed (e.g. by triangulation), only read points. - * This prevents crash from T49813 + * This prevents crash from T49813. * TODO(kevin): perhaps find a better way to do this? */ if (face_counts->size() != dm->getNumPolys(dm) || face_indices->size() != dm->getNumLoops(dm)) diff --git a/source/blender/alembic/intern/abc_mesh.h b/source/blender/alembic/intern/abc_mesh.h index 28d17105480..64a3109232c 100644 --- a/source/blender/alembic/intern/abc_mesh.h +++ b/source/blender/alembic/intern/abc_mesh.h @@ -109,12 +109,6 @@ private: const Alembic::AbcGeom::ISampleSelector &sample_sel); }; -void read_mesh_sample(ImportSettings *settings, - const Alembic::AbcGeom::IPolyMeshSchema &schema, - const Alembic::AbcGeom::ISampleSelector &selector, - CDStreamConfig &config, - bool &do_normals); - /* ************************************************************************** */ class AbcSubDReader : public AbcObjectReader { @@ -131,11 +125,6 @@ public: DerivedMesh *read_derivedmesh(DerivedMesh *dm, const float time, int read_flag, const char **err_str); }; -void read_subd_sample(ImportSettings *settings, - const Alembic::AbcGeom::ISubDSchema &schema, - const Alembic::AbcGeom::ISampleSelector &selector, - CDStreamConfig &config); - /* ************************************************************************** */ void read_mverts(MVert *mverts, From 2f6f75613fc0845604b205a85203134cca3b1034 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 30 Nov 2016 12:52:48 +0100 Subject: [PATCH 323/590] OCIO: Cleanup style Was a ground work for some more improvements here, but got dragged to some other studio maintenance job here. The plan would be to enable exposure/gamma control for fallback mode which will definitely be really handy for development and might be handy for cases when OCIO config can not be read. --- intern/opencolorio/fallback_impl.cc | 153 ++++++++++++++++++---------- 1 file changed, 97 insertions(+), 56 deletions(-) diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc index 1124e7fd8ab..d0a129360b0 100644 --- a/intern/opencolorio/fallback_impl.cc +++ b/intern/opencolorio/fallback_impl.cc @@ -77,7 +77,8 @@ int FallbackImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr * /*config*/) return 2; } -const char *FallbackImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr * /*config*/, int index) +const char *FallbackImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr * /*config*/, + int index) { if (index == 0) return "Linear"; @@ -87,7 +88,8 @@ const char *FallbackImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr * return NULL; } -OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcPtr * /*config*/, const char *name) +OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcPtr * /*config*/, + const char *name) { if (strcmp(name, "scene_linear") == 0) return COLORSPACE_LINEAR; @@ -109,15 +111,17 @@ OCIO_ConstColorSpaceRcPtr *FallbackImpl::configGetColorSpace(OCIO_ConstConfigRcP return NULL; } -int FallbackImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) +int FallbackImpl::configGetIndexForColorSpace(OCIO_ConstConfigRcPtr *config, + const char *name) { OCIO_ConstColorSpaceRcPtr *cs = configGetColorSpace(config, name); - if (cs == COLORSPACE_LINEAR) + if (cs == COLORSPACE_LINEAR) { return 0; - else if (cs == COLORSPACE_SRGB) + } + else if (cs == COLORSPACE_SRGB) { return 1; - + } return -1; } @@ -131,44 +135,51 @@ int FallbackImpl::configGetNumDisplays(OCIO_ConstConfigRcPtr * /*config*/) return 1; } -const char *FallbackImpl::configGetDisplay(OCIO_ConstConfigRcPtr * /*config*/, int index) +const char *FallbackImpl::configGetDisplay(OCIO_ConstConfigRcPtr * /*config*/, + int index) { - if (index == 0) + if (index == 0) { return "sRGB"; - + } return NULL; } -const char *FallbackImpl::configGetDefaultView(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/) +const char *FallbackImpl::configGetDefaultView(OCIO_ConstConfigRcPtr * /*config*/, + const char * /*display*/) { return "Default"; } -int FallbackImpl::configGetNumViews(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/) +int FallbackImpl::configGetNumViews(OCIO_ConstConfigRcPtr * /*config*/, + const char * /*display*/) { return 1; } -const char *FallbackImpl::configGetView(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/, int index) +const char *FallbackImpl::configGetView(OCIO_ConstConfigRcPtr * /*config*/, + const char * /*display*/, int index) { - if (index == 0) + if (index == 0) { return "Default"; - + } return NULL; } -const char *FallbackImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr * /*config*/, const char * /*display*/, const char * /*view*/) +const char *FallbackImpl::configGetDisplayColorSpaceName(OCIO_ConstConfigRcPtr * /*config*/, + const char * /*display*/, + const char * /*view*/) { return "sRGB"; } -void FallbackImpl::configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr * /*config*/, float *rgb) +void FallbackImpl::configGetDefaultLumaCoefs(OCIO_ConstConfigRcPtr * /*config*/, + float *rgb) { - /* Here we simply use the older Blender assumed primaries of - * ITU-BT.709 / sRGB, or 0.2126729 0.7151522 0.0721750. Brute - * force stupid, but only plausible option given no color management - * system in place. - */ + /* Here we simply use the older Blender assumed primaries of + * ITU-BT.709 / sRGB, or 0.2126729 0.7151522 0.0721750. Brute + * force stupid, but only plausible option given no color management + * system in place. + */ rgb[0] = 0.2126f; rgb[1] = 0.7152f; @@ -180,12 +191,14 @@ int FallbackImpl::configGetNumLooks(OCIO_ConstConfigRcPtr * /*config*/) return 0; } -const char *FallbackImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr * /*config*/, int /*index*/) +const char *FallbackImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr * /*config*/, + int /*index*/) { return ""; } -OCIO_ConstLookRcPtr *FallbackImpl::configGetLook(OCIO_ConstConfigRcPtr * /*config*/, const char * /*name*/) +OCIO_ConstLookRcPtr *FallbackImpl::configGetLook(OCIO_ConstConfigRcPtr * /*config*/, + const char * /*name*/) { return NULL; } @@ -213,25 +226,30 @@ void FallbackImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr * /*cs*/) { } -OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName) +OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames( + OCIO_ConstConfigRcPtr *config, + const char *srcName, + const char *dstName) { OCIO_ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName); OCIO_ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName); - - if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) + if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) { return PROCESSOR_LINEAR_TO_SRGB; - else if (cs_src == COLORSPACE_SRGB && cs_dst == COLORSPACE_LINEAR) + } + else if (cs_src == COLORSPACE_SRGB && cs_dst == COLORSPACE_LINEAR) { return PROCESSOR_SRGB_TO_LINEAR; - + } return 0; } -OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessor(OCIO_ConstConfigRcPtr * /*config*/, OCIO_ConstTransformRcPtr *tfm) +OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessor(OCIO_ConstConfigRcPtr * /*config*/, + OCIO_ConstTransformRcPtr *tfm) { return (OCIO_ConstProcessorRcPtr*)tfm; } -void FallbackImpl::processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) +void FallbackImpl::processorApply(OCIO_ConstProcessorRcPtr *processor, + OCIO_PackedImageDesc *img) { /* OCIO_TODO stride not respected, channels must be 3 or 4 */ OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)img; @@ -253,7 +271,8 @@ void FallbackImpl::processorApply(OCIO_ConstProcessorRcPtr *processor, OCIO_Pack } } -void FallbackImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, OCIO_PackedImageDesc *img) +void FallbackImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, + OCIO_PackedImageDesc *img) { /* OCIO_TODO stride not respected, channels must be 3 or 4 */ OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)img; @@ -275,15 +294,19 @@ void FallbackImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, } } -void FallbackImpl::processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel) +void FallbackImpl::processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, + float *pixel) { - if (processor == PROCESSOR_LINEAR_TO_SRGB) + if (processor == PROCESSOR_LINEAR_TO_SRGB) { linearrgb_to_srgb_v3_v3(pixel, pixel); - else if (processor == PROCESSOR_SRGB_TO_LINEAR) + } + else if (processor == PROCESSOR_SRGB_TO_LINEAR) { srgb_to_linearrgb_v3_v3(pixel, pixel); + } } -void FallbackImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel) +void FallbackImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, + float *pixel) { if (processor == PROCESSOR_LINEAR_TO_SRGB) linearrgb_to_srgb_v4(pixel, pixel); @@ -291,7 +314,8 @@ void FallbackImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float srgb_to_linearrgb_v4(pixel, pixel); } -void FallbackImpl::processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, float *pixel) +void FallbackImpl::processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, + float *pixel) { if (pixel[3] == 1.0f || pixel[3] == 0.0f) { processorApplyRGBA(processor, pixel); @@ -320,11 +344,12 @@ void FallbackImpl::processorRelease(OCIO_ConstProcessorRcPtr * /*p*/) const char *FallbackImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs) { - if (cs == COLORSPACE_LINEAR) + if (cs == COLORSPACE_LINEAR) { return "Linear"; - else if (cs == COLORSPACE_SRGB) + } + else if (cs == COLORSPACE_SRGB) { return "sRGB"; - + } return NULL; } @@ -343,31 +368,38 @@ OCIO_DisplayTransformRcPtr *FallbackImpl::createDisplayTransform(void) return (OCIO_DisplayTransformRcPtr*)PROCESSOR_LINEAR_TO_SRGB; } -void FallbackImpl::displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*name*/) +void FallbackImpl::displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr * /*dt*/, + const char * /*name*/) { } -void FallbackImpl::displayTransformSetDisplay(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*name*/) +void FallbackImpl::displayTransformSetDisplay(OCIO_DisplayTransformRcPtr * /*dt*/, + const char * /*name*/) { } -void FallbackImpl::displayTransformSetView(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*name*/) +void FallbackImpl::displayTransformSetView(OCIO_DisplayTransformRcPtr * /*dt*/, + const char * /*name*/) { } -void FallbackImpl::displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr * /*dt*/, OCIO_ConstTransformRcPtr * /*et*/) +void FallbackImpl::displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr * /*dt*/, + OCIO_ConstTransformRcPtr * /*et*/) { } -void FallbackImpl::displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr * /*dt*/, OCIO_ConstTransformRcPtr * /*et*/) +void FallbackImpl::displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr * /*dt*/, + OCIO_ConstTransformRcPtr * /*et*/) { } -void FallbackImpl::displayTransformSetLooksOverride(OCIO_DisplayTransformRcPtr * /*dt*/, const char * /*looks*/) +void FallbackImpl::displayTransformSetLooksOverride(OCIO_DisplayTransformRcPtr * /*dt*/, + const char * /*looks*/) { } -void FallbackImpl::displayTransformSetLooksOverrideEnabled(OCIO_DisplayTransformRcPtr * /*dt*/, bool /*enabled*/) +void FallbackImpl::displayTransformSetLooksOverrideEnabled(OCIO_DisplayTransformRcPtr * /*dt*/, + bool /*enabled*/) { } @@ -375,11 +407,14 @@ void FallbackImpl::displayTransformRelease(OCIO_DisplayTransformRcPtr * /*dt*/) { } -OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(float *data, long width, long height, long numChannels, - long chanStrideBytes, long xStrideBytes, long yStrideBytes) +OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc( + float *data, + long width, long height, long numChannels, + long chanStrideBytes, long xStrideBytes, long yStrideBytes) { - OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription*)MEM_callocN(sizeof(OCIO_PackedImageDescription), "OCIO_PackedImageDescription"); - + OCIO_PackedImageDescription *desc = + (OCIO_PackedImageDescription*)MEM_callocN(sizeof(OCIO_PackedImageDescription), + "OCIO_PackedImageDescription"); desc->data = data; desc->width = width; desc->height = height; @@ -387,7 +422,6 @@ OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(float *data, long desc->chanStrideBytes = chanStrideBytes; desc->xStrideBytes = xStrideBytes; desc->yStrideBytes = yStrideBytes; - return (OCIO_PackedImageDesc*)desc; } @@ -401,7 +435,8 @@ OCIO_ExponentTransformRcPtr *FallbackImpl::createExponentTransform(void) return (OCIO_ExponentTransformRcPtr*)PROCESSOR_UNKNOWN; } -void FallbackImpl::exponentTransformSetValue(OCIO_ExponentTransformRcPtr * /*et*/, const float * /*exponent*/) +void FallbackImpl::exponentTransformSetValue(OCIO_ExponentTransformRcPtr * /*et*/, + const float * /*exponent*/) { } @@ -414,7 +449,9 @@ OCIO_MatrixTransformRcPtr *FallbackImpl::createMatrixTransform(void) return (OCIO_MatrixTransformRcPtr*)PROCESSOR_UNKNOWN; } -void FallbackImpl::matrixTransformSetValue(OCIO_MatrixTransformRcPtr * /*mt*/, const float * /*m44*/, const float * /*offset4*/) +void FallbackImpl::matrixTransformSetValue(OCIO_MatrixTransformRcPtr * /*mt*/, + const float * /*m44*/, + const float * /*offset4*/) { } @@ -422,7 +459,9 @@ void FallbackImpl::matrixTransformRelease(OCIO_MatrixTransformRcPtr * /*mt*/) { } -void FallbackImpl::matrixTransformScale(float * /*m44*/, float * /*offset44*/, const float * /*scale4*/) +void FallbackImpl::matrixTransformScale(float * /*m44*/, + float * /*offset44*/, + const float * /*scale4*/) { } @@ -431,9 +470,11 @@ bool FallbackImpl::supportGLSLDraw(void) return false; } -bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState ** /*state_r*/, OCIO_ConstProcessorRcPtr * /*processor*/, +bool FallbackImpl::setupGLSLDraw(struct OCIO_GLSLDrawState ** /*state_r*/, + OCIO_ConstProcessorRcPtr * /*processor*/, OCIO_CurveMappingSettings * /*curve_mapping_settings*/, - float /*dither*/, bool /*predivide*/) + float /*dither*/, + bool /*predivide*/) { return false; } From df63195d2a7bc374398b0b6dfa389db3b40f5a70 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 30 Nov 2016 15:25:54 +0100 Subject: [PATCH 324/590] Cleanup id->newid usage, initial work. This aims at always ensuring that ID.newid (and relevant LIB_TAG_NEW) stay in clean (i.e. cleared) state by default. To achieve this, instead of clearing after all id copy call (would be horribly noisy, and bad for performances), we try to completely remove the setting of id->newid by default when copying a new ID. This implies that areas actually needing that info (mainly, object editing area (make single user...) and make local area) have to ensure they set it themselves as needed. This is far from simple change, many complex code paths to consider, so will need some serious testing. :/ --- source/blender/blenkernel/BKE_animsys.h | 2 +- source/blender/blenkernel/BKE_library.h | 1 + source/blender/blenkernel/intern/anim_sys.c | 8 +- source/blender/blenkernel/intern/brush.c | 3 + source/blender/blenkernel/intern/depsgraph.c | 6 +- source/blender/blenkernel/intern/image.c | 1 - source/blender/blenkernel/intern/library.c | 33 ++++-- source/blender/blenkernel/intern/object.c | 3 + source/blender/blenkernel/intern/rigidbody.c | 4 +- source/blender/blenkernel/intern/sca.c | 22 ++-- source/blender/blenkernel/intern/scene.c | 8 +- source/blender/blenkernel/intern/sequencer.c | 3 +- source/blender/blenloader/intern/readfile.c | 1 + .../editors/interface/interface_templates.c | 5 +- source/blender/editors/object/object_add.c | 107 +++++++++++------- .../blender/editors/object/object_relations.c | 98 +++++++--------- .../editors/space_outliner/outliner_tools.c | 3 + .../editors/space_outliner/outliner_tree.c | 7 +- source/blender/makesdna/DNA_ID.h | 6 +- source/blender/makesrna/intern/rna_ID.c | 4 +- 20 files changed, 180 insertions(+), 145 deletions(-) diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 00ea323f934..a67e903877a 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -73,7 +73,7 @@ struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action); bool BKE_animdata_copy_id(struct ID *id_to, struct ID *id_from, const bool do_action); /* Copy AnimData Actions */ -void BKE_animdata_copy_id_action(struct ID *id); +void BKE_animdata_copy_id_action(struct ID *id, const bool set_newid); /* Merge copies of data from source AnimData block */ typedef enum eAnimData_MergeCopy_Modes { diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 855eb10976c..77ea7ecbefb 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -80,6 +80,7 @@ void id_us_plus(struct ID *id); void id_us_min(struct ID *id); void id_fake_user_set(struct ID *id); void id_fake_user_clear(struct ID *id); +void BKE_id_clear_newpoin(struct ID *id); void BKE_id_make_local_generic(struct Main *bmain, struct ID *id, const bool id_in_mainlist, const bool lib_local); bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local); diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index a5abc6beff8..21279392392 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -308,17 +308,19 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action) return true; } -void BKE_animdata_copy_id_action(ID *id) +void BKE_animdata_copy_id_action(ID *id, const bool set_newid) { AnimData *adt = BKE_animdata_from_id(id); if (adt) { if (adt->action) { id_us_min((ID *)adt->action); - adt->action = BKE_action_copy(G.main, adt->action); + adt->action = set_newid ? ID_NEW_SET(adt->action, BKE_action_copy(G.main, adt->action)) : + BKE_action_copy(G.main, adt->action); } if (adt->tmpact) { id_us_min((ID *)adt->tmpact); - adt->tmpact = BKE_action_copy(G.main, adt->tmpact); + adt->tmpact = set_newid ? ID_NEW_SET(adt->tmpact, BKE_action_copy(G.main, adt->tmpact)) : + BKE_action_copy(G.main, adt->tmpact); } } } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 8ef1fae1155..0d509ecea06 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -249,6 +249,9 @@ void BKE_brush_make_local(Main *bmain, Brush *brush, const bool lib_local) brush_new->id.us = 0; + /* setting newid is mandatory for complex make_lib_local logic... */ + ID_NEW_SET(brush, brush_new); + if (!lib_local) { BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE); } diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 50f8423bbff..7361645ba2c 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -1428,7 +1428,6 @@ static void scene_sort_groups(Main *bmain, Scene *sce) /* test; are group objects all in this scene? */ for (ob = bmain->object.first; ob; ob = ob->id.next) { ob->id.tag &= ~LIB_TAG_DOIT; - ob->id.newid = NULL; /* newid abuse for GroupObject */ } for (base = sce->base.first; base; base = base->next) base->object->id.tag |= LIB_TAG_DOIT; @@ -1459,6 +1458,11 @@ static void scene_sort_groups(Main *bmain, Scene *sce) group->gobject = listb; } } + + /* newid abused for GroupObject, cleanup. */ + for (ob = bmain->object.first; ob; ob = ob->id.next) { + ob->id.newid = NULL; + } } static void dag_scene_tag_rebuild(Scene *sce) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index c9bad2160ff..a2d94ccc478 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -436,7 +436,6 @@ static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src) Image *BKE_image_copy(Main *bmain, Image *ima) { Image *nima = image_alloc(bmain, ima->id.name + 2, ima->source, ima->type); - ima->id.newid = &nima->id; BLI_strncpy(nima->name, ima->name, sizeof(ima->name)); diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 3411eae22e1..31c10c843da 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -263,6 +263,14 @@ void id_fake_user_clear(ID *id) } } +void BKE_id_clear_newpoin(ID *id) +{ + if (id->newid) { + id->newid->tag &= ~LIB_TAG_NEW; + } + id->newid = NULL; +} + static int id_expand_local_callback( void *UNUSED(user_data), struct ID *id_self, struct ID **id_pointer, int UNUSED(cd_flag)) { @@ -326,6 +334,17 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c if (id_copy(bmain, id, &id_new, false)) { id_new->us = 0; + /* setting newid is mandatory for complex make_lib_local logic... */ + ID_NEW_SET(id, id_new); + Key *key = BKE_key_from_id(id), *key_new = BKE_key_from_id(id); + if (key && key_new) { + ID_NEW_SET(key, key_new); + } + bNodeTree *ntree = ntreeFromID(id), *ntree_new = ntreeFromID(id_new); + if (ntree && ntree_new) { + ID_NEW_SET(ntree, ntree_new); + } + if (!lib_local) { BKE_libblock_remap(bmain, id, id_new, ID_REMAP_SKIP_INDIRECT_USAGE); } @@ -337,6 +356,8 @@ void BKE_id_make_local_generic(Main *bmain, ID *id, const bool id_in_mainlist, c /** * Calls the appropriate make_local method for the block, unless test is set. * + * \note Always set ID->newid pointer in case it gets duplicated... + * * \param lib_local Special flag used when making a whole library's content local, it needs specific handling. * * \return true if the block can be made local. @@ -561,6 +582,7 @@ bool id_copy(Main *bmain, ID *id, ID **newid, bool test) return false; } +/** Does *not* set ID->newid pointer. */ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) { ID *newid = NULL; @@ -571,11 +593,11 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) if (RNA_property_editable(ptr, prop)) { if (id_copy(CTX_data_main(C), id, &newid, false) && newid) { /* copy animation actions too */ - BKE_animdata_copy_id_action(id); + BKE_animdata_copy_id_action(id, false); /* us is 1 by convention, but RNA_property_pointer_set * will also increment it, so set it to zero */ newid->us = 0; - + /* assign copy */ RNA_id_pointer_create(newid, &idptr); RNA_property_pointer_set(ptr, prop, idptr); @@ -1120,9 +1142,6 @@ void *BKE_libblock_copy(Main *bmain, ID *id) memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID)); } - - id->newid = idn; - idn->tag |= LIB_TAG_NEW; BKE_libblock_copy_data(idn, id, false); @@ -1147,8 +1166,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action) memcpy(cpn + sizeof(ID), cp + sizeof(ID), idn_len - sizeof(ID)); } - id->newid = idn; - idn->tag |= LIB_TAG_NEW; idn->us = 1; BKE_libblock_copy_data(idn, id, do_action); @@ -1662,7 +1679,6 @@ void BKE_library_make_local( const bool do_skip = (id && !BKE_idcode_is_linkable(GS(id->name))); for (; id; id = id->next) { - id->newid = NULL; id->tag &= ~LIB_TAG_DOIT; if (id->lib == NULL) { @@ -1862,6 +1878,7 @@ void BKE_library_make_local( } } + BKE_main_id_clear_newpoins(bmain); BLI_memarena_free(linklist_mem); } diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 4489ca907f6..c6666ec5ced 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -1215,6 +1215,9 @@ void BKE_object_make_local_ex(Main *bmain, Object *ob, const bool lib_local, con ob_new->id.us = 0; ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL; + /* setting newid is mandatory for complex make_lib_local logic... */ + ID_NEW_SET(ob, ob_new); + if (!lib_local) { BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE); } diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index ebf9f017731..628222ed306 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -225,8 +225,8 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) /* preserve relationships between constraints and rigid bodies after duplication */ void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) { - ID_NEW(rbc->ob1); - ID_NEW(rbc->ob2); + ID_NEW_REMAP(rbc->ob1); + ID_NEW_REMAP(rbc->ob2); } /* ************************************** */ diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index c7f406089d9..fa221348932 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -602,41 +602,41 @@ void set_sca_new_poins_ob(Object *ob) if (act->flag & ACT_NEW) { if (act->type==ACT_EDIT_OBJECT) { bEditObjectActuator *eoa= act->data; - ID_NEW(eoa->ob); + ID_NEW_REMAP(eoa->ob); } else if (act->type==ACT_SCENE) { bSceneActuator *sca= act->data; - ID_NEW(sca->camera); + ID_NEW_REMAP(sca->camera); } else if (act->type==ACT_CAMERA) { bCameraActuator *ca= act->data; - ID_NEW(ca->ob); + ID_NEW_REMAP(ca->ob); } else if (act->type==ACT_OBJECT) { bObjectActuator *oa= act->data; - ID_NEW(oa->reference); + ID_NEW_REMAP(oa->reference); } else if (act->type==ACT_MESSAGE) { bMessageActuator *ma= act->data; - ID_NEW(ma->toObject); + ID_NEW_REMAP(ma->toObject); } else if (act->type==ACT_PARENT) { bParentActuator *para = act->data; - ID_NEW(para->ob); + ID_NEW_REMAP(para->ob); } else if (act->type==ACT_ARMATURE) { bArmatureActuator *aa = act->data; - ID_NEW(aa->target); - ID_NEW(aa->subtarget); + ID_NEW_REMAP(aa->target); + ID_NEW_REMAP(aa->subtarget); } else if (act->type==ACT_PROPERTY) { bPropertyActuator *pa= act->data; - ID_NEW(pa->ob); + ID_NEW_REMAP(pa->ob); } else if (act->type==ACT_STEERING) { bSteeringActuator *sta = act->data; - ID_NEW(sta->navmesh); - ID_NEW(sta->target); + ID_NEW_REMAP(sta->navmesh); + ID_NEW_REMAP(sta->target); } } act= act->next; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 6e1f11cb526..a699427315e 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -186,8 +186,6 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) scen = BKE_libblock_copy(bmain, &sce->id); BLI_duplicatelist(&(scen->base), &(sce->base)); - BKE_main_id_clear_newpoins(bmain); - id_us_plus((ID *)scen->world); id_us_plus((ID *)scen->set); /* id_us_plus((ID *)scen->gm.dome.warptext); */ /* XXX Not refcounted? see readfile.c */ @@ -225,7 +223,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) } /* copy action and remove animation used by sequencer */ - BKE_animdata_copy_id_action(&scen->id); + BKE_animdata_copy_id_action(&scen->id, false); if (type != SCE_COPY_FULL) remove_sequencer_fcurves(scen); @@ -318,7 +316,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) /* camera */ if (type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) { - ID_NEW(scen->camera); + ID_NEW_REMAP(scen->camera); } /* before scene copy */ @@ -329,7 +327,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) if (scen->world) { id_us_plus((ID *)scen->world); scen->world = BKE_world_copy(bmain, scen->world); - BKE_animdata_copy_id_action((ID *)scen->world); + BKE_animdata_copy_id_action((ID *)scen->world, false); } if (sce->ed) { diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index 65d751a8a72..1d2f5aee440 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -320,7 +320,8 @@ void BKE_sequencer_free_clipboard(void) /* Manage pointers in the clipboard. * note that these pointers should _never_ be access in the sequencer, * they are only for storage while in the clipboard - * notice 'newid' is used for temp pointer storage here, validate on access. + * notice 'newid' is used for temp pointer storage here, validate on access (this is safe usage, + * since those datablocks are fully out of Main lists). */ #define ID_PT (*id_pt) static void seqclipboard_ptr_free(ID **id_pt) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 98c8a260993..af73410728b 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -8102,6 +8102,7 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short id->lib = main->curlib; id->us = ID_FAKE_USERS(id); id->icon_id = 0; + id->newid = NULL; /* Needed because .blend may have been saved with crap value here... */ /* this case cannot be direct_linked: it's just the ID part */ if (bhead->code == ID_ID) { diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index bdad667f206..4db1c845c23 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -303,7 +303,10 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_LOCAL: if (id) { - if (id_make_local(CTX_data_main(C), id, false, false)) { + Main *bmain = CTX_data_main(C); + if (id_make_local(bmain, id, false, false)) { + BKE_main_id_clear_newpoins(bmain); + /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template->ptr, template->prop); RNA_property_pointer_set(&template->ptr, template->prop, idptr); diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 6647102acad..02dd3ed2df5 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1350,7 +1350,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, for (dob = lb->first; dob; dob = dob->next) { Base *basen; - Object *ob = BKE_object_copy(bmain, dob->ob); + Object *ob = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, dob->ob)); /* font duplis can have a totcol without material, we get them from parent * should be implemented better... @@ -1394,6 +1394,11 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, } } + /* Remap new object to itself, and clear again newid pointer of orig object. */ + BKE_libblock_relink(&ob->id); + set_sca_new_poins_ob(ob); + BKE_id_clear_newpoin(&dob->ob->id); + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } @@ -1484,8 +1489,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (parent_gh) BLI_ghash_free(parent_gh, NULL, NULL); - copy_object_set_idnew(C); - free_object_duplilist(lb); base->object->transflag &= ~OB_DUPLI; @@ -1960,8 +1963,12 @@ void OBJECT_OT_convert(wmOperatorType *ot) /* used below, assumes id.new is correct */ /* leaves selection of base/object unaltered */ +/* Does set ID->newid pointers. */ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base, int dupflag) { +#define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } +#define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; } + Base *basen = NULL; Material ***matarar; Object *ob, *obn; @@ -1973,7 +1980,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base ; /* nothing? */ } else { - obn = BKE_object_copy(bmain, ob); + obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); basen = MEM_mallocN(sizeof(Base), "duplibase"); @@ -1995,20 +2002,21 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base /* duplicates using userflags */ if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(&obn->id); + BKE_animdata_copy_id_action(&obn->id, true); } if (dupflag & USER_DUP_MAT) { for (a = 0; a < obn->totcol; a++) { id = (ID *)obn->mat[a]; if (id) { - ID_NEW_US(obn->mat[a]) - else - obn->mat[a] = BKE_material_copy(bmain, obn->mat[a]); + ID_NEW_REMAP_US(obn->mat[a]) + else { + obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a])); + } id_us_min(id); if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(&obn->mat[a]->id); + BKE_animdata_copy_id_action(&obn->mat[a]->id, true); } } } @@ -2018,12 +2026,13 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base for (psys = obn->particlesystem.first; psys; psys = psys->next) { id = (ID *) psys->part; if (id) { - ID_NEW_US(psys->part) - else - psys->part = BKE_particlesettings_copy(bmain, psys->part); + ID_NEW_REMAP_US(psys->part) + else { + psys->part = ID_NEW_SET(psys->part, BKE_particlesettings_copy(bmain, psys->part)); + } if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(&psys->part->id); + BKE_animdata_copy_id_action(&psys->part->id, true); } id_us_min(id); @@ -2037,9 +2046,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base switch (obn->type) { case OB_MESH: if (dupflag & USER_DUP_MESH) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_mesh_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_mesh_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2047,9 +2056,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_CURVE: if (dupflag & USER_DUP_CURVE) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_curve_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2057,9 +2066,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_SURF: if (dupflag & USER_DUP_SURF) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_curve_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2067,9 +2076,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_FONT: if (dupflag & USER_DUP_FONT) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_curve_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2077,9 +2086,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_MBALL: if (dupflag & USER_DUP_MBALL) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_mball_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_mball_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2087,9 +2096,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_LAMP: if (dupflag & USER_DUP_LAMP) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_lamp_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_lamp_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2100,9 +2109,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (obn->pose) BKE_pose_tag_recalc(bmain, obn->pose); if (dupflag & USER_DUP_ARM) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_armature_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data)); BKE_pose_rebuild(obn, obn->data); didit = 1; } @@ -2111,9 +2120,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_LATTICE: if (dupflag != 0) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_lattice_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_lattice_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2121,9 +2130,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_CAMERA: if (dupflag != 0) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_camera_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_camera_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2131,9 +2140,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_SPEAKER: if (dupflag != 0) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_speaker_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_speaker_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2148,12 +2157,15 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag & USER_DUP_ACT) { bActuator *act; - BKE_animdata_copy_id_action((ID *)obn->data); + BKE_animdata_copy_id_action((ID *)obn->data, true); if (key) { - BKE_animdata_copy_id_action((ID *)key); + BKE_animdata_copy_id_action((ID *)key, true); } /* Update the duplicated action in the action actuators */ + /* XXX TODO this code is all wrong! actact->act is user-refcounted (see readfile.c), + * and what about other ID pointers of other BGE logic bricks, + * and since this is object-level, why is it only ran if obdata was duplicated??? -mont29 */ for (act = obn->actuators.first; act; act = act->next) { if (act->type == ACT_ACTION) { bActionActuator *actact = (bActionActuator *) act->data; @@ -2170,9 +2182,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base for (a = 0; a < obn->totcol; a++) { id = (ID *)(*matarar)[a]; if (id) { - ID_NEW_US((*matarar)[a]) - else - (*matarar)[a] = BKE_material_copy(bmain, (*matarar)[a]); + ID_NEW_REMAP_US((*matarar)[a]) + else { + (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a])); + } id_us_min(id); } } @@ -2181,6 +2194,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base } } return basen; + +#undef ID_NEW_REMAP_US +#undef ID_NEW_REMAP_US2 } /* single object duplicate, if dupflag==0, fully linked, else it uses the flags given */ @@ -2193,8 +2209,7 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag Base *basen; Object *ob; - BKE_main_id_clear_newpoins(bmain); - clear_sca_new_poins(); /* sensor/contr/act */ + clear_sca_new_poins(); /* BGE logic */ basen = object_add_duplicate_internal(bmain, scene, base, dupflag); if (basen == NULL) { @@ -2213,6 +2228,8 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag ED_render_id_flush_update(bmain, ob->data); } + BKE_main_id_clear_newpoins(bmain); + return basen; } @@ -2224,8 +2241,7 @@ static int duplicate_exec(bContext *C, wmOperator *op) const bool linked = RNA_boolean_get(op->ptr, "linked"); int dupflag = (linked) ? 0 : U.dupflag; - BKE_main_id_clear_newpoins(bmain); - clear_sca_new_poins(); /* sensor/contr/act */ + clear_sca_new_poins(); /* BGE logic */ CTX_DATA_BEGIN (C, Base *, base, selected_bases) { @@ -2251,6 +2267,8 @@ static int duplicate_exec(bContext *C, wmOperator *op) copy_object_set_idnew(C); + BKE_main_id_clear_newpoins(bmain); + DAG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); @@ -2309,8 +2327,7 @@ static int add_named_exec(bContext *C, wmOperator *op) base->flag = ob->flag; /* prepare dupli */ - BKE_main_id_clear_newpoins(bmain); - clear_sca_new_poins(); /* sensor/contr/act */ + clear_sca_new_poins(); /* BGE logic */ basen = object_add_duplicate_internal(bmain, scene, base, dupflag); @@ -2336,6 +2353,8 @@ static int add_named_exec(bContext *C, wmOperator *op) copy_object_set_idnew(C); + BKE_main_id_clear_newpoins(bmain); + DAG_relations_tag_update(bmain); MEM_freeN(base); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index f448e925dd9..d670f4b8425 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1731,6 +1731,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) /**************************** Make Single User ********************************/ +/* Warning, sets ID->newid pointers of objects and groups, but does not clear them. */ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups) { Base *base; @@ -1738,18 +1739,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in Group *group, *groupn; GroupObject *go; - clear_sca_new_poins(); /* sensor/contr/act */ - - /* newid may still have some trash from Outliner tree building, so clear that first to avoid errors, see T26002. - * We have to clear whole datablocks, not only Object one may be accessed here, see T49905. */ - ListBase *lbarray[MAX_LIBARRAY]; - int a = set_listbasepointers(bmain, lbarray); - while (a--) { - ListBase *lb = lbarray[a]; - for (ID *id = lb->first; id; id = id->next) { - id->newid = NULL; - } - } + clear_sca_new_poins(); /* BGE logic */ /* duplicate (must set newid) */ for (base = FIRSTBASE; base; base = base->next) { @@ -1758,8 +1748,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in if ((base->flag & flag) == flag) { if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) { /* base gets copy of object */ - obn = BKE_object_copy(bmain, ob); - base->object = obn; + base->object = obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); if (copy_groups) { if (ob->flag & OB_FROMGROUP) { @@ -1789,8 +1778,6 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in /* duplicate groups that consist entirely of duplicated objects */ for (group = bmain->group.first; group; group = group->id.next) { - group->id.newid = NULL; - if (copy_groups && group->gobject.first) { bool all_duplicated = true; @@ -1802,10 +1789,11 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in } if (all_duplicated) { - groupn = BKE_group_copy(bmain, group); + groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group)); - for (go = groupn->gobject.first; go; go = go->next) + for (go = groupn->gobject.first; go; go = go->next) { go->ob = (Object *)go->ob->id.newid; + } } } } @@ -1813,8 +1801,8 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in /* group pointers in scene */ BKE_scene_groups_relink(scene); - ID_NEW(scene->camera); - if (v3d) ID_NEW(v3d->camera); + ID_NEW_REMAP(scene->camera); + if (v3d) ID_NEW_REMAP(v3d->camera); /* object and group pointers */ for (base = FIRSTBASE; base; base = base->next) { @@ -1837,6 +1825,8 @@ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob) } single_object_users(bmain, scene, NULL, OB_DONE, copy_groups); + + BKE_main_id_clear_newpoins(bmain); } static void new_id_matar(Main *bmain, Material **matar, const int totcol) @@ -1853,9 +1843,8 @@ static void new_id_matar(Main *bmain, Material **matar, const int totcol) id_us_min(id); } else if (id->us > 1) { - matar[a] = BKE_material_copy(bmain, matar[a]); + matar[a] = ID_NEW_SET(id, BKE_material_copy(bmain, matar[a])); id_us_min(id); - id->newid = (ID *)matar[a]; } } } @@ -1883,45 +1872,46 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) switch (ob->type) { case OB_LAMP: - ob->data = la = BKE_lamp_copy(bmain, ob->data); + ob->data = la = ID_NEW_SET(ob->data, BKE_lamp_copy(bmain, ob->data)); for (a = 0; a < MAX_MTEX; a++) { if (la->mtex[a]) { - ID_NEW(la->mtex[a]->object); + ID_NEW_REMAP(la->mtex[a]->object); } } break; case OB_CAMERA: - ob->data = BKE_camera_copy(bmain, ob->data); + ob->data = ID_NEW_SET(ob->data, BKE_camera_copy(bmain, ob->data)); break; case OB_MESH: - ob->data = me = BKE_mesh_copy(bmain, ob->data); - if (me->key) - BKE_animdata_copy_id_action((ID *)me->key); + /* Needed to remap texcomesh below. */ + me = ob->data = ID_NEW_SET(ob->data, BKE_mesh_copy(bmain, ob->data)); + if (me->key) /* We do not need to set me->key->id.newid here... */ + BKE_animdata_copy_id_action((ID *)me->key, false); break; case OB_MBALL: - ob->data = BKE_mball_copy(bmain, ob->data); + ob->data = ID_NEW_SET(ob->data, BKE_mball_copy(bmain, ob->data)); break; case OB_CURVE: case OB_SURF: case OB_FONT: - ob->data = cu = BKE_curve_copy(bmain, ob->data); - ID_NEW(cu->bevobj); - ID_NEW(cu->taperobj); - if (cu->key) - BKE_animdata_copy_id_action((ID *)cu->key); + ob->data = cu = ID_NEW_SET(ob->data, BKE_curve_copy(bmain, ob->data)); + ID_NEW_REMAP(cu->bevobj); + ID_NEW_REMAP(cu->taperobj); + if (cu->key) /* We do not need to set cu->key->id.newid here... */ + BKE_animdata_copy_id_action((ID *)cu->key, false); break; case OB_LATTICE: - ob->data = lat = BKE_lattice_copy(bmain, ob->data); - if (lat->key) - BKE_animdata_copy_id_action((ID *)lat->key); + ob->data = lat = ID_NEW_SET(ob->data, BKE_lattice_copy(bmain, ob->data)); + if (lat->key) /* We do not need to set lat->key->id.newid here... */ + BKE_animdata_copy_id_action((ID *)lat->key, false); break; case OB_ARMATURE: DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - ob->data = BKE_armature_copy(bmain, ob->data); + ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data)); BKE_pose_rebuild(ob, ob->data); break; case OB_SPEAKER: - ob->data = BKE_speaker_copy(bmain, ob->data); + ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data)); break; default: if (G.debug & G_DEBUG) @@ -1934,17 +1924,16 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) * AnimData structure, which is not what we want. * (sergey) */ - BKE_animdata_copy_id_action((ID *)ob->data); + BKE_animdata_copy_id_action((ID *)ob->data, false); id_us_min(id); - id->newid = ob->data; } } } me = bmain->mesh.first; while (me) { - ID_NEW(me->texcomesh); + ID_NEW_REMAP(me->texcomesh); me = me->id.next; } } @@ -1958,7 +1947,7 @@ static void single_object_action_users(Scene *scene, const int flag) ob = base->object; if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - BKE_animdata_copy_id_action(&ob->id); + BKE_animdata_copy_id_action(&ob->id, false); } } } @@ -1977,11 +1966,11 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo for (a = 1; a <= ob->totcol; a++) { ma = give_current_material(ob, a); if (ma) { - /* do not test for LIB_TAG_NEW: this functions guaranteed delivers single_users! */ + /* do not test for LIB_TAG_NEW or use newid: this functions guaranteed delivers single_users! */ if (ma->id.us > 1) { man = BKE_material_copy(bmain, ma); - BKE_animdata_copy_id_action(&man->id); + BKE_animdata_copy_id_action(&man->id, false); man->id.us = 0; assign_material(ob, man, a, BKE_MAT_ASSIGN_USERPREF); @@ -1992,7 +1981,7 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo if (tex->id.us > 1) { id_us_min(&tex->id); tex = BKE_texture_copy(bmain, tex); - BKE_animdata_copy_id_action(&tex->id); + BKE_animdata_copy_id_action(&tex->id, false); man->mtex[b]->tex = tex; } } @@ -2018,8 +2007,8 @@ static void do_single_tex_user(Main *bmain, Tex **from) id_us_min(&tex->id); } else if (tex->id.us > 1) { - texn = BKE_texture_copy(bmain, tex); - BKE_animdata_copy_id_action(&texn->id); + texn = ID_NEW_SET(tex, BKE_texture_copy(bmain, tex)); + BKE_animdata_copy_id_action(&texn->id, false); tex->id.newid = (ID *)texn; id_us_min(&tex->id); *from = texn; @@ -2096,7 +2085,7 @@ static void single_mat_users_expand(Main *bmain) if (ma->id.tag & LIB_TAG_NEW) for (a = 0; a < MAX_MTEX; a++) if (ma->mtex[a]) - ID_NEW(ma->mtex[a]->object); + ID_NEW_REMAP(ma->mtex[a]->object); } /* used for copying scenes */ @@ -2247,7 +2236,6 @@ static int make_local_exec(bContext *C, wmOperator *op) } tag_localizable_objects(C, mode); - BKE_main_id_clear_newpoins(bmain); CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { @@ -2264,7 +2252,7 @@ static int make_local_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { if (ob->id.lib == NULL) { - ID_NEW(ob->parent); + ID_NEW_REMAP(ob->parent); } } CTX_DATA_END; @@ -2335,6 +2323,7 @@ static int make_local_exec(bContext *C, wmOperator *op) CTX_DATA_END; } + BKE_main_id_clear_newpoins(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; @@ -2381,8 +2370,6 @@ static int make_single_user_exec(bContext *C, wmOperator *op) const bool copy_groups = false; bool update_deps = false; - BKE_main_id_clear_newpoins(bmain); - if (RNA_boolean_get(op->ptr, "object")) { single_object_users(bmain, scene, v3d, flag, copy_groups); @@ -2406,11 +2393,6 @@ static int make_single_user_exec(bContext *C, wmOperator *op) single_object_action_users(scene, flag); } - /* TODO(sergey): This should not be needed, however some tool still could rely - * on the fact, that id->newid is kept NULL by default. - * Need to make sure all the guys are learing newid before they're - * using it, not after. - */ BKE_main_id_clear_newpoins(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 13200e92e7e..7739d241bd3 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -442,6 +442,9 @@ static void id_local_cb( if (id_make_local(bmain, tselem->id, false, false) == false) { id_clear_lib_data(bmain, tselem->id); } + else { + BKE_main_id_clear_newpoins(bmain); + } } } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 20f7ca4db16..ec46c5df9a0 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1645,11 +1645,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) outliner_free_tree(&soops->tree); outliner_storage_cleanup(soops); - /* clear ob id.new flags */ - for (Object *ob = mainvar->object.first; ob; ob = ob->id.next) { - ob->id.newid = NULL; - } - /* options */ if (soops->outlinevis == SO_LIBRARIES) { Library *lib; @@ -1835,6 +1830,8 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) outliner_sort(&soops->tree); } outliner_filter_tree(soops, &soops->tree); + + BKE_main_id_clear_newpoins(mainvar); } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index feeb2d5e4d7..59fd0c7832c 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -290,9 +290,9 @@ typedef enum ID_Type { #endif #define GS(a) (CHECK_TYPE_ANY(a, char *, const char *, char [66], const char[66]), (*((const short *)(a)))) -#define ID_NEW(a) if ( (a) && (a)->id.newid ) (a) = (void *)(a)->id.newid -#define ID_NEW_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } -#define ID_NEW_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; } +#define ID_NEW_SET(_id, _idn) \ + (((ID *)(_id))->newid = (ID *)(_idn), ((ID *)(_id))->newid->tag |= LIB_TAG_NEW, (void *)((ID *)(_id))->newid) +#define ID_NEW_REMAP(a) if ((a) && (a)->id.newid) (a) = (void *)(a)->id.newid /* id->flag (persitent). */ enum { diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 87fb45a4419..896d4979089 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -358,7 +358,9 @@ static struct ID *rna_ID_make_local(struct ID *self, Main *bmain, int clear_prox id_make_local(bmain, self, false, false); } - return self->newid ? self->newid : self; + ID *ret_id = self->newid ? self->newid : self; + BKE_id_clear_newpoin(self); + return ret_id; } From 05b181fbc55ae9eac82d15e9abd45d32a2f386d8 Mon Sep 17 00:00:00 2001 From: lazydodo Date: Wed, 30 Nov 2016 18:26:25 -0700 Subject: [PATCH 325/590] Fix T46795 : Reset GWLP_USERDATA to NULL at window destruction so any future events will not try to reference this deleted class. --- intern/ghost/intern/GHOST_WindowWin32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 2aa950f8278..7d80aa43a40 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -353,7 +353,7 @@ GHOST_WindowWin32::~GHOST_WindowWin32() // Release our reference of the DropTarget and it will delete itself eventually. m_dropTarget->Release(); } - + ::SetWindowLongPtr(m_hWnd, GWLP_USERDATA, NULL); ::DestroyWindow(m_hWnd); m_hWnd = 0; } From 58877d6d082d82185ca611b704364168e5984bd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Thu, 1 Dec 2016 08:32:02 +0100 Subject: [PATCH 326/590] Alembic: quiet compilation warnings on Windows. Most of them are harmless implicit conversions (e.g. Alembic deals with doubles for storing time information when Blender uses both ints and floats/doubles) or class/struct mismatch on forward declarations. --- source/blender/alembic/intern/abc_camera.cc | 18 +++++++++--------- source/blender/alembic/intern/abc_customdata.h | 5 +++-- source/blender/alembic/intern/abc_exporter.cc | 14 +++++++------- source/blender/alembic/intern/abc_mesh.cc | 4 ++-- source/blender/alembic/intern/abc_object.cc | 4 ++-- source/blender/alembic/intern/abc_object.h | 2 +- source/blender/alembic/intern/abc_points.cc | 3 ++- source/blender/alembic/intern/abc_points.h | 2 +- source/blender/alembic/intern/abc_util.cc | 2 +- source/blender/alembic/intern/abc_util.h | 2 +- source/blender/alembic/intern/alembic_capi.cc | 4 ++-- 11 files changed, 31 insertions(+), 29 deletions(-) diff --git a/source/blender/alembic/intern/abc_camera.cc b/source/blender/alembic/intern/abc_camera.cc index d5271e3ca31..4f70b2a972c 100644 --- a/source/blender/alembic/intern/abc_camera.cc +++ b/source/blender/alembic/intern/abc_camera.cc @@ -138,11 +138,11 @@ void AbcCameraReader::readObjectData(Main *bmain, float time) bcam->stereo.convergence_distance = convergence_plane.getValue(sample_sel); } - const float lens = cam_sample.getFocalLength(); - const float apperture_x = cam_sample.getHorizontalAperture(); - const float apperture_y = cam_sample.getVerticalAperture(); - const float h_film_offset = cam_sample.getHorizontalFilmOffset(); - const float v_film_offset = cam_sample.getVerticalFilmOffset(); + const float lens = static_cast(cam_sample.getFocalLength()); + const float apperture_x = static_cast(cam_sample.getHorizontalAperture()); + const float apperture_y = static_cast(cam_sample.getVerticalAperture()); + const float h_film_offset = static_cast(cam_sample.getHorizontalFilmOffset()); + const float v_film_offset = static_cast(cam_sample.getVerticalFilmOffset()); const float film_aspect = apperture_x / apperture_y; bcam->lens = lens; @@ -150,10 +150,10 @@ void AbcCameraReader::readObjectData(Main *bmain, float time) bcam->sensor_y = apperture_y * 10; bcam->shiftx = h_film_offset / apperture_x; bcam->shifty = v_film_offset / apperture_y / film_aspect; - bcam->clipsta = max_ff(0.1f, cam_sample.getNearClippingPlane()); - bcam->clipend = cam_sample.getFarClippingPlane(); - bcam->gpu_dof.focus_distance = cam_sample.getFocusDistance(); - bcam->gpu_dof.fstop = cam_sample.getFStop(); + bcam->clipsta = max_ff(0.1f, static_cast(cam_sample.getNearClippingPlane())); + bcam->clipend = static_cast(cam_sample.getFarClippingPlane()); + bcam->gpu_dof.focus_distance = static_cast(cam_sample.getFocusDistance()); + bcam->gpu_dof.fstop = static_cast(cam_sample.getFStop()); m_object = BKE_object_add_only_object(bmain, OB_CAMERA, m_object_name.c_str()); m_object->data = bcam; diff --git a/source/blender/alembic/intern/abc_customdata.h b/source/blender/alembic/intern/abc_customdata.h index bc42e24eba1..9e671fde386 100644 --- a/source/blender/alembic/intern/abc_customdata.h +++ b/source/blender/alembic/intern/abc_customdata.h @@ -26,6 +26,7 @@ #define __ABC_CUSTOMDATA_H__ #include +#include struct CustomData; struct MLoop; @@ -65,8 +66,8 @@ struct CDStreamConfig { float weight; float time; - int index; - int ceil_index; + Alembic::AbcGeom::index_t index; + Alembic::AbcGeom::index_t ceil_index; CDStreamConfig() : mloop(NULL) diff --git a/source/blender/alembic/intern/abc_exporter.cc b/source/blender/alembic/intern/abc_exporter.cc index d259721e192..ff8b0442ab6 100644 --- a/source/blender/alembic/intern/abc_exporter.cc +++ b/source/blender/alembic/intern/abc_exporter.cc @@ -176,13 +176,13 @@ void AbcExporter::getShutterSamples(double step, bool time_relative, /* sample all frame */ if (shutter_open == 0.0 && shutter_close == 1.0) { - for (double t = 0; t < 1.0; t += step) { + for (double t = 0.0; t < 1.0; t += step) { samples.push_back((t + m_settings.frame_start) / time_factor); } } else { /* sample between shutter open & close */ - const int nsamples = std::max((1.0 / step) - 1.0, 1.0); + const int nsamples = static_cast(std::max((1.0 / step) - 1.0, 1.0)); const double time_inc = (shutter_close - shutter_open) / nsamples; for (double t = shutter_open; t <= shutter_close; t += time_inc) { @@ -217,7 +217,7 @@ void AbcExporter::getFrameSet(double step, std::set &frames) getShutterSamples(step, false, shutter_samples); - for (int frame = m_settings.frame_start; frame <= m_settings.frame_end; ++frame) { + for (double frame = m_settings.frame_start; frame <= m_settings.frame_end; frame += 1.0) { for (int j = 0, e = shutter_samples.size(); j < e; ++j) { frames.insert(frame + shutter_samples[j]); } @@ -238,9 +238,9 @@ void AbcExporter::operator()(Main *bmain, float &progress, bool &was_canceled) } Scene *scene = m_scene; - const int fps = FPS; + const double fps = FPS; char buf[16]; - snprintf(buf, 15, "%d", fps); + snprintf(buf, 15, "%f", fps); const std::string str_fps = buf; Alembic::AbcCoreAbstract::MetaData md; @@ -578,7 +578,7 @@ AbcTransformWriter *AbcExporter::getXForm(const std::string &name) void AbcExporter::setCurrentFrame(Main *bmain, double t) { - m_scene->r.cfra = std::floor(t); - m_scene->r.subframe = t - m_scene->r.cfra; + m_scene->r.cfra = static_cast(t); + m_scene->r.subframe = static_cast(t) - m_scene->r.cfra; BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, m_scene, m_scene->lay); } diff --git a/source/blender/alembic/intern/abc_mesh.cc b/source/blender/alembic/intern/abc_mesh.cc index 4fe1f2b51d0..bdd75f93189 100644 --- a/source/blender/alembic/intern/abc_mesh.cc +++ b/source/blender/alembic/intern/abc_mesh.cc @@ -952,7 +952,7 @@ static void read_mesh_sample(ImportSettings *settings, if (config.weight != 0.0f) { Alembic::AbcGeom::IPolyMeshSchema::Sample ceil_sample; - schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast(config.ceil_index))); + schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); abc_mesh_data.ceil_positions = ceil_sample.getPositions(); } @@ -1186,7 +1186,7 @@ static void read_subd_sample(ImportSettings *settings, if (config.weight != 0.0f) { Alembic::AbcGeom::ISubDSchema::Sample ceil_sample; - schema.get(ceil_sample, Alembic::Abc::ISampleSelector(static_cast(config.ceil_index))); + schema.get(ceil_sample, Alembic::Abc::ISampleSelector(config.ceil_index)); abc_mesh_data.ceil_positions = ceil_sample.getPositions(); } diff --git a/source/blender/alembic/intern/abc_object.cc b/source/blender/alembic/intern/abc_object.cc index 314b2568bed..9dfccdb8c7f 100644 --- a/source/blender/alembic/intern/abc_object.cc +++ b/source/blender/alembic/intern/abc_object.cc @@ -170,13 +170,13 @@ static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { - mat0[i][j] = m0[i][j]; + mat0[i][j] = static_cast(m0[i][j]); } } for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { - mat1[i][j] = m1[i][j]; + mat1[i][j] = static_cast(m1[i][j]); } } diff --git a/source/blender/alembic/intern/abc_object.h b/source/blender/alembic/intern/abc_object.h index d1bcbbe6cbe..0f733e67d3f 100644 --- a/source/blender/alembic/intern/abc_object.h +++ b/source/blender/alembic/intern/abc_object.h @@ -76,7 +76,7 @@ private: /* ************************************************************************** */ -class CacheFile; +struct CacheFile; struct ImportSettings { bool do_convert_mat; diff --git a/source/blender/alembic/intern/abc_points.cc b/source/blender/alembic/intern/abc_points.cc index 6ddba350b0a..4c78f3e83c7 100644 --- a/source/blender/alembic/intern/abc_points.cc +++ b/source/blender/alembic/intern/abc_points.cc @@ -189,7 +189,8 @@ void read_points_sample(const IPointsSchema &schema, N3fArraySamplePtr vnormals; if (has_property(prop, "N")) { - const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", time); + const Alembic::Util::uint32_t itime = static_cast(time); + const IN3fArrayProperty &normals_prop = IN3fArrayProperty(prop, "N", itime); if (normals_prop) { vnormals = normals_prop.getValue(selector); diff --git a/source/blender/alembic/intern/abc_points.h b/source/blender/alembic/intern/abc_points.h index 792283f04d3..cb68dbca4d5 100644 --- a/source/blender/alembic/intern/abc_points.h +++ b/source/blender/alembic/intern/abc_points.h @@ -28,7 +28,7 @@ #include "abc_object.h" #include "abc_customdata.h" -class ParticleSystem; +struct ParticleSystem; /* ************************************************************************** */ diff --git a/source/blender/alembic/intern/abc_util.cc b/source/blender/alembic/intern/abc_util.cc index 979a72fcf4e..f8ce72d845d 100644 --- a/source/blender/alembic/intern/abc_util.cc +++ b/source/blender/alembic/intern/abc_util.cc @@ -215,7 +215,7 @@ void convert_matrix(const Imath::M44d &xform, Object *ob, { for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { - r_mat[i][j] = xform[i][j]; + r_mat[i][j] = static_cast(xform[i][j]); } } diff --git a/source/blender/alembic/intern/abc_util.h b/source/blender/alembic/intern/abc_util.h index 2f423a9f8c5..60a96855d14 100644 --- a/source/blender/alembic/intern/abc_util.h +++ b/source/blender/alembic/intern/abc_util.h @@ -39,7 +39,7 @@ struct CacheReader { using Alembic::Abc::chrono_t; class AbcObjectReader; -class ImportSettings; +struct ImportSettings; struct ID; struct Object; diff --git a/source/blender/alembic/intern/alembic_capi.cc b/source/blender/alembic/intern/alembic_capi.cc index d0eb9900f4f..d8d017119b1 100644 --- a/source/blender/alembic/intern/alembic_capi.cc +++ b/source/blender/alembic/intern/alembic_capi.cc @@ -625,8 +625,8 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa CFRA = SFRA; } else if (min_time < max_time) { - SFRA = min_time * FPS; - EFRA = max_time * FPS; + SFRA = static_cast(min_time * FPS); + EFRA = static_cast(max_time * FPS); CFRA = SFRA; } } From 87cd56b012494e20be06b63f85b798fa043c3194 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 1 Dec 2016 12:11:11 +0100 Subject: [PATCH 327/590] Fix T50075: Assert during debug render of hair_geom_transmission.blend --- intern/cycles/kernel/closure/bsdf_hair.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/intern/cycles/kernel/closure/bsdf_hair.h b/intern/cycles/kernel/closure/bsdf_hair.h index bede5f45e7e..daaa26dc6ad 100644 --- a/intern/cycles/kernel/closure/bsdf_hair.h +++ b/intern/cycles/kernel/closure/bsdf_hair.h @@ -267,7 +267,10 @@ ccl_device int bsdf_hair_transmission_sample(const ShaderClosure *sc, float3 Ng, *eval = make_float3(*pdf, *pdf, *pdf); - kernel_assert(dot(locy, *omega_in) < 0.0f); + /* TODO(sergey): Should always be negative, but seems some precision issue + * is involved here. + */ + kernel_assert(dot(locy, *omega_in) < 1e-4f); return LABEL_TRANSMIT|LABEL_GLOSSY; } From 9d50175b6cc5860926f0974fafd9e8e7868eb805 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Sat, 26 Nov 2016 17:30:02 +0100 Subject: [PATCH 328/590] Cycles: Fix correlation issues in certain cases There were two cases where correlation issues were obvious: - File from T38710 was giving issues in 2.78a again - File from T50116 was having totally different shadow between sample 1 and sample 32. Use some more simplified version of CMJ hash which seems to give nice randomized value which solves the correlation. This commit will break all unit test files, but it's a bug fix so perhaps OK to commit this. This also fixes T41143: Sobol gives nonuniform noise Proper science paper about hash function is coming. Reviewers: brecht Reviewed By: brecht Subscribers: lukasstockner97 Differential Revision: https://developer.blender.org/D2385 --- intern/cycles/kernel/kernel_jitter.h | 9 +++++++++ intern/cycles/kernel/kernel_random.h | 12 +++++------- intern/cycles/kernel/kernel_volume.h | 9 ++------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/intern/cycles/kernel/kernel_jitter.h b/intern/cycles/kernel/kernel_jitter.h index aec7bc33acd..67546131746 100644 --- a/intern/cycles/kernel/kernel_jitter.h +++ b/intern/cycles/kernel/kernel_jitter.h @@ -149,6 +149,15 @@ ccl_device_inline uint cmj_hash(uint i, uint p) return i; } +ccl_device_inline uint cmj_hash_simple(uint i, uint p) +{ + i = (i ^ 61) ^ p; + i += i << 3; + i ^= i >> 4; + i *= 0x27d4eb2d; + return i; +} + ccl_device_inline float cmj_randfloat(uint i, uint p) { return cmj_hash(i, p) * (1.0f / 4294967808.0f); diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index 2b767da5041..e773753396f 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -120,13 +120,11 @@ ccl_device_forceinline float path_rng_1D(KernelGlobals *kg, ccl_addr_space RNG * /* Cranly-Patterson rotation using rng seed */ float shift; - /* using the same *rng value to offset seems to give correlation issues, - * we could hash it with the dimension but this has a performance impact, - * we need to find a solution for this */ - if(dimension & 1) - shift = (*rng >> 16) * (1.0f/(float)0xFFFF); - else - shift = (*rng & 0xFFFF) * (1.0f/(float)0xFFFF); + /* Hash rng with dimension to solve correlation issues. + * See T38710, T50116. + */ + RNG tmp_rng = cmj_hash_simple(dimension, *rng); + shift = tmp_rng * (1.0f/(float)0xFFFFFFFF); return r + shift - floorf(r + shift); #endif diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index dd7b0d9812d..a07ce6be077 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -582,17 +582,12 @@ ccl_device VolumeIntegrateResult kernel_volume_integrate_heterogeneous_distance( ccl_device_noinline VolumeIntegrateResult kernel_volume_integrate(KernelGlobals *kg, PathState *state, ShaderData *sd, Ray *ray, PathRadiance *L, float3 *throughput, RNG *rng, bool heterogeneous) { - /* workaround to fix correlation bug in T38710, can find better solution - * in random number generator later, for now this is done here to not impact - * performance of rendering without volumes */ - RNG tmp_rng = cmj_hash(*rng, state->rng_offset); - shader_setup_from_volume(kg, sd, ray); if(heterogeneous) - return kernel_volume_integrate_heterogeneous_distance(kg, state, ray, sd, L, throughput, &tmp_rng); + return kernel_volume_integrate_heterogeneous_distance(kg, state, ray, sd, L, throughput, rng); else - return kernel_volume_integrate_homogeneous(kg, state, ray, sd, L, throughput, &tmp_rng, true); + return kernel_volume_integrate_homogeneous(kg, state, ray, sd, L, throughput, rng, true); } /* Decoupled Volume Sampling From f812b05922f51c4c6c5d1c8898fb2cd6aba3f3f0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 1 Dec 2016 14:27:10 +0100 Subject: [PATCH 329/590] Fix T50116: Light threshold broke branched path tracer In fact, the issue was caused by light threshold being too high for certain scenes. Lowered it down to 0.01. --- intern/cycles/blender/addon/properties.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 607aafbfa1d..3616b13e751 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -288,7 +288,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Probabilistically terminate light samples when the light contribution is below this threshold (more noise but faster rendering). " "Zero disables the test and never ignores lights", min=0.0, max=1.0, - default=0.05, + default=0.01, ) cls.caustics_reflective = BoolProperty( From 87cacd3893a7e07b38b4b9b4de553898987148b8 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 1 Dec 2016 15:05:53 +0100 Subject: [PATCH 330/590] Buildbot: Disable glibc211 slaves --- build_files/buildbot/master.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_files/buildbot/master.cfg b/build_files/buildbot/master.cfg index 6b7191cd57b..387e53593b3 100644 --- a/build_files/buildbot/master.cfg +++ b/build_files/buildbot/master.cfg @@ -297,8 +297,8 @@ def generic_builder(id, libdir='', branch='', rsync=False): # Builders add_builder(c, 'mac_x86_64_10_6_cmake', 'darwin-9.x.universal', generic_builder, hour=5) -add_builder(c, 'linux_glibc211_i686_cmake', '', generic_builder, hour=1) -add_builder(c, 'linux_glibc211_x86_64_cmake', '', generic_builder, hour=2) +# add_builder(c, 'linux_glibc211_i686_cmake', '', generic_builder, hour=1) +# add_builder(c, 'linux_glibc211_x86_64_cmake', '', generic_builder, hour=2) add_builder(c, 'linux_glibc219_i686_cmake', '', generic_builder, hour=3) add_builder(c, 'linux_glibc219_x86_64_cmake', '', generic_builder, hour=4) add_builder(c, 'win32_cmake_vc2013', 'windows_vc12', generic_builder, hour=3) From d258865995821e6bc8abe0bb5d72f8dd1e7910b9 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 1 Dec 2016 19:34:35 +1300 Subject: [PATCH 331/590] Compiler warning fix --- source/blender/editors/transform/transform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index daf0aed59e7..d4cd2351f46 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -103,7 +103,7 @@ static void drawEdgeSlide(TransInfo *t); static void drawVertSlide(TransInfo *t); static void postInputRotation(TransInfo *t, float values[3]); -static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around); +static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], const short around); static void initSnapSpatial(TransInfo *t, float r_snap[3]); From bdceea9475ea039b76bee3b290f17ef800d3433e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 1 Dec 2016 19:36:30 +1300 Subject: [PATCH 332/590] GPencil Sculpt: Numpad keys now work when doing sculpt sessions (i.e. when the operator is run using wait_for_input=True) This just brings it in line with the drawing operator --- source/blender/editors/gpencil/gpencil_brush.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/editors/gpencil/gpencil_brush.c b/source/blender/editors/gpencil/gpencil_brush.c index 8576cbca239..ec5a42c23a5 100644 --- a/source/blender/editors/gpencil/gpencil_brush.c +++ b/source/blender/editors/gpencil/gpencil_brush.c @@ -1798,6 +1798,12 @@ static int gpsculpt_brush_modal(bContext *C, wmOperator *op, const wmEvent *even case UPARROWKEY: case DOWNARROWKEY: return OPERATOR_PASS_THROUGH; + + /* Camera/View Manipulations - Allowed */ + /* (See rationale in gpencil_paint.c -> gpencil_draw_modal()) */ + case PAD0: case PAD1: case PAD2: case PAD3: case PAD4: + case PAD5: case PAD6: case PAD7: case PAD8: case PAD9: + return OPERATOR_PASS_THROUGH; /* Unhandled event */ default: From 69a75b0169c64b14f00de7b7e2da45720cdc4d06 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 2 Dec 2016 02:19:59 +1300 Subject: [PATCH 333/590] GPencil: Include various new operators into the 3D View menus too Quite a few of the operators added for 2.78 were not included in the menus --- release/scripts/startup/bl_ui/space_view3d.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 9de9376312c..5e936076d0e 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -3053,11 +3053,18 @@ class VIEW3D_MT_edit_gpencil(Menu): layout.separator() layout.menu("VIEW3D_MT_object_animation") # NOTE: provides keyingset access... + layout.menu("VIEW3D_MT_edit_gpencil_interpolate") layout.separator() layout.menu("VIEW3D_MT_edit_gpencil_delete") layout.operator("gpencil.duplicate_move", text="Duplicate") + layout.operator("gpencil.stroke_subdivide", text="Subdivide") + + layout.separator() + + layout.operator_menu_enum("gpencil.stroke_join", "type", text="Join...") + layout.operator("gpencil.stroke_flip", text="Flip Direction") layout.separator() @@ -3077,6 +3084,11 @@ class VIEW3D_MT_edit_gpencil(Menu): layout.separator() layout.operator_menu_enum("gpencil.move_to_layer", "layer", text="Move to Layer") + layout.operator("gpencil.stroke_change_color", text="Move to Color") + layout.operator_menu_enum("gpencil.stroke_arrange", "direction", text="Arrange Strokes...") + + layout.separator() + layout.operator_menu_enum("gpencil.convert", "type", text="Convert to Geometry...") @@ -3097,6 +3109,20 @@ class VIEW3D_MT_edit_gpencil_transform(Menu): layout.operator("transform.tosphere", text="To Sphere") layout.operator("transform.transform", text="Shrink Fatten").mode = 'GPENCIL_SHRINKFATTEN' + layout.separator() + + layout.operator("gpencil.reproject") + + +class VIEW3D_MT_edit_gpencil_interpolate(Menu): + bl_label = "Interpolate" + + def draw(self, context): + layout = self.layout + + layout.operator("gpencil.interpolate", text="Interpolate") + layout.operator("gpencil.interpolate_sequence", text="Sequence") + # ********** Panel ********** From 7fe7835d13de669be3b65b4e36000e8883f7117b Mon Sep 17 00:00:00 2001 From: Luca Rood Date: Wed, 23 Nov 2016 17:19:03 -0200 Subject: [PATCH 334/590] Fix (unreported) looptri array not being recalculated in ccgDM and emDM In ccgDM and emDM, looptri array recalculation was being handled directly by `*DM_getLoopTriArray` (`getLoopTriArray` callback), while `*DM_recalcLoopTri` (`recalcLoopTri` callback) was doing nothing. This results in the array not being recalculated when other functions that depend on the array data called the recalc function. This moves all the recalculation code to `*DM_recalcLoopTri` and makes `*DM_getLoopTriArray` call that. This commit also makes a minor change to the `getNumLoopTri` function, so that it returns the correct number without having to recalculate the looptri array. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D2375 --- .../blender/blenkernel/intern/DerivedMesh.c | 4 +- .../blenkernel/intern/editderivedmesh.c | 56 ++++++++--------- .../blender/blenkernel/intern/subsurf_ccg.c | 60 +++++++++---------- 3 files changed, 61 insertions(+), 59 deletions(-) diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index ae18f5289d4..1f937d837b4 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -230,7 +230,9 @@ static MPoly *dm_dupPolyArray(DerivedMesh *dm) static int dm_getNumLoopTri(DerivedMesh *dm) { - return dm->looptris.num; + const int numlooptris = poly_to_tri_count(dm->getNumPolys(dm), dm->getNumLoops(dm)); + BLI_assert(ELEM(dm->looptris.num, 0, numlooptris)); + return numlooptris; } static CustomData *dm_getVertCData(DerivedMesh *dm) diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index 05cf5f6d7bd..e7c0e69b1cb 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -621,10 +621,33 @@ static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm)) /* do nothing */ } -static void emDM_recalcLoopTri(DerivedMesh *UNUSED(dm)) +static void emDM_recalcLoopTri(DerivedMesh *dm) { - /* Nothing to do: emDM tessellation is known, - * allocate and fill in with emDM_getLoopTriArray */ + EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; + BMLoop *(*looptris)[3] = bmdm->em->looptris; + MLoopTri *mlooptri; + const int tottri = bmdm->em->tottri; + int i; + + DM_ensure_looptri_data(dm); + mlooptri = dm->looptris.array; + + BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); + BLI_assert(tottri == dm->looptris.num); + + BM_mesh_elem_index_ensure(bmdm->em->bm, BM_FACE | BM_LOOP); + + for (i = 0; i < tottri; i++) { + BMLoop **ltri = looptris[i]; + MLoopTri *lt = &mlooptri[i]; + + ARRAY_SET_ITEMS( + lt->tri, + BM_elem_index_get(ltri[0]), + BM_elem_index_get(ltri[1]), + BM_elem_index_get(ltri[2])); + lt->poly = BM_elem_index_get(ltri[0]->f); + } } static const MLoopTri *emDM_getLoopTriArray(DerivedMesh *dm) @@ -633,32 +656,9 @@ static const MLoopTri *emDM_getLoopTriArray(DerivedMesh *dm) BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); } else { - EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; - BMLoop *(*looptris)[3] = bmdm->em->looptris; - MLoopTri *mlooptri; - const int tottri = bmdm->em->tottri; - int i; - - DM_ensure_looptri_data(dm); - mlooptri = dm->looptris.array; - - BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); - BLI_assert(tottri == dm->looptris.num); - - BM_mesh_elem_index_ensure(bmdm->em->bm, BM_FACE | BM_LOOP); - - for (i = 0; i < tottri; i++) { - BMLoop **ltri = looptris[i]; - MLoopTri *lt = &mlooptri[i]; - - ARRAY_SET_ITEMS( - lt->tri, - BM_elem_index_get(ltri[0]), - BM_elem_index_get(ltri[1]), - BM_elem_index_get(ltri[2])); - lt->poly = BM_elem_index_get(ltri[0]->f); - } + dm->recalcLoopTri(dm); } + return dm->looptris.array; } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 6d57c5f09e8..c4665c40ec4 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -4474,46 +4474,46 @@ static void ccgDM_recalcTessellation(DerivedMesh *UNUSED(dm)) /* Nothing to do: CCG handles creating its own tessfaces */ } -static void ccgDM_recalcLoopTri(DerivedMesh *UNUSED(dm)) +static void ccgDM_recalcLoopTri(DerivedMesh *dm) { - /* Nothing to do: CCG tessellation is known, - * allocate and fill in with ccgDM_getLoopTriArray */ + BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE); + MLoopTri *mlooptri; + const int tottri = dm->numPolyData * 2; + int i, poly_index; + + DM_ensure_looptri_data(dm); + mlooptri = dm->looptris.array; + + BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); + BLI_assert(tottri == dm->looptris.num); + + for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) { + MLoopTri *lt; + lt = &mlooptri[i]; + /* quad is (0, 3, 2, 1) */ + lt->tri[0] = (poly_index * 4) + 0; + lt->tri[1] = (poly_index * 4) + 2; + lt->tri[2] = (poly_index * 4) + 3; + lt->poly = poly_index; + + lt = &mlooptri[i + 1]; + lt->tri[0] = (poly_index * 4) + 0; + lt->tri[1] = (poly_index * 4) + 1; + lt->tri[2] = (poly_index * 4) + 2; + lt->poly = poly_index; + } + BLI_rw_mutex_unlock(&loops_cache_rwlock); } static const MLoopTri *ccgDM_getLoopTriArray(DerivedMesh *dm) { - BLI_rw_mutex_lock(&loops_cache_rwlock, THREAD_LOCK_WRITE); if (dm->looptris.array) { BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); } else { - MLoopTri *mlooptri; - const int tottri = dm->numPolyData * 2; - int i, poly_index; - - DM_ensure_looptri_data(dm); - mlooptri = dm->looptris.array; - - BLI_assert(poly_to_tri_count(dm->numPolyData, dm->numLoopData) == dm->looptris.num); - BLI_assert(tottri == dm->looptris.num); - - for (i = 0, poly_index = 0; i < tottri; i += 2, poly_index += 1) { - MLoopTri *lt; - lt = &mlooptri[i]; - /* quad is (0, 3, 2, 1) */ - lt->tri[0] = (poly_index * 4) + 0; - lt->tri[1] = (poly_index * 4) + 2; - lt->tri[2] = (poly_index * 4) + 3; - lt->poly = poly_index; - - lt = &mlooptri[i + 1]; - lt->tri[0] = (poly_index * 4) + 0; - lt->tri[1] = (poly_index * 4) + 1; - lt->tri[2] = (poly_index * 4) + 2; - lt->poly = poly_index; - } + dm->recalcLoopTri(dm); } - BLI_rw_mutex_unlock(&loops_cache_rwlock); + return dm->looptris.array; } From 0e1cf858a0f11d0a57ad60429af650b2da632889 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 1 Dec 2016 16:30:17 +0100 Subject: [PATCH 335/590] install_deps.sh: Update official (default) lib versions of py/oiio/osl/osd/ffmpeg. --- build_files/build_environment/install_deps.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 573ea4577e2..44334612a3a 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -289,7 +289,7 @@ NO_BUILD=false NO_CONFIRM=false USE_CXX11=false -PYTHON_VERSION="3.5.1" +PYTHON_VERSION="3.5.2" PYTHON_VERSION_MIN="3.5" PYTHON_FORCE_BUILD=false PYTHON_FORCE_REBUILD=false @@ -322,7 +322,7 @@ OPENEXR_FORCE_REBUILD=false OPENEXR_SKIP=false _with_built_openexr=false -OIIO_VERSION="1.6.9" +OIIO_VERSION="1.7.8" OIIO_VERSION_MIN="1.6.0" OIIO_VERSION_MAX="1.9.0" # UNKNOWN currently # Not supported by current OSL... OIIO_FORCE_BUILD=false @@ -337,14 +337,14 @@ LLVM_FORCE_REBUILD=false LLVM_SKIP=false # OSL needs to be compiled for now! -OSL_VERSION="1.7.3" +OSL_VERSION="1.7.5" OSL_VERSION_MIN=$OSL_VERSION OSL_FORCE_BUILD=false OSL_FORCE_REBUILD=false OSL_SKIP=false # OpenSubdiv needs to be compiled for now -OSD_VERSION="3.0.5" +OSD_VERSION="3.1.0" OSD_VERSION_MIN=$OSD_VERSION OSD_FORCE_BUILD=false OSD_FORCE_REBUILD=false @@ -372,7 +372,7 @@ OPENCOLLADA_FORCE_BUILD=false OPENCOLLADA_FORCE_REBUILD=false OPENCOLLADA_SKIP=false -FFMPEG_VERSION="2.8.4" +FFMPEG_VERSION="3.2.1" FFMPEG_VERSION_MIN="2.8.4" FFMPEG_FORCE_BUILD=false FFMPEG_FORCE_REBUILD=false From a4c655848180a8e88c1b19a1be0a96cff66670f2 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 2 Dec 2016 09:44:41 +0100 Subject: [PATCH 336/590] Fix (unreported) memleak in ImBuf mipmap code in some cases. `IMB_remakemipmap` may 'shrink' the mipmap list without actually freeing anything, so we need to check all possible levels in `imb_freemipmapImBuf` to avoid memory leaks, not only those currently used. --- source/blender/imbuf/intern/allocimbuf.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/source/blender/imbuf/intern/allocimbuf.c b/source/blender/imbuf/intern/allocimbuf.c index ef3743d9c8a..33750478bb4 100644 --- a/source/blender/imbuf/intern/allocimbuf.c +++ b/source/blender/imbuf/intern/allocimbuf.c @@ -89,11 +89,14 @@ void imb_mmap_unlock(void) void imb_freemipmapImBuf(ImBuf *ibuf) { int a; - - for (a = 1; a < ibuf->miptot; a++) { - if (ibuf->mipmap[a - 1]) - IMB_freeImBuf(ibuf->mipmap[a - 1]); - ibuf->mipmap[a - 1] = NULL; + + /* Do not trust ibuf->miptot, in some cases IMB_remakemipmap can leave unfreed unused levels, + * leading to memory leaks... */ + for (a = 0; a < IMB_MIPMAP_LEVELS; a++) { + if (ibuf->mipmap[a] != NULL) { + IMB_freeImBuf(ibuf->mipmap[a]); + ibuf->mipmap[a] = NULL; + } } ibuf->miptot = 0; From 0ac2be7030ee114e43407743c85ca72aade62e7e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 2 Dec 2016 10:15:24 +0100 Subject: [PATCH 337/590] Cycles: Disable AVX2 crash workarounds I can no longer reproduce crash with neither of the files where the crash was originally visible. This is something where other changes (light threshold, sampling) had an effect and made code to work as it is supposed to. Could have been optimizator issue or something like that. Let's see if we hit same issue again. --- intern/cycles/util/util_math.h | 9 +++------ intern/cycles/util/util_transform.h | 5 ++--- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 3f4d3e06c0b..6cb68b53d16 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -596,8 +596,7 @@ ccl_device_inline float len_squared(const float4& a) ccl_device_inline float3 normalize(const float3& a) { - /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ -#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) && 0 +#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) __m128 norm = _mm_sqrt_ps(_mm_dp_ps(a.m128, a.m128, 0x7F)); return _mm_div_ps(a.m128, norm); #else @@ -798,8 +797,7 @@ ccl_device_inline float4 operator-(const float4& a) ccl_device_inline float4 operator*(const float4& a, const float4& b) { - /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ -#if defined(__KERNEL_SSE__) && 0 +#ifdef __KERNEL_SSE__ return _mm_mul_ps(a.m128, b.m128); #else return make_float4(a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w); @@ -847,8 +845,7 @@ ccl_device_inline float4 operator/(const float4& a, const float4& b) ccl_device_inline float4 operator+(const float4& a, const float4& b) { - /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ -#if defined(__KERNEL_SSE__) && 0 +#ifdef __KERNEL_SSE__ return _mm_add_ps(a.m128, b.m128); #else return make_float4(a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w); diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index ea5eb3b25b0..a0695f20488 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -74,7 +74,7 @@ ccl_device_inline float3 transform_perspective(const Transform *t, const float3 ccl_device_inline float3 transform_point(const Transform *t, const float3 a) { /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ -#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) && 0 +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) ssef x, y, z, w, aa; aa = a.m128; @@ -103,8 +103,7 @@ ccl_device_inline float3 transform_point(const Transform *t, const float3 a) ccl_device_inline float3 transform_direction(const Transform *t, const float3 a) { - /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ -#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) && 0 +#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__) ssef x, y, z, w, aa; aa = a.m128; x = _mm_loadu_ps(&t->x.x); From 0c958b9f8e933605497a59faf8838a544b9da740 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 2 Dec 2016 10:45:03 +0100 Subject: [PATCH 338/590] Fix T50062: Mask - Clicking in ActivePoint Parent makes Blender crash. Mask primitive adding code was not initializing correctly id_type of points' parents. --- .../blenloader/intern/versioning_270.c | 19 +++++++++++++++++++ source/blender/editors/mask/mask_add.c | 1 + 2 files changed, 20 insertions(+) diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 25d78b73d59..88c583b827e 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -46,6 +46,7 @@ #include "DNA_screen_types.h" #include "DNA_object_force.h" #include "DNA_object_types.h" +#include "DNA_mask_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_particle_types.h" @@ -60,6 +61,7 @@ #include "BKE_colortools.h" #include "BKE_library.h" #include "BKE_main.h" +#include "BKE_mask.h" #include "BKE_modifier.h" #include "BKE_node.h" #include "BKE_scene.h" @@ -1473,4 +1475,21 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) br->fill_threshold /= sqrt_3; } } + + /* To be added to next subversion bump! */ + { + /* Mask primitive adding code was not initializing correctly id_type of its points' parent. */ + for (Mask *mask = main->mask.first; mask; mask = mask->id.next) { + for (MaskLayer *mlayer = mask->masklayers.first; mlayer; mlayer = mlayer->next) { + for (MaskSpline *mspline = mlayer->splines.first; mspline; mspline = mspline->next) { + int i = 0; + for (MaskSplinePoint *mspoint = mspline->points; i < mspline->tot_point; mspoint++, i++) { + if (mspoint->parent.id_type == 0) { + BKE_mask_parent_init(&mspoint->parent); + } + } + } + } + } + } } diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index e3e8f35e7d8..f01af22cec9 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -779,6 +779,7 @@ static int create_primitive_from_points(bContext *C, wmOperator *op, const float for (i = 0; i < num_points; i++) { MaskSplinePoint *new_point = &new_spline->points[i]; + BKE_mask_parent_init(&new_point->parent); copy_v2_v2(new_point->bezt.vec[1], points[i]); mul_v2_fl(new_point->bezt.vec[1], scale); From acc1f8fbed5dfe78d33fa03783205c8ff65f092f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 2 Dec 2016 10:42:31 +0100 Subject: [PATCH 339/590] Cycles: Add AVX intrinsics helpers They are defined for MSVC but seems to be missing in GCC and CLang-3.8. Maybe some further tweaks to policy when to define those functions is needed, but should be fine for now. --- intern/cycles/util/util_avxf.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/intern/cycles/util/util_avxf.h b/intern/cycles/util/util_avxf.h index 2db2c4dad1a..2451213963a 100644 --- a/intern/cycles/util/util_avxf.h +++ b/intern/cycles/util/util_avxf.h @@ -180,6 +180,14 @@ __forceinline const avxf nmadd(const avxf& a, const avxf& b, const avxf& c) { } #endif +#ifndef _mm256_set_m128 +# define _mm256_set_m128(/* __m128 */ hi, /* __m128 */ lo) \ + _mm256_insertf128_ps(_mm256_castps128_ps256(lo), (hi), 0x1) +#endif + +#define _mm256_loadu2_m128(/* float const* */ hiaddr, /* float const* */ loaddr) \ + _mm256_set_m128(_mm_loadu_ps(hiaddr), _mm_loadu_ps(loaddr)) + CCL_NAMESPACE_END #endif From 31fbf2b74adf6f1b810915715614667aaf2e6f94 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 2 Dec 2016 12:15:24 +0100 Subject: [PATCH 340/590] Cycles: Implement AVX2 path for curve intersection functions Gives little performance improvement on Linux and gives up to 2% speedup on koro.blend on Windows. Inspired by Maxym Dmytrychenko, thanks! --- intern/cycles/kernel/geom/geom_curve.h | 66 +++++++++++++++++-- intern/cycles/kernel/geom/geom_motion_curve.h | 66 ++++++++++++++++++- 2 files changed, 127 insertions(+), 5 deletions(-) diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h index 84aaaab7453..636dbcc71e0 100644 --- a/intern/cycles/kernel/geom/geom_curve.h +++ b/intern/cycles/kernel/geom/geom_curve.h @@ -255,6 +255,17 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte int ka = max(k0 - 1, v00.x); int kb = min(k1 + 1, v00.x + v00.y - 1); +#ifdef __KERNEL_AVX2__ + avxf P_curve_0_1, P_curve_2_3; + if(type & PRIMITIVE_CURVE) { + P_curve_0_1 = _mm256_loadu2_m128(&kg->__curve_keys.data[k0].x, &kg->__curve_keys.data[ka].x); + P_curve_2_3 = _mm256_loadu2_m128(&kg->__curve_keys.data[kb].x, &kg->__curve_keys.data[k1].x); + } + else { + int fobject = (object == OBJECT_NONE) ? kernel_tex_fetch(__prim_object, curveAddr) : object; + motion_cardinal_curve_keys_avx(kg, fobject, prim, time, ka, k0, k1, kb, &P_curve_0_1,&P_curve_2_3); + } +#else /* __KERNEL_AVX2__ */ ssef P_curve[4]; if(type & PRIMITIVE_CURVE) { @@ -267,6 +278,7 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, curveAddr): object; motion_cardinal_curve_keys(kg, fobject, prim, time, ka, k0, k1, kb, (float4*)&P_curve); } +#endif /* __KERNEL_AVX2__ */ ssef rd_sgn = set_sign_bit<0, 1, 1, 1>(shuffle<0>(rd_ss)); ssef mul_zxxy = shuffle<2, 0, 0, 1>(vdir) * rd_sgn; @@ -278,6 +290,33 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte ssef htfm1 = shuffle<1, 0, 1, 3>(load1f_first(extract<0>(d_ss)), vdir0); ssef htfm2 = shuffle<1, 3, 2, 3>(mul_shuf, vdir0); +#ifdef __KERNEL_AVX2__ + const avxf vPP = _mm256_broadcast_ps(&P.m128); + const avxf htfm00 = avxf(htfm0.m128, htfm0.m128); + const avxf htfm11 = avxf(htfm1.m128, htfm1.m128); + const avxf htfm22 = avxf(htfm2.m128, htfm2.m128); + + const avxf p01 = madd(shuffle<0>(P_curve_0_1 - vPP), + htfm00, + madd(shuffle<1>(P_curve_0_1 - vPP), + htfm11, + shuffle<2>(P_curve_0_1 - vPP) * htfm22)); + const avxf p23 = madd(shuffle<0>(P_curve_2_3 - vPP), + htfm00, + madd(shuffle<1>(P_curve_2_3 - vPP), + htfm11, + shuffle<2>(P_curve_2_3 - vPP)*htfm22)); + + const ssef p0 = _mm256_castps256_ps128(p01); + const ssef p1 = _mm256_extractf128_ps(p01, 1); + const ssef p2 = _mm256_castps256_ps128(p23); + const ssef p3 = _mm256_extractf128_ps(p23, 1); + + const ssef P_curve_1 = _mm256_extractf128_ps(P_curve_0_1, 1); + r_st = ((float4 &)P_curve_1).w; + const ssef P_curve_2 = _mm256_castps256_ps128(P_curve_2_3); + r_en = ((float4 &)P_curve_2).w; +#else /* __KERNEL_AVX2__ */ ssef htfm[] = { htfm0, htfm1, htfm2 }; ssef vP = load4f(P); ssef p0 = transform_point_T3(htfm, P_curve[0] - vP); @@ -285,6 +324,10 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte ssef p2 = transform_point_T3(htfm, P_curve[2] - vP); ssef p3 = transform_point_T3(htfm, P_curve[3] - vP); + r_st = ((float4 &)P_curve[1]).w; + r_en = ((float4 &)P_curve[2]).w; +#endif /* __KERNEL_AVX2__ */ + float fc = 0.71f; ssef vfc = ssef(fc); ssef vfcxp3 = vfc * p3; @@ -294,8 +337,6 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte vcurve_coef[2] = madd(ssef(fc * 2.0f), p0, madd(ssef(fc - 3.0f), p1, msub(ssef(3.0f - 2.0f * fc), p2, vfcxp3))); vcurve_coef[3] = msub(ssef(fc - 2.0f), p2 - p1, msub(vfc, p0, vfcxp3)); - r_st = ((float4 &)P_curve[1]).w; - r_en = ((float4 &)P_curve[2]).w; } #else float3 curve_coef[4]; @@ -383,8 +424,9 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte /* begin loop */ while(!(tree >> (depth))) { - float i_st = tree * resol; - float i_en = i_st + (level * resol); + const float i_st = tree * resol; + const float i_en = i_st + (level * resol); + #ifdef __KERNEL_SSE2__ ssef vi_st = ssef(i_st), vi_en = ssef(i_en); ssef vp_st = madd(madd(madd(vcurve_coef[3], vi_st, vcurve_coef[2]), vi_st, vcurve_coef[1]), vi_st, vcurve_coef[0]); @@ -458,13 +500,23 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte if(flags & CURVE_KN_RIBBONS) { float3 tg = (p_en - p_st); +#ifdef __KERNEL_SSE__ + const float3 tg_sq = tg * tg; + float w = tg_sq.x + tg_sq.y; +#else float w = tg.x * tg.x + tg.y * tg.y; +#endif if(w == 0) { tree++; level = tree & -tree; continue; } +#ifdef __KERNEL_SSE__ + const float3 p_sttg = p_st * tg; + w = -(p_sttg.x + p_sttg.y) / w; +#else w = -(p_st.x * tg.x + p_st.y * tg.y) / w; +#endif w = saturate(w); /* compute u on the curve segment */ @@ -496,7 +548,13 @@ ccl_device_forceinline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Inte if(difl != 0.0f) { mw_extension = min(difl * fabsf(bmaxz), extmax); r_ext = mw_extension + r_curr; +#ifdef __KERNEL_SSE__ + const float3 p_curr_sq = p_curr * p_curr; + const float3 dxxx = _mm_sqrt_ss(_mm_hadd_ps(p_curr_sq.m128, p_curr_sq.m128)); + float d = dxxx.x; +#else float d = sqrtf(p_curr.x * p_curr.x + p_curr.y * p_curr.y); +#endif float d0 = d - r_curr; float d1 = d + r_curr; float inv_mw_extension = 1.0f/mw_extension; diff --git a/intern/cycles/kernel/geom/geom_motion_curve.h b/intern/cycles/kernel/geom/geom_motion_curve.h index 6de5aa7ea99..80b33fad68b 100644 --- a/intern/cycles/kernel/geom/geom_motion_curve.h +++ b/intern/cycles/kernel/geom/geom_motion_curve.h @@ -118,7 +118,12 @@ ccl_device_inline void motion_cardinal_curve_keys_for_step(KernelGlobals *kg, in } /* return 2 curve key locations */ -ccl_device_inline void motion_cardinal_curve_keys(KernelGlobals *kg, int object, int prim, float time, int k0, int k1, int k2, int k3, float4 keys[4]) +ccl_device_inline void motion_cardinal_curve_keys(KernelGlobals *kg, + int object, + int prim, + float time, + int k0, int k1, int k2, int k3, + float4 keys[4]) { /* get motion info */ int numsteps, numkeys; @@ -147,6 +152,65 @@ ccl_device_inline void motion_cardinal_curve_keys(KernelGlobals *kg, int object, keys[3] = (1.0f - t)*keys[3] + t*next_keys[3]; } +#ifdef __KERNEL_AVX2__ +/* Similar to above, but returns keys as pair of two AVX registers with each + * holding two float4. + */ +ccl_device_inline void motion_cardinal_curve_keys_avx(KernelGlobals *kg, + int object, + int prim, + float time, + int k0, int k1, + int k2, int k3, + avxf *out_keys_0_1, + avxf *out_keys_2_3) +{ + /* Get motion info. */ + int numsteps, numkeys; + object_motion_info(kg, object, &numsteps, NULL, &numkeys); + + /* Figure out which steps we need to fetch and their interpolation factor. */ + int maxstep = numsteps * 2; + int step = min((int)(time*maxstep), maxstep - 1); + float t = time*maxstep - step; + + /* Find attribute. */ + AttributeElement elem; + int offset = find_attribute_curve_motion(kg, + object, + ATTR_STD_MOTION_VERTEX_POSITION, + &elem); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + + /* Fetch key coordinates. */ + float4 next_keys[4]; + float4 keys[4]; + motion_cardinal_curve_keys_for_step(kg, + offset, + numkeys, + numsteps, + step, + k0, k1, k2, k3, + keys); + motion_cardinal_curve_keys_for_step(kg, + offset, + numkeys, + numsteps, + step + 1, + k0, k1, k2, k3, + next_keys); + + const avxf keys_0_1 = avxf(keys[0].m128, keys[1].m128); + const avxf keys_2_3 = avxf(keys[2].m128, keys[3].m128); + const avxf next_keys_0_1 = avxf(next_keys[0].m128, next_keys[1].m128); + const avxf next_keys_2_3 = avxf(next_keys[2].m128, next_keys[3].m128); + + /* Interpolate between steps. */ + *out_keys_0_1 = (1.0f - t) * keys_0_1 + t*next_keys_0_1; + *out_keys_2_3 = (1.0f - t) * keys_2_3 + t*next_keys_2_3; +} +#endif + #endif CCL_NAMESPACE_END From 35d490b3f13c75e9a62cb30f3842ed38a27f6dbc Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 2 Dec 2016 16:57:00 +0100 Subject: [PATCH 341/590] OCIO: Implement exposure/gamma for fallback implementation Quite handy for debugging. Unfortunately, this doesn't support viewport tweaks yet since those require GLSL for colorspace conversion. Maybe this will be implemented as well one day in the future.. --- intern/opencolorio/fallback_impl.cc | 249 ++++++++++++++++++++++++---- 1 file changed, 214 insertions(+), 35 deletions(-) diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc index d0a129360b0..87629422013 100644 --- a/intern/opencolorio/fallback_impl.cc +++ b/intern/opencolorio/fallback_impl.cc @@ -23,18 +23,26 @@ * ***** END GPL LICENSE BLOCK ***** */ -#include +#include +#include #include "MEM_guardedalloc.h" #include "BLI_math_color.h" +#include "BLI_math_vector.h" #include "ocio_impl.h" +using std::max; + #define CONFIG_DEFAULT ((OCIO_ConstConfigRcPtr*)1) -#define PROCESSOR_LINEAR_TO_SRGB ((OCIO_ConstProcessorRcPtr*)1) -#define PROCESSOR_SRGB_TO_LINEAR ((OCIO_ConstProcessorRcPtr*)2) -#define PROCESSOR_UNKNOWN ((OCIO_ConstProcessorRcPtr*)3) +enum TransformType { + TRANSFORM_LINEAR_TO_SRGB, + TRANSFORM_SRGB_TO_LINEAR, + TRANSFORM_MATRIX, + TRANSFORM_EXPONENT, + TRANSFORM_UNKNOWN, +}; #define COLORSPACE_LINEAR ((OCIO_ConstColorSpaceRcPtr*)1) #define COLORSPACE_SRGB ((OCIO_ConstColorSpaceRcPtr*)2) @@ -49,6 +57,145 @@ typedef struct OCIO_PackedImageDescription { long yStrideBytes; } OCIO_PackedImageDescription; +struct FallbackTransform { + FallbackTransform() + : type(TRANSFORM_UNKNOWN), + linear_transform(NULL), + display_transform(NULL) + { + } + + ~FallbackTransform() + { + delete linear_transform; + delete display_transform; + } + + void applyRGB(float *pixel) + { + if (type == TRANSFORM_LINEAR_TO_SRGB) { + applyLinearRGB(pixel); + linearrgb_to_srgb_v3_v3(pixel, pixel); + applyDisplayRGB(pixel); + } + else if (type == TRANSFORM_SRGB_TO_LINEAR) { + srgb_to_linearrgb_v3_v3(pixel, pixel); + } + else if (type == TRANSFORM_EXPONENT) { + pixel[0] = powf(max(0.0f, pixel[0]), exponent[0]); + pixel[1] = powf(max(0.0f, pixel[1]), exponent[1]); + pixel[2] = powf(max(0.0f, pixel[2]), exponent[2]); + } + else if (type == TRANSFORM_MATRIX) { + float r = pixel[0]; + float g = pixel[1]; + float b = pixel[2]; + pixel[0] = r*matrix[0] + g*matrix[1] + b*matrix[2]; + pixel[1] = r*matrix[4] + g*matrix[5] + b*matrix[6]; + pixel[2] = r*matrix[8] + g*matrix[9] + b*matrix[10]; + pixel[0] += offset[0]; + pixel[1] += offset[1]; + pixel[2] += offset[2]; + } + } + + void applyRGBA(float *pixel) + { + if (type == TRANSFORM_LINEAR_TO_SRGB) { + applyLinearRGBA(pixel); + linearrgb_to_srgb_v4(pixel, pixel); + applyDisplayRGBA(pixel); + } + else if (type == TRANSFORM_SRGB_TO_LINEAR) { + srgb_to_linearrgb_v4(pixel, pixel); + } + else if (type == TRANSFORM_EXPONENT) { + pixel[0] = powf(max(0.0f, pixel[0]), exponent[0]); + pixel[1] = powf(max(0.0f, pixel[1]), exponent[1]); + pixel[2] = powf(max(0.0f, pixel[2]), exponent[2]); + pixel[3] = powf(max(0.0f, pixel[3]), exponent[3]); + } + else if (type == TRANSFORM_MATRIX) { + float r = pixel[0]; + float g = pixel[1]; + float b = pixel[2]; + float a = pixel[3]; + pixel[0] = r*matrix[0] + g*matrix[1] + b*matrix[2] + a*matrix[3]; + pixel[1] = r*matrix[4] + g*matrix[5] + b*matrix[6] + a*matrix[7]; + pixel[2] = r*matrix[8] + g*matrix[9] + b*matrix[10] + a*matrix[11]; + pixel[3] = r*matrix[12] + g*matrix[13] + b*matrix[14] + a*matrix[15]; + pixel[0] += offset[0]; + pixel[1] += offset[1]; + pixel[2] += offset[2]; + pixel[3] += offset[3]; + } + } + + void applyLinearRGB(float *pixel) + { + if (linear_transform != NULL) { + linear_transform->applyRGB(pixel); + } + } + + void applyLinearRGBA(float *pixel) + { + if (linear_transform != NULL) { + linear_transform->applyRGBA(pixel); + } + } + + void applyDisplayRGB(float *pixel) + { + if (display_transform != NULL) { + display_transform->applyRGB(pixel); + } + } + + void applyDisplayRGBA(float *pixel) + { + if (display_transform != NULL) { + display_transform->applyRGBA(pixel); + } + } + + TransformType type; + FallbackTransform *linear_transform; + FallbackTransform *display_transform; + /* Exponent transform. */ + float exponent[4]; + /* Matrix transform. */ + float matrix[16]; + float offset[4]; + + MEM_CXX_CLASS_ALLOC_FUNCS("FallbackProcessor"); +}; + +struct FallbackProcessor { + FallbackProcessor() + : transform(NULL) + { + } + + ~FallbackProcessor() { + delete transform; + } + + void applyRGB(float *pixel) + { + transform->applyRGB(pixel); + } + + void applyRGBA(float *pixel) + { + transform->applyRGBA(pixel); + } + + FallbackTransform *transform; + + MEM_CXX_CLASS_ALLOC_FUNCS("FallbackProcessor"); +}; + OCIO_ConstConfigRcPtr *FallbackImpl::getCurrentConfig(void) { return CONFIG_DEFAULT; @@ -233,19 +380,27 @@ OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessorWithNames( { OCIO_ConstColorSpaceRcPtr *cs_src = configGetColorSpace(config, srcName); OCIO_ConstColorSpaceRcPtr *cs_dst = configGetColorSpace(config, dstName); + FallbackTransform *transform = new FallbackTransform(); if (cs_src == COLORSPACE_LINEAR && cs_dst == COLORSPACE_SRGB) { - return PROCESSOR_LINEAR_TO_SRGB; + transform->type = TRANSFORM_LINEAR_TO_SRGB; } else if (cs_src == COLORSPACE_SRGB && cs_dst == COLORSPACE_LINEAR) { - return PROCESSOR_SRGB_TO_LINEAR; + transform->type = TRANSFORM_SRGB_TO_LINEAR; } - return 0; + else { + transform->type = TRANSFORM_UNKNOWN; + } + FallbackProcessor *processor = new FallbackProcessor(); + processor->transform = transform; + return (OCIO_ConstProcessorRcPtr *)processor; } OCIO_ConstProcessorRcPtr *FallbackImpl::configGetProcessor(OCIO_ConstConfigRcPtr * /*config*/, - OCIO_ConstTransformRcPtr *tfm) + OCIO_ConstTransformRcPtr *transform) { - return (OCIO_ConstProcessorRcPtr*)tfm; + FallbackProcessor *processor = new FallbackProcessor(); + processor->transform = (FallbackTransform *)transform; + return (OCIO_ConstProcessorRcPtr *)processor; } void FallbackImpl::processorApply(OCIO_ConstProcessorRcPtr *processor, @@ -297,21 +452,13 @@ void FallbackImpl::processorApply_predivide(OCIO_ConstProcessorRcPtr *processor, void FallbackImpl::processorApplyRGB(OCIO_ConstProcessorRcPtr *processor, float *pixel) { - if (processor == PROCESSOR_LINEAR_TO_SRGB) { - linearrgb_to_srgb_v3_v3(pixel, pixel); - } - else if (processor == PROCESSOR_SRGB_TO_LINEAR) { - srgb_to_linearrgb_v3_v3(pixel, pixel); - } + ((FallbackProcessor *)processor)->applyRGB(pixel); } void FallbackImpl::processorApplyRGBA(OCIO_ConstProcessorRcPtr *processor, float *pixel) { - if (processor == PROCESSOR_LINEAR_TO_SRGB) - linearrgb_to_srgb_v4(pixel, pixel); - else if (processor == PROCESSOR_SRGB_TO_LINEAR) - srgb_to_linearrgb_v4(pixel, pixel); + ((FallbackProcessor *)processor)->applyRGBA(pixel); } void FallbackImpl::processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *processor, @@ -338,8 +485,9 @@ void FallbackImpl::processorApplyRGBA_predivide(OCIO_ConstProcessorRcPtr *proces } } -void FallbackImpl::processorRelease(OCIO_ConstProcessorRcPtr * /*p*/) +void FallbackImpl::processorRelease(OCIO_ConstProcessorRcPtr *processor) { + delete (FallbackProcessor*)(processor); } const char *FallbackImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs) @@ -365,7 +513,9 @@ const char *FallbackImpl::colorSpaceGetFamily(OCIO_ConstColorSpaceRcPtr * /*cs*/ OCIO_DisplayTransformRcPtr *FallbackImpl::createDisplayTransform(void) { - return (OCIO_DisplayTransformRcPtr*)PROCESSOR_LINEAR_TO_SRGB; + FallbackTransform *transform = new FallbackTransform(); + transform->type = TRANSFORM_LINEAR_TO_SRGB; + return (OCIO_DisplayTransformRcPtr*)transform; } void FallbackImpl::displayTransformSetInputColorSpaceName(OCIO_DisplayTransformRcPtr * /*dt*/, @@ -383,14 +533,18 @@ void FallbackImpl::displayTransformSetView(OCIO_DisplayTransformRcPtr * /*dt*/, { } -void FallbackImpl::displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr * /*dt*/, - OCIO_ConstTransformRcPtr * /*et*/) +void FallbackImpl::displayTransformSetDisplayCC(OCIO_DisplayTransformRcPtr *dt, + OCIO_ConstTransformRcPtr *et) { + FallbackTransform *transform = (FallbackTransform *)dt; + transform->display_transform = (FallbackTransform *)et; } -void FallbackImpl::displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr * /*dt*/, - OCIO_ConstTransformRcPtr * /*et*/) +void FallbackImpl::displayTransformSetLinearCC(OCIO_DisplayTransformRcPtr *dt, + OCIO_ConstTransformRcPtr *et) { + FallbackTransform *transform = (FallbackTransform *)dt; + transform->linear_transform = (FallbackTransform *)et; } void FallbackImpl::displayTransformSetLooksOverride(OCIO_DisplayTransformRcPtr * /*dt*/, @@ -432,12 +586,16 @@ void FallbackImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc* id) OCIO_ExponentTransformRcPtr *FallbackImpl::createExponentTransform(void) { - return (OCIO_ExponentTransformRcPtr*)PROCESSOR_UNKNOWN; + FallbackTransform *transform = new FallbackTransform(); + transform->type = TRANSFORM_EXPONENT; + return (OCIO_ExponentTransformRcPtr *)transform; } -void FallbackImpl::exponentTransformSetValue(OCIO_ExponentTransformRcPtr * /*et*/, - const float * /*exponent*/) +void FallbackImpl::exponentTransformSetValue(OCIO_ExponentTransformRcPtr *et, + const float *exponent) { + FallbackTransform *transform = (FallbackTransform *)et; + copy_v4_v4(transform->exponent, exponent); } void FallbackImpl::exponentTransformRelease(OCIO_ExponentTransformRcPtr * /*et*/) @@ -446,23 +604,44 @@ void FallbackImpl::exponentTransformRelease(OCIO_ExponentTransformRcPtr * /*et*/ OCIO_MatrixTransformRcPtr *FallbackImpl::createMatrixTransform(void) { - return (OCIO_MatrixTransformRcPtr*)PROCESSOR_UNKNOWN; + FallbackTransform *transform = new FallbackTransform(); + transform->type = TRANSFORM_MATRIX; + return (OCIO_MatrixTransformRcPtr *)transform; } -void FallbackImpl::matrixTransformSetValue(OCIO_MatrixTransformRcPtr * /*mt*/, - const float * /*m44*/, - const float * /*offset4*/) +void FallbackImpl::matrixTransformSetValue(OCIO_MatrixTransformRcPtr *mt, + const float *m44, + const float *offset4) { + FallbackTransform *transform = (FallbackTransform *)mt; + copy_m4_m4((float (*)[4])transform->matrix, (float (*)[4])m44); + copy_v4_v4(transform->offset, offset4); } void FallbackImpl::matrixTransformRelease(OCIO_MatrixTransformRcPtr * /*mt*/) { } -void FallbackImpl::matrixTransformScale(float * /*m44*/, - float * /*offset44*/, - const float * /*scale4*/) +void FallbackImpl::matrixTransformScale(float *m44, + float *offset4, + const float *scale4) { + if (scale4 == NULL) { + return; + } + if (m44 != NULL) { + memset(m44, 0, 16*sizeof(float)); + m44[0] = scale4[0]; + m44[5] = scale4[1]; + m44[10] = scale4[2]; + m44[15] = scale4[3]; + } + if (offset4 != NULL) { + offset4[0] = 0.0f; + offset4[1] = 0.0f; + offset4[2] = 0.0f; + offset4[3] = 0.0f; + } } bool FallbackImpl::supportGLSLDraw(void) From a2ebc5268f2b98ee7335e0054c177c849a45cfba Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sat, 26 Nov 2016 04:22:34 +0100 Subject: [PATCH 342/590] Cycles: Refactor Progress system to provide better estimates The Progress system in Cycles had two limitations so far: - It just counted tiles, but ignored their size. For example, when rendering a 600x500 image with 512x512 tiles, the right 88x500 tile would count for 50% of the progress, although it only covers 15% of the image. - Scene update time was incorrectly counted as rendering time - therefore, the remaining time started very long and gradually decreased. This patch fixes both problems: First of all, the Progress now has a function to ignore time spans, and that is used to ignore scene update time. The larger change is the tile size: Instead of counting samples per tile, so that the final value is num_samples*num_tiles, the code now counts every sample for every pixel, so that the final value is num_samples*num_pixels. Along with that, some unused variables were removed from the Progress and Session classes. Reviewers: brecht, sergey, #cycles Subscribers: brecht, candreacchio, sergey Differential Revision: https://developer.blender.org/D2214 --- intern/cycles/app/cycles_standalone.cpp | 18 +-- intern/cycles/blender/blender_session.cpp | 31 +---- intern/cycles/device/device.h | 1 + intern/cycles/device/device_cpu.cpp | 7 +- intern/cycles/device/device_cuda.cpp | 8 +- intern/cycles/device/device_multi.cpp | 8 ++ intern/cycles/device/device_network.cpp | 5 + intern/cycles/device/device_task.cpp | 12 +- intern/cycles/device/device_task.h | 4 +- intern/cycles/device/opencl/opencl_mega.cpp | 6 +- intern/cycles/device/opencl/opencl_split.cpp | 4 + intern/cycles/render/bake.cpp | 20 ++- intern/cycles/render/bake.h | 3 +- intern/cycles/render/session.cpp | 110 +++++----------- intern/cycles/render/session.h | 9 +- intern/cycles/render/tile.cpp | 37 ++++-- intern/cycles/render/tile.h | 6 +- intern/cycles/util/util_progress.h | 129 +++++++++++-------- intern/cycles/util/util_time.h | 8 +- 19 files changed, 219 insertions(+), 207 deletions(-) diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp index b21e8630cdb..9816d614a7c 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -72,20 +72,17 @@ static void session_print(const string& str) static void session_print_status() { - int sample, tile; - double total_time, sample_time, render_time; string status, substatus; /* get status */ - sample = options.session->progress.get_sample(); - options.session->progress.get_tile(tile, total_time, sample_time, render_time); + float progress = options.session->progress.get_progress(); options.session->progress.get_status(status, substatus); if(substatus != "") status += ": " + substatus; /* print status */ - status = string_printf("Sample %d %s", sample, status.c_str()); + status = string_printf("Progress %05.2f %s", (double) progress*100, status.c_str()); session_print(status); } @@ -167,13 +164,12 @@ static void display_info(Progress& progress) latency = (elapsed - last); last = elapsed; - int sample, tile; - double total_time, sample_time, render_time; + double total_time, sample_time; string status, substatus; - sample = progress.get_sample(); - progress.get_tile(tile, total_time, sample_time, render_time); + progress.get_time(total_time, sample_time); progress.get_status(status, substatus); + float progress_val = progress.get_progress(); if(substatus != "") status += ": " + substatus; @@ -184,10 +180,10 @@ static void display_info(Progress& progress) "%s" " Time: %.2f" " Latency: %.4f" - " Sample: %d" + " Progress: %05.2f" " Average: %.4f" " Interactive: %s", - status.c_str(), total_time, latency, sample, sample_time, interactive.c_str()); + status.c_str(), total_time, latency, (double) progress_val*100, sample_time, interactive.c_str()); view_display_info(str.c_str()); diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index e16cea0ebaf..71c1eefe65f 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -930,38 +930,13 @@ void BlenderSession::get_status(string& status, string& substatus) void BlenderSession::get_progress(float& progress, double& total_time, double& render_time) { - double tile_time; - int tile, sample, samples_per_tile; - int tile_total = session->tile_manager.state.num_tiles; - int samples = session->tile_manager.state.sample + 1; - int total_samples = session->tile_manager.get_num_effective_samples(); - - session->progress.get_tile(tile, total_time, render_time, tile_time); - - sample = session->progress.get_sample(); - samples_per_tile = session->tile_manager.get_num_effective_samples(); - - if(background && samples_per_tile && tile_total) - progress = ((float)sample / (float)(tile_total * samples_per_tile)); - else if(!background && samples > 0 && total_samples != INT_MAX) - progress = ((float)samples) / total_samples; - else - progress = 0.0; + session->progress.get_time(total_time, render_time); + progress = session->progress.get_progress(); } void BlenderSession::update_bake_progress() { - float progress; - int sample, samples_per_task, parts_total; - - sample = session->progress.get_sample(); - samples_per_task = scene->bake_manager->num_samples; - parts_total = scene->bake_manager->num_parts; - - if(samples_per_task) - progress = ((float)sample / (float)(parts_total * samples_per_task)); - else - progress = 0.0; + float progress = session->progress.get_progress(); if(progress != last_progress) { b_engine.update_progress(progress); diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index b9bdffa2618..988ad10607d 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -220,6 +220,7 @@ public: DeviceInfo info; virtual const string& error_message() { return error_msg; } bool have_error() { return !error_message().empty(); } + virtual bool show_samples() const { return false; } /* statistics */ Stats &stats; diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index aed86d8d853..c8e001ec2fd 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -112,6 +112,11 @@ public: task_pool.stop(); } + virtual bool show_samples() const + { + return (TaskScheduler::num_threads() == 1); + } + void mem_alloc(device_memory& mem, MemoryType /*type*/) { mem.device_pointer = mem.data_pointer; @@ -275,7 +280,7 @@ public: tile.sample = sample + 1; - task.update_progress(&tile); + task.update_progress(&tile, tile.w*tile.h); } task.release_tile(tile); diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index fbb97f78e70..233f94be1bf 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -115,6 +115,12 @@ public: return path_exists(cubins_path); } + virtual bool show_samples() const + { + /* The CUDADevice only processes one tile at a time, so showing samples is fine. */ + return true; + } + /*#ifdef NDEBUG #define cuda_abort() #else @@ -1267,7 +1273,7 @@ public: tile.sample = sample + 1; - task->update_progress(&tile); + task->update_progress(&tile, tile.w*tile.h); } task->release_tile(tile); diff --git a/intern/cycles/device/device_multi.cpp b/intern/cycles/device/device_multi.cpp index 48fd159d508..31b800640d3 100644 --- a/intern/cycles/device/device_multi.cpp +++ b/intern/cycles/device/device_multi.cpp @@ -89,6 +89,14 @@ public: return error_msg; } + virtual bool show_samples() const + { + if(devices.size() > 1) { + return false; + } + return devices.front().device->show_samples(); + } + bool load_kernels(const DeviceRequestedFeatures& requested_features) { foreach(SubDevice& sub, devices) diff --git a/intern/cycles/device/device_network.cpp b/intern/cycles/device/device_network.cpp index 3eb5ad2d2db..53eef6cf199 100644 --- a/intern/cycles/device/device_network.cpp +++ b/intern/cycles/device/device_network.cpp @@ -51,6 +51,11 @@ public: thread_mutex rpc_lock; + virtual bool show_samples() const + { + return false; + } + NetworkDevice(DeviceInfo& info, Stats &stats, const char *address) : Device(info, stats, true), socket(io_service) { diff --git a/intern/cycles/device/device_task.cpp b/intern/cycles/device/device_task.cpp index 1f1128a28f8..48d18035c13 100644 --- a/intern/cycles/device/device_task.cpp +++ b/intern/cycles/device/device_task.cpp @@ -19,6 +19,8 @@ #include "device_task.h" +#include "buffers.h" + #include "util_algorithm.h" #include "util_time.h" @@ -99,14 +101,18 @@ void DeviceTask::split(list& tasks, int num, int max_size) } } -void DeviceTask::update_progress(RenderTile *rtile) +void DeviceTask::update_progress(RenderTile *rtile, int pixel_samples) { if((type != PATH_TRACE) && (type != SHADER)) return; - if(update_progress_sample) - update_progress_sample(); + if(update_progress_sample) { + if(pixel_samples == -1) { + pixel_samples = shader_w; + } + update_progress_sample(pixel_samples, rtile? rtile->sample : 0); + } if(update_tile_sample) { double current_time = time_dt(); diff --git a/intern/cycles/device/device_task.h b/intern/cycles/device/device_task.h index 8423e83bdfd..8bd54c3d2b0 100644 --- a/intern/cycles/device/device_task.h +++ b/intern/cycles/device/device_task.h @@ -56,10 +56,10 @@ public: int get_subtask_count(int num, int max_size = 0); void split(list& tasks, int num, int max_size = 0); - void update_progress(RenderTile *rtile); + void update_progress(RenderTile *rtile, int pixel_samples = -1); function acquire_tile; - function update_progress_sample; + function update_progress_sample; function update_tile_sample; function release_tile; function get_cancel; diff --git a/intern/cycles/device/opencl/opencl_mega.cpp b/intern/cycles/device/opencl/opencl_mega.cpp index 369c086df57..6ea7619e022 100644 --- a/intern/cycles/device/opencl/opencl_mega.cpp +++ b/intern/cycles/device/opencl/opencl_mega.cpp @@ -39,6 +39,10 @@ public: { } + virtual bool show_samples() const { + return true; + } + virtual void load_kernels(const DeviceRequestedFeatures& /*requested_features*/, vector &programs) { @@ -120,7 +124,7 @@ public: tile.sample = sample + 1; - task->update_progress(&tile); + task->update_progress(&tile, tile.w*tile.h); } /* Complete kernel execution before release tile */ diff --git a/intern/cycles/device/opencl/opencl_split.cpp b/intern/cycles/device/opencl/opencl_split.cpp index 239e73a40fd..3c3c2150128 100644 --- a/intern/cycles/device/opencl/opencl_split.cpp +++ b/intern/cycles/device/opencl/opencl_split.cpp @@ -247,6 +247,10 @@ public: } } + virtual bool show_samples() const { + return false; + } + /* Split kernel utility functions. */ size_t get_tex_size(const char *tex_name) { diff --git a/intern/cycles/render/bake.cpp b/intern/cycles/render/bake.cpp index 13310a61761..d9a297002c6 100644 --- a/intern/cycles/render/bake.cpp +++ b/intern/cycles/render/bake.cpp @@ -135,20 +135,16 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre { size_t num_pixels = bake_data->size(); - progress.reset_sample(); - this->num_parts = 0; + int num_samples = is_aa_pass(shader_type)? scene->integrator->aa_samples : 1; - /* calculate the total parts for the progress bar */ + /* calculate the total pixel samples for the progress bar */ + total_pixel_samples = 0; for(size_t shader_offset = 0; shader_offset < num_pixels; shader_offset += m_shader_limit) { size_t shader_size = (size_t)fminf(num_pixels - shader_offset, m_shader_limit); - - DeviceTask task(DeviceTask::SHADER); - task.shader_w = shader_size; - - this->num_parts += device->get_split_task_count(task); + total_pixel_samples += shader_size * num_samples; } - - this->num_samples = is_aa_pass(shader_type)? scene->integrator->aa_samples : 1; + progress.reset_sample(); + progress.set_total_pixel_samples(total_pixel_samples); for(size_t shader_offset = 0; shader_offset < num_pixels; shader_offset += m_shader_limit) { size_t shader_size = (size_t)fminf(num_pixels - shader_offset, m_shader_limit); @@ -187,9 +183,9 @@ bool BakeManager::bake(Device *device, DeviceScene *dscene, Scene *scene, Progre task.shader_x = 0; task.offset = shader_offset; task.shader_w = d_output.size(); - task.num_samples = this->num_samples; + task.num_samples = num_samples; task.get_cancel = function_bind(&Progress::get_cancel, &progress); - task.update_progress_sample = function_bind(&Progress::increment_sample_update, &progress); + task.update_progress_sample = function_bind(&Progress::add_samples_update, &progress, _1, _2); device->task_add(task); device->task_wait(); diff --git a/intern/cycles/render/bake.h b/intern/cycles/render/bake.h index 8377e387197..25f5eb3c897 100644 --- a/intern/cycles/render/bake.h +++ b/intern/cycles/render/bake.h @@ -73,8 +73,7 @@ public: bool need_update; - int num_samples; - int num_parts; + int total_pixel_samples; private: BakeData *m_bake_data; diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 9d8c9fed7af..8e902243211 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -67,10 +67,7 @@ Session::Session(const SessionParams& params_) session_thread = NULL; scene = NULL; - start_time = 0.0; reset_time = 0.0; - preview_time = 0.0; - paused_time = 0.0; last_update_time = 0.0; delayed_reset.do_reset = false; @@ -201,12 +198,10 @@ void Session::run_gpu() { bool tiles_written = false; - start_time = time_dt(); reset_time = time_dt(); - paused_time = 0.0; last_update_time = time_dt(); - progress.set_render_start_time(start_time + paused_time); + progress.set_render_start_time(); while(!progress.get_cancel()) { /* advance to next tile */ @@ -233,13 +228,9 @@ void Session::run_gpu() update_status_time(pause, no_tiles); while(1) { - double pause_start = time_dt(); + scoped_timer pause_timer; pause_cond.wait(pause_lock); - paused_time += time_dt() - pause_start; - - if(!params.background) - progress.set_start_time(start_time + paused_time); - progress.set_render_start_time(start_time + paused_time); + progress.add_skip_time(pause_timer, params.background); update_status_time(pause, no_tiles); progress.set_update(); @@ -255,7 +246,9 @@ void Session::run_gpu() if(!no_tiles) { /* update scene */ + scoped_timer update_timer; update_scene(); + progress.add_skip_time(update_timer, params.background); if(!device->error_message().empty()) progress.set_error(device->error_message()); @@ -523,13 +516,9 @@ void Session::run_cpu() update_status_time(pause, no_tiles); while(1) { - double pause_start = time_dt(); + scoped_timer pause_timer; pause_cond.wait(pause_lock); - paused_time += time_dt() - pause_start; - - if(!params.background) - progress.set_start_time(start_time + paused_time); - progress.set_render_start_time(start_time + paused_time); + progress.add_skip_time(pause_timer, params.background); update_status_time(pause, no_tiles); progress.set_update(); @@ -550,7 +539,9 @@ void Session::run_cpu() thread_scoped_lock buffers_lock(buffers_mutex); /* update scene */ + scoped_timer update_timer; update_scene(); + progress.add_skip_time(update_timer, params.background); if(!device->error_message().empty()) progress.set_error(device->error_message()); @@ -718,14 +709,14 @@ void Session::reset_(BufferParams& buffer_params, int samples) } tile_manager.reset(buffer_params, samples); + progress.reset_sample(); - start_time = time_dt(); - preview_time = 0.0; - paused_time = 0.0; + bool show_progress = params.background || tile_manager.get_num_effective_samples() != INT_MAX; + progress.set_total_pixel_samples(show_progress? tile_manager.state.total_pixel_samples : 0); if(!params.background) - progress.set_start_time(start_time); - progress.set_render_start_time(start_time); + progress.set_start_time(); + progress.set_render_start_time(); } void Session::reset(BufferParams& buffer_params, int samples) @@ -827,61 +818,40 @@ void Session::update_scene() void Session::update_status_time(bool show_pause, bool show_done) { - int sample = tile_manager.state.sample; - int resolution = tile_manager.state.resolution_divider; - int num_tiles = tile_manager.state.num_tiles; + int progressive_sample = tile_manager.state.sample; + int num_samples = tile_manager.get_num_effective_samples(); + int tile = tile_manager.state.num_rendered_tiles; + int num_tiles = tile_manager.state.num_tiles; /* update status */ string status, substatus; if(!params.progressive) { - const int progress_sample = progress.get_sample(), - num_samples = tile_manager.get_num_effective_samples(); - const bool is_gpu = params.device.type == DEVICE_CUDA || params.device.type == DEVICE_OPENCL; - const bool is_multidevice = params.device.multi_devices.size() > 1; const bool is_cpu = params.device.type == DEVICE_CPU; - const bool is_last_tile = (num_samples * num_tiles - progress_sample) < num_samples; + const bool is_last_tile = (progress.get_finished_tiles() + 1) == num_tiles; substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles); - if((is_gpu && !is_multidevice && !device->info.use_split_kernel) || - (is_cpu && (num_tiles == 1 || is_last_tile))) + if(device->show_samples() || (is_cpu && is_last_tile)) { - /* When using split-kernel (OpenCL) each thread in a tile will be working on a different - * sample. Can't display sample number when device uses split-kernel + /* Some devices automatically support showing the sample number: + * - CUDADevice + * - OpenCLDevice when using the megakernel (the split kernel renders multiple samples at the same time, so the current sample isn't really defined) + * - CPUDevice when using one thread + * For these devices, the current sample is always shown. + * + * The other option is when the last tile is currently being rendered by the CPU. */ - - /* when rendering on GPU multithreading happens within single tile, as in - * tiles are handling sequentially and in this case we could display - * currently rendering sample number - * this helps a lot from feedback point of view. - * also display the info on CPU, when using 1 tile only - */ - - int status_sample = progress_sample; - if(tile > 1) { - /* sample counter is global for all tiles, subtract samples - * from already finished tiles to get sample counter for - * current tile only - */ - if(is_cpu && is_last_tile && num_tiles > 1) { - status_sample = num_samples - (num_samples * num_tiles - progress_sample); - } - else { - status_sample -= (tile - 1) * num_samples; - } - } - - substatus += string_printf(", Sample %d/%d", status_sample, num_samples); + substatus += string_printf(", Sample %d/%d", progress.get_current_sample(), num_samples); } } else if(tile_manager.num_samples == INT_MAX) - substatus = string_printf("Path Tracing Sample %d", sample+1); + substatus = string_printf("Path Tracing Sample %d", progressive_sample+1); else substatus = string_printf("Path Tracing Sample %d/%d", - sample+1, - tile_manager.get_num_effective_samples()); + progressive_sample+1, + num_samples); if(show_pause) { status = "Paused"; @@ -895,22 +865,6 @@ void Session::update_status_time(bool show_pause, bool show_done) } progress.set_status(status, substatus); - - /* update timing */ - if(preview_time == 0.0 && resolution == 1) - preview_time = time_dt(); - - double tile_time = (tile == 0 || sample == 0)? 0.0: (time_dt() - preview_time - paused_time) / sample; - - /* negative can happen when we pause a bit before rendering, can discard that */ - if(preview_time < 0.0) preview_time = 0.0; - - progress.set_tile(tile, tile_time); -} - -void Session::update_progress_sample() -{ - progress.increment_sample(); } void Session::path_trace() @@ -922,7 +876,7 @@ void Session::path_trace() task.release_tile = function_bind(&Session::release_tile, this, _1); task.get_cancel = function_bind(&Progress::get_cancel, &this->progress); task.update_tile_sample = function_bind(&Session::update_tile_sample, this, _1); - task.update_progress_sample = function_bind(&Session::update_progress_sample, this); + task.update_progress_sample = function_bind(&Progress::add_samples, &this->progress, _1, _2); task.need_finish_queue = params.progressive_refine; task.integrator_branched = scene->integrator->method == Integrator::BRANCHED_PATH; task.requested_tile_size = params.tile_size; diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 1db4692e171..c7ff1446171 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -145,6 +145,10 @@ public: void device_free(); + /* Returns the rendering progress or 0 if no progress can be determined + * (for example, when rendering with unlimited samples). */ + float get_progress(); + protected: struct DelayedReset { thread_mutex mutex; @@ -173,8 +177,6 @@ protected: void update_tile_sample(RenderTile& tile); void release_tile(RenderTile& tile); - void update_progress_sample(); - bool device_use_gl; thread *session_thread; @@ -194,10 +196,7 @@ protected: bool kernels_loaded; - double start_time; double reset_time; - double preview_time; - double paused_time; /* progressive refine */ double last_update_time; diff --git a/intern/cycles/render/tile.cpp b/intern/cycles/render/tile.cpp index 3a6dfea11a7..e59d0c843a3 100644 --- a/intern/cycles/render/tile.cpp +++ b/intern/cycles/render/tile.cpp @@ -108,36 +108,57 @@ TileManager::~TileManager() { } -void TileManager::reset(BufferParams& params_, int num_samples_) +static int get_divider(int w, int h, int start_resolution) { - params = params_; - int divider = 1; - int w = params.width, h = params.height; - if(start_resolution != INT_MAX) { while(w*h > start_resolution*start_resolution) { w = max(1, w/2); h = max(1, h/2); - divider *= 2; + divider <<= 1; } } + return divider; +} - num_samples = num_samples_; +void TileManager::reset(BufferParams& params_, int num_samples_) +{ + params = params_; + + set_samples(num_samples_); state.buffer = BufferParams(); state.sample = range_start_sample - 1; state.num_tiles = 0; state.num_rendered_tiles = 0; state.num_samples = 0; - state.resolution_divider = divider; + state.resolution_divider = get_divider(params.width, params.height, start_resolution); state.tiles.clear(); } void TileManager::set_samples(int num_samples_) { num_samples = num_samples_; + + /* No real progress indication is possible when using unlimited samples. */ + if(num_samples == INT_MAX) { + state.total_pixel_samples = 0; + } + else { + uint64_t pixel_samples = 0; + /* While rendering in the viewport, the initial preview resolution is increased to the native resolution + * before the actual rendering begins. Therefore, additional pixel samples will be rendered. */ + int divider = get_divider(params.width, params.height, start_resolution) / 2; + while(divider > 1) { + int image_w = max(1, params.width/divider); + int image_h = max(1, params.height/divider); + pixel_samples += image_w * image_h; + divider >>= 1; + } + + state.total_pixel_samples = pixel_samples + get_num_effective_samples() * params.width*params.height; + } } /* If sliced is false, splits image into tiles and assigns equal amount of tiles to every render device. diff --git a/intern/cycles/render/tile.h b/intern/cycles/render/tile.h index af1b1ed8b0f..5d92ebac355 100644 --- a/intern/cycles/render/tile.h +++ b/intern/cycles/render/tile.h @@ -64,6 +64,10 @@ public: int resolution_divider; int num_tiles; int num_rendered_tiles; + + /* Total samples over all pixels: Generally num_samples*num_pixels, + * but can be higher due to the initial resolution division for previews. */ + uint64_t total_pixel_samples; /* This vector contains a list of tiles for every logical device in the session. * In each list, the tiles are sorted according to the tile order setting. */ vector > tiles; @@ -91,7 +95,7 @@ public: /* Number to samples in the rendering range. */ int range_num_samples; - /* get number of actual samples to render. */ + /* Get number of actual samples to render. */ int get_num_effective_samples(); protected: diff --git a/intern/cycles/util/util_progress.h b/intern/cycles/util/util_progress.h index 4ae1d61dd17..14215056840 100644 --- a/intern/cycles/util/util_progress.h +++ b/intern/cycles/util/util_progress.h @@ -34,12 +34,12 @@ class Progress { public: Progress() { - tile = 0; - sample = 0; + pixel_samples = 0; + total_pixel_samples = 0; + current_tile_sample = 0; + finished_tiles = 0; start_time = time_dt(); - total_time = 0.0; - render_time = 0.0; - tile_time = 0.0; + render_start_time = time_dt(); status = "Initializing"; substatus = ""; sync_status = ""; @@ -62,22 +62,22 @@ public: thread_scoped_lock lock(progress.progress_mutex); progress.get_status(status, substatus); - progress.get_tile(tile, total_time, render_time, tile_time); - sample = progress.get_sample(); + pixel_samples = progress.pixel_samples; + total_pixel_samples = progress.total_pixel_samples; + current_tile_sample = progress.get_current_sample(); return *this; } void reset() { - tile = 0; - sample = 0; + pixel_samples = 0; + total_pixel_samples = 0; + current_tile_sample = 0; + finished_tiles = 0; start_time = time_dt(); render_start_time = time_dt(); - total_time = 0.0; - render_time = 0.0; - tile_time = 0.0; status = "Initializing"; substatus = ""; sync_status = ""; @@ -139,69 +139,93 @@ public: /* tile and timing information */ - void set_start_time(double start_time_) + void set_start_time() { thread_scoped_lock lock(progress_mutex); - start_time = start_time_; + start_time = time_dt(); } - void set_render_start_time(double render_start_time_) + void set_render_start_time() { thread_scoped_lock lock(progress_mutex); - render_start_time = render_start_time_; + render_start_time = time_dt(); } - void set_tile(int tile_, double tile_time_) + void add_skip_time(const scoped_timer &start_timer, bool only_render) { - thread_scoped_lock lock(progress_mutex); + double skip_time = time_dt() - start_timer.get_start(); - tile = tile_; - total_time = time_dt() - start_time; - render_time = time_dt() - render_start_time; - tile_time = tile_time_; - } - - void get_tile(int& tile_, double& total_time_, double& render_time_, double& tile_time_) - { - thread_scoped_lock lock(progress_mutex); - - tile_ = tile; - total_time_ = (total_time > 0.0)? total_time: 0.0; - render_time_ = (render_time > 0.0)? render_time: 0.0; - tile_time_ = tile_time; + render_start_time += skip_time; + if(!only_render) { + start_time += skip_time; + } } void get_time(double& total_time_, double& render_time_) { - total_time_ = (total_time > 0.0)? total_time: 0.0; - render_time_ = (render_time > 0.0)? render_time: 0.0; + thread_scoped_lock lock(progress_mutex); + + total_time_ = time_dt() - start_time; + render_time_ = time_dt() - render_start_time; } void reset_sample() { thread_scoped_lock lock(progress_mutex); - sample = 0; + pixel_samples = 0; + current_tile_sample = 0; + finished_tiles = 0; } - void increment_sample() + void set_total_pixel_samples(uint64_t total_pixel_samples_) { thread_scoped_lock lock(progress_mutex); - sample++; + total_pixel_samples = total_pixel_samples_; } - void increment_sample_update() + float get_progress() { - increment_sample(); + if(total_pixel_samples > 0) { + return ((float) pixel_samples) / total_pixel_samples; + } + return 0.0f; + } + + void add_samples(uint64_t pixel_samples_, int tile_sample) + { + thread_scoped_lock lock(progress_mutex); + + pixel_samples += pixel_samples_; + current_tile_sample = tile_sample; + } + + void add_samples_update(uint64_t pixel_samples_, int tile_sample) + { + add_samples(pixel_samples_, tile_sample); set_update(); } - int get_sample() + void add_finished_tile() { - return sample; + thread_scoped_lock lock(progress_mutex); + + finished_tiles++; + } + + int get_current_sample() + { + /* Note that the value here always belongs to the last tile that updated, + * so it's only useful if there is only one active tile. */ + return current_tile_sample; + } + + int get_finished_tiles() + { + return finished_tiles; } /* status messages */ @@ -212,8 +236,6 @@ public: thread_scoped_lock lock(progress_mutex); status = status_; substatus = substatus_; - total_time = time_dt() - start_time; - render_time = time_dt() - render_start_time; } set_update(); @@ -224,8 +246,6 @@ public: { thread_scoped_lock lock(progress_mutex); substatus = substatus_; - total_time = time_dt() - start_time; - render_time = time_dt() - render_start_time; } set_update(); @@ -237,8 +257,6 @@ public: thread_scoped_lock lock(progress_mutex); sync_status = status_; sync_substatus = substatus_; - total_time = time_dt() - start_time; - render_time = time_dt() - render_start_time; } set_update(); @@ -250,8 +268,6 @@ public: { thread_scoped_lock lock(progress_mutex); sync_substatus = substatus_; - total_time = time_dt() - start_time; - render_time = time_dt() - render_start_time; } set_update(); @@ -292,12 +308,19 @@ protected: function update_cb; function cancel_cb; - int tile; /* counter for rendered tiles */ - int sample; /* counter of rendered samples, global for all tiles */ + /* pixel_samples counts how many samples have been rendered over all pixel, not just per pixel. + * This makes the progress estimate more accurate when tiles with different sizes are used. + * + * total_pixel_samples is the total amount of pixel samples that will be rendered. */ + uint64_t pixel_samples, total_pixel_samples; + /* Stores the current sample count of the last tile that called the update function. + * It's used to display the sample count if only one tile is active. */ + int current_tile_sample; + /* Stores the number of tiles that's already finished. + * Used to determine whether all but the last tile are finished rendering, in which case the current_tile_sample is displayed. */ + int finished_tiles; double start_time, render_start_time; - double total_time, render_time; - double tile_time; string status; string substatus; diff --git a/intern/cycles/util/util_time.h b/intern/cycles/util/util_time.h index a5b074bffa0..65798244111 100644 --- a/intern/cycles/util/util_time.h +++ b/intern/cycles/util/util_time.h @@ -29,7 +29,7 @@ void time_sleep(double t); class scoped_timer { public: - explicit scoped_timer(double *value) : value_(value) + explicit scoped_timer(double *value = NULL) : value_(value) { time_start_ = time_dt(); } @@ -40,6 +40,12 @@ public: *value_ = time_dt() - time_start_; } } + + double get_start() const + { + return time_start_; + } + protected: double *value_; double time_start_; From 1a01ef4ae903f05ae4ff14bd585ed909e35fc089 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 3 Dec 2016 14:56:46 +0100 Subject: [PATCH 343/590] Fix macOS build with openimageio 1.7.8 and openexr. These macros conflict and are no longer needed with C99 or C++ anyway. --- source/blender/blenlib/BLI_math_base.h | 57 -------------------------- 1 file changed, 57 deletions(-) diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index e97a250cd24..0126e30d900 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -85,63 +85,6 @@ static const int NAN_INT = 0x7FC00000; # define NAN_FLT (*((float *)(&NAN_INT))) #endif -/* do not redefine functions from C99, POSIX.1-2001 or MSVC12 (partial C99) */ -#if !(defined(_ISOC99_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || defined(_MSC_VER)) - -#ifndef sqrtf -#define sqrtf(a) ((float)sqrt(a)) -#endif -#ifndef powf -#define powf(a, b) ((float)pow(a, b)) -#endif -#ifndef cosf -#define cosf(a) ((float)cos(a)) -#endif -#ifndef sinf -#define sinf(a) ((float)sin(a)) -#endif -#ifndef acosf -#define acosf(a) ((float)acos(a)) -#endif -#ifndef asinf -#define asinf(a) ((float)asin(a)) -#endif -#ifndef atan2f -#define atan2f(a, b) ((float)atan2(a, b)) -#endif -#ifndef tanf -#define tanf(a) ((float)tan(a)) -#endif -#ifndef atanf -#define atanf(a) ((float)atan(a)) -#endif -#ifndef floorf -#define floorf(a) ((float)floor(a)) -#endif -#ifndef ceilf -#define ceilf(a) ((float)ceil(a)) -#endif -#ifndef fabsf -#define fabsf(a) ((float)fabs(a)) -#endif -#ifndef logf -#define logf(a) ((float)log(a)) -#endif -#ifndef expf -#define expf(a) ((float)exp(a)) -#endif -#ifndef fmodf -#define fmodf(a, b) ((float)fmod(a, b)) -#endif -#ifndef hypotf -#define hypotf(a, b) ((float)hypot(a, b)) -#endif -#ifndef copysignf -#define copysignf(a, b) ((float)copysign(a, b)) -#endif - -#endif /* C99, POSIX.1-2001 or MSVC12 (partial C99) */ - #if BLI_MATH_DO_INLINE #include "intern/math_base_inline.c" #endif From ae04d0fcb6e05f6a1132b5dd4f6103f01d0c5dd1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sat, 3 Dec 2016 14:56:58 +0100 Subject: [PATCH 344/590] CMake: update for macOS 10.9 libs with ffmpeg 3.2.1 and webp support. --- build_files/cmake/platform/platform_apple.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 129969ad16c..0083cca6bff 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -158,7 +158,7 @@ if(WITH_CODEC_FFMPEG) mp3lame swscale x264 xvidcore theora theoradec theoraenc vorbis vorbisenc vorbisfile ogg ) if(WITH_CXX11) - set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} schroedinger orc vpx) + set(FFMPEG_LIBRARIES ${FFMPEG_LIBRARIES} schroedinger orc vpx webp swresample) endif() set(FFMPEG_LIBPATH ${FFMPEG}/lib) endif() From 923eae25d1abf7b93edf553982877672f6259dcb Mon Sep 17 00:00:00 2001 From: lazydodo Date: Sat, 3 Dec 2016 17:38:20 -0700 Subject: [PATCH 345/590] [msvc] Changes for new oiio/ffmpeg versions. --- .../cmake/platform/platform_win32_msvc.cmake | 15 ++++++++------- source/creator/CMakeLists.txt | 16 +++++++--------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/build_files/cmake/platform/platform_win32_msvc.cmake b/build_files/cmake/platform/platform_win32_msvc.cmake index 96c9ec91d11..3b50351a131 100644 --- a/build_files/cmake/platform/platform_win32_msvc.cmake +++ b/build_files/cmake/platform/platform_win32_msvc.cmake @@ -238,14 +238,14 @@ if(WITH_CODEC_FFMPEG) windows_find_package(FFMPEG) if(NOT FFMPEG_FOUND) warn_hardcoded_paths(ffmpeg) - set(FFMPEG_LIBRARY_VERSION 55) - set(FFMPEG_LIBRARY_VERSION_AVU 52) + set(FFMPEG_LIBRARY_VERSION 57) + set(FFMPEG_LIBRARY_VERSION_AVU 55) set(FFMPEG_LIBRARIES - ${LIBDIR}/ffmpeg/lib/avcodec-${FFMPEG_LIBRARY_VERSION}.lib - ${LIBDIR}/ffmpeg/lib/avformat-${FFMPEG_LIBRARY_VERSION}.lib - ${LIBDIR}/ffmpeg/lib/avdevice-${FFMPEG_LIBRARY_VERSION}.lib - ${LIBDIR}/ffmpeg/lib/avutil-${FFMPEG_LIBRARY_VERSION_AVU}.lib - ${LIBDIR}/ffmpeg/lib/swscale-2.lib + ${LIBDIR}/ffmpeg/lib/avcodec.lib + ${LIBDIR}/ffmpeg/lib/avformat.lib + ${LIBDIR}/ffmpeg/lib/avdevice.lib + ${LIBDIR}/ffmpeg/lib/avutil.lib + ${LIBDIR}/ffmpeg/lib/swscale.lib ) endif() endif() @@ -380,6 +380,7 @@ if(WITH_OPENIMAGEIO) set(OPENCOLORIO_DEFINITIONS "-DOCIO_STATIC_BUILD") set(OPENIMAGEIO_IDIFF "${OPENIMAGEIO}/bin/idiff.exe") add_definitions(-DOIIO_STATIC_BUILD) + add_definitions(-DOIIO_NO_SSE=1) endif() if(WITH_LLVM) diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 04a79f6498f..eea45545949 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -713,10 +713,7 @@ elseif(WIN32) ) if(WITH_PYTHON_INSTALL_NUMPY) - set(PYTHON_NUMPY_VERSION 1.9) - if((MSVC_VERSION EQUAL 1900) OR (MSVC_VERSION EQUAL 1910)) - set(PYTHON_NUMPY_VERSION 1.11) - endif() + set(PYTHON_NUMPY_VERSION 1.10) add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${BLENDER_VERSION}/python/lib/site-packages) @@ -830,11 +827,12 @@ elseif(WIN32) else() install( FILES - ${LIBDIR}/ffmpeg/lib/avcodec-55.dll - ${LIBDIR}/ffmpeg/lib/avformat-55.dll - ${LIBDIR}/ffmpeg/lib/avdevice-55.dll - ${LIBDIR}/ffmpeg/lib/avutil-52.dll - ${LIBDIR}/ffmpeg/lib/swscale-2.dll + ${LIBDIR}/ffmpeg/lib/avcodec-57.dll + ${LIBDIR}/ffmpeg/lib/avformat-57.dll + ${LIBDIR}/ffmpeg/lib/avdevice-57.dll + ${LIBDIR}/ffmpeg/lib/avutil-55.dll + ${LIBDIR}/ffmpeg/lib/swscale-4.dll + ${LIBDIR}/ffmpeg/lib/swresample-2.dll DESTINATION "." ) endif() From d9d7b5b4d0779e16e5ba3103982351180de7df0e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 4 Dec 2016 15:05:50 +1100 Subject: [PATCH 346/590] Cleanup: simplify bitmap line drawing - Expand overly dense & confusing delta assignments. - Replace bit shift with multiply. Also link to 'clipped' version of this function which may be useful to add later. --- .../blender/blenlib/intern/bitmap_draw_2d.c | 43 +++++++++++-------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/source/blender/blenlib/intern/bitmap_draw_2d.c b/source/blender/blenlib/intern/bitmap_draw_2d.c index afc54511d13..e77e8cf40d0 100644 --- a/source/blender/blenlib/intern/bitmap_draw_2d.c +++ b/source/blender/blenlib/intern/bitmap_draw_2d.c @@ -46,6 +46,8 @@ /** * Plot a line from \a p1 to \a p2 (inclusive). + * + * \note For clipped line drawing, see: http://stackoverflow.com/a/40902741/432509 */ void BLI_bitmap_draw_2d_line_v2v2i( const int p1[2], const int p2[2], @@ -57,33 +59,36 @@ void BLI_bitmap_draw_2d_line_v2v2i( int x2 = p2[0]; int y2 = p2[1]; - 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; - int delta_y = (y2 > y1 ? ((void)(iy = 1), y2 - y1) : ((void)(iy = -1), y1 - y2)) << 1; - if (callback(x1, y1, userData) == 0) { return; } + /* if x1 == x2 or y1 == y2, then it does not matter what we set here */ + const int sign_x = (x2 > x1) ? 1 : -1; + const int sign_y = (y2 > y1) ? 1 : -1; + + const int delta_x = (sign_x == 1) ? (x2 - x1) : (x1 - x2); + const int delta_y = (sign_y == 1) ? (y2 - y1) : (y1 - y2); + + const int delta_x_step = delta_x * 2; + const int delta_y_step = delta_y * 2; + if (delta_x >= delta_y) { /* error may go below zero */ - int error = delta_y - (delta_x >> 1); + int error = delta_y_step - delta_x; while (x1 != x2) { if (error >= 0) { - if (error || (ix > 0)) { - y1 += iy; - error -= delta_x; + if (error || (sign_x == 1)) { + y1 += sign_y; + error -= delta_x_step; } /* else do nothing */ } /* else do nothing */ - x1 += ix; - error += delta_y; + x1 += sign_x; + error += delta_y_step; if (callback(x1, y1, userData) == 0) { return; @@ -92,20 +97,20 @@ void BLI_bitmap_draw_2d_line_v2v2i( } else { /* error may go below zero */ - int error = delta_x - (delta_y >> 1); + int error = delta_x_step - delta_y; while (y1 != y2) { if (error >= 0) { - if (error || (iy > 0)) { - x1 += ix; - error -= delta_y; + if (error || (sign_y == 1)) { + x1 += sign_x; + error -= delta_y_step; } /* else do nothing */ } /* else do nothing */ - y1 += iy; - error += delta_x; + y1 += sign_y; + error += delta_x_step; if (callback(x1, y1, userData) == 0) { return; From 7d443ed86df8ad5cc1bed831a1333f5b550c3f01 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sun, 4 Dec 2016 21:55:17 +1100 Subject: [PATCH 347/590] Docs: Show 'Other Options' last in --help Own error when changing order, moving experimental features last made some sense, but causes them to be listed twice. Reorder and comment to avoid it happening again. --- source/creator/creator_args.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index c3c76a0d1d3..ab3410d2b7b 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -584,16 +584,16 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo BLI_argsPrintArgDoc(ba, "--"); - printf("\n"); - printf("Other Options:\n"); - BLI_argsPrintOtherDoc(ba); - - /* keep last args */ printf("\n"); printf("Experimental Features:\n"); BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph"); BLI_argsPrintArgDoc(ba, "--enable-new-basic-shader-glsl"); + /* Other options _must_ be last (anything not handled will show here) */ + printf("\n"); + printf("Other Options:\n"); + BLI_argsPrintOtherDoc(ba); + printf("\n"); printf("Argument Parsing:\n"); printf("\tArguments must be separated by white space, eg:\n"); From 1791697d4337eecf6a6007772b165b9142e7fcc1 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 4 Dec 2016 13:49:34 +0100 Subject: [PATCH 348/590] Fix macOS 10.9 build when using OIIO without FFmpeg. --- build_files/cmake/platform/platform_apple.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build_files/cmake/platform/platform_apple.cmake b/build_files/cmake/platform/platform_apple.cmake index 0083cca6bff..04485e31d98 100644 --- a/build_files/cmake/platform/platform_apple.cmake +++ b/build_files/cmake/platform/platform_apple.cmake @@ -316,6 +316,9 @@ if(WITH_OPENIMAGEIO) ${OPENEXR_LIBRARIES} ${ZLIB_LIBRARIES} ) + if(WITH_CXX11) + set(OPENIMAGEIO_LIBRARIES ${OPENIMAGEIO_LIBRARIES} ${LIBDIR}/ffmpeg/lib/libwebp.a) + endif() set(OPENIMAGEIO_LIBPATH ${OPENIMAGEIO}/lib ${JPEG_LIBPATH} From dfca1e14605f4318c8e20acead4a06c38d3d435b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Sun, 4 Dec 2016 20:23:55 +0100 Subject: [PATCH 349/590] CMake: disable QuickTime with macOS SDK 10.12+, no longer supported by Apple. --- CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index afc1d9d5872..8055f4fd3e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -628,6 +628,12 @@ if(APPLE) # to silence sdk not found warning, just overrides CMAKE_OSX_SYSROOT set(CMAKE_XCODE_ATTRIBUTE_SDKROOT macosx${OSX_SYSTEM}) endif() + + # QuickTime framework is no longer available in SDK 10.12+ + if(WITH_CODEC_QUICKTIME AND ${OSX_SYSTEM} VERSION_GREATER 10.11) + set(WITH_CODEC_QUICKTIME OFF) + message(STATUS "QuickTime not supported by SDK ${OSX_SYSTEM}, disabling WITH_CODEC_QUICKTIME") + endif() endif() if(OSX_SYSTEM MATCHES 10.9) From b18f83bcf404fee98713fd2eba82570efb53f13e Mon Sep 17 00:00:00 2001 From: Luca Rood Date: Sat, 3 Dec 2016 14:05:56 -0200 Subject: [PATCH 350/590] Fix T50141: Nabla zero division on texture force field This sets forces to zero, when Nabla is zero and a grayscale texture is used or texture mode is Gradient or Curl. Nabla equal to zero was causing a zero division, and forces ended up being set to `nan`. Reviewed By: mont29 Differential Revision: http://developer.blender.org/D2393 --- source/blender/blenkernel/intern/effect.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 7e6897a2858..3e85b0d4a15 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -770,7 +770,7 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP force[1] = (0.5f - result->tg) * strength; force[2] = (0.5f - result->tb) * strength; } - else { + else if (nabla != 0) { strength/=nabla; tex_co[0] += nabla; @@ -810,6 +810,9 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP force[2] = (dgdx - drdy) * strength; } } + else { + zero_v3(force); + } if (eff->pd->flag & PFIELD_TEX_2D) { float fac = -dot_v3v3(force, efd->nor); From 95b224dab2ea02e89e64890f6764708a24705db8 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 5 Dec 2016 11:34:49 +0100 Subject: [PATCH 351/590] Fix compilation error on recent Debian desktop Something funny happened here, there were missing symbols from png library to math functions. --- source/blender/datatoc/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/datatoc/CMakeLists.txt b/source/blender/datatoc/CMakeLists.txt index 0f123fbf9f0..af7f954cad1 100644 --- a/source/blender/datatoc/CMakeLists.txt +++ b/source/blender/datatoc/CMakeLists.txt @@ -62,4 +62,9 @@ if(NOT WITH_HEADLESS) add_executable(datatoc_icon ${SRC}) target_link_libraries(datatoc_icon ${PNG_LIBRARIES} ${ZLIB_LIBRARIES}) + # PNG library uses pow() and floow(), so seems -lm is required for proper + # workign binary. + if(UNIX AND NOT APPLE) + target_link_libraries(datatoc_icon m) + endif() endif() From 60dae91db85479f714cf8c797e467d6a941dea18 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Mon, 5 Dec 2016 13:35:24 +0300 Subject: [PATCH 352/590] Fix depsgraph: hair collision is actually enabled, so add the relations. --- source/blender/blenkernel/intern/depsgraph.c | 4 ++++ .../blender/depsgraph/intern/builder/deg_builder_relations.cc | 3 +++ 2 files changed, 7 insertions(+) diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index 7361645ba2c..a8341939692 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -800,6 +800,10 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc /* Actual code uses get_collider_cache */ dag_add_collision_relations(dag, scene, ob, node, part->collision_group, ob->lay, eModifierType_Collision, NULL, true, "Particle Collision"); } + else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) { + /* Hair uses cloth simulation, i.e. get_collision_objects */ + dag_add_collision_relations(dag, scene, ob, node, psys->clmd->coll_parms->group, ob->lay | scene->lay, eModifierType_Collision, NULL, true, "Hair Collision"); + } dag_add_forcefield_relations(dag, scene, ob, node, part->effector_weights, part->type == PART_HAIR, 0, "Particle Force Field"); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index dadb7f8917f..ac917f2148a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1210,6 +1210,9 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) if (part->type != PART_HAIR) { add_collision_relations(psys_key, scene, ob, part->collision_group, ob->lay, true, "Particle Collision"); } + else if ((psys->flag & PSYS_HAIR_DYNAMICS) && psys->clmd && psys->clmd->coll_parms) { + add_collision_relations(psys_key, scene, ob, psys->clmd->coll_parms->group, ob->lay | scene->lay, true, "Hair Collision"); + } /* effectors */ add_forcefield_relations(psys_key, scene, ob, psys, part->effector_weights, part->type == PART_HAIR, "Particle Field"); From 2cb5dffc8d307753f2e05f6a474289182c6b058b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 5 Dec 2016 15:59:31 +0100 Subject: [PATCH 353/590] Depsgraph: Avoid transitive relation from local transform to final There is always an uber eval node on the way. so we can avoid creating some relations here in order to speed up both construction time and evaluation. --- .../intern/builder/deg_builder_relations.cc | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index ac917f2148a..46f053e23e0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -406,12 +406,18 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval"); } else { - /* operation order */ - add_relation(base_op_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Object Transform"); - - // XXX - add_relation(base_op_key, ob_ubereval_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval"); - add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval"); + /* NOTE: Keep an eye here, we skip some relations here to "streamline" + * dependencies and avoid transitive relations which causes overhead. + * But once we get rid of uber eval node this will need reconsideration. + */ + add_relation(base_op_key, + ob_ubereval_key, + DEPSREL_TYPE_COMPONENT_ORDER, + "Temp Ubereval"); + add_relation(ob_ubereval_key, + final_transform_key, + DEPSREL_TYPE_COMPONENT_ORDER, + "Temp Ubereval"); } From d1d721769299d8c79c45fe2c2849a81c3b57e82c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 5 Dec 2016 16:03:10 +0100 Subject: [PATCH 354/590] Depsgraph: Rigid body simulation doesn't need explicit time relation It'll be dependent on time via Time Source -> Rebuild RB World chain. --- .../depsgraph/intern/builder/deg_builder_relations.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 46f053e23e0..3fa22741e4d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1065,8 +1065,10 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) /* time dependency */ TimeSourceKey time_src_key; - add_relation(time_src_key, init_key, DEPSREL_TYPE_TIME, "TimeSrc -> Rigidbody Reset/Rebuild (Optional)"); - add_relation(time_src_key, sim_key, DEPSREL_TYPE_TIME, "TimeSrc -> Rigidbody Sim Step"); + add_relation(time_src_key, + init_key, + DEPSREL_TYPE_TIME, + "TimeSrc -> Rigidbody Reset/Rebuild (Optional)"); /* objects - simulation participants */ if (rbw->group) { From 69e8e34d9662f1788712f0736dafa53e4e47eea3 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 5 Dec 2016 16:30:30 +0100 Subject: [PATCH 355/590] Depsgraph: avoid more transitive relations for rigid body simulation --- .../intern/builder/deg_builder_relations.cc | 50 ++++++++++++------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 3fa22741e4d..d9a21d2b888 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -410,10 +410,15 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o * dependencies and avoid transitive relations which causes overhead. * But once we get rid of uber eval node this will need reconsideration. */ - add_relation(base_op_key, - ob_ubereval_key, - DEPSREL_TYPE_COMPONENT_ORDER, - "Temp Ubereval"); + if (ob->rigidbody_object == NULL) { + /* Rigid body will hook up another node inbetween, so skip + * relation here to avoid transitive relation. + */ + add_relation(base_op_key, + ob_ubereval_key, + DEPSREL_TYPE_COMPONENT_ORDER, + "Temp Ubereval"); + } add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, @@ -1091,7 +1096,6 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) eDepsOperation_Code trans_opcode = ob->parent ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL; OperationKey trans_op(&ob->id, DEPSNODE_TYPE_TRANSFORM, trans_opcode); - add_relation(trans_op, rbo_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> RBO Sync"); add_relation(sim_key, rbo_key, DEPSREL_TYPE_COMPONENT_ORDER, "Rigidbody Sim Eval -> RBO Sync"); /* if constraints exist, those depend on the result of the rigidbody sim @@ -1103,22 +1107,34 @@ void DepsgraphRelationBuilder::build_rigidbody(Scene *scene) * to control whether rigidbody eval gets interleaved into the constraint stack */ if (ob->constraints.first) { - OperationKey constraint_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_CONSTRAINTS); - add_relation(rbo_key, constraint_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Ob Constraints"); + OperationKey constraint_key(&ob->id, + DEPSNODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_CONSTRAINTS); + add_relation(rbo_key, + constraint_key, + DEPSREL_TYPE_COMPONENT_ORDER, + "RBO Sync -> Ob Constraints"); } else { - /* final object transform depends on rigidbody */ - OperationKey done_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL); - add_relation(rbo_key, done_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Done"); - - // XXX: ubereval will be removed eventually, but we still need it in the meantime - OperationKey uber_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL); - add_relation(rbo_key, uber_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Uber (Temp)"); + /* Final object transform depends on rigidbody. + * + * NOTE: Currently we consider final here an ubereval node. + * If it is gone we'll need to reconsider relation here. + */ + OperationKey uber_key(&ob->id, + DEPSNODE_TYPE_TRANSFORM, + DEG_OPCODE_OBJECT_UBEREVAL); + add_relation(rbo_key, + uber_key, + DEPSREL_TYPE_COMPONENT_ORDER, + "RBO Sync -> Uber (Temp)"); } - - /* needed to get correct base values */ - add_relation(trans_op, sim_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> Rigidbody Sim Eval"); + /* Needed to get correct base values. */ + add_relation(trans_op, + sim_key, + DEPSREL_TYPE_OPERATION, + "Base Ob Transform -> Rigidbody Sim Eval"); } } From 7471f09f2bb20fed33c57ca0ad53990be3eb48fd Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 5 Dec 2016 16:31:34 +0100 Subject: [PATCH 356/590] Depsgraph: Use HIGH priority for scheduled tasks This kind of keeps threads "warmer" and should in theory give better cache coherency bringing some %% of speedup. It was already tested few months ago and it gave few % speedup in barber shop, but was reverted due to some bone popping. The popping is now fixed so it should be fine to use new scheduling policy. --- source/blender/depsgraph/intern/eval/deg_eval.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index e926f83bcbe..065f65659e6 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); } } From fe0520e2c841569712e14446f4afbb4036daae3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Mon, 5 Dec 2016 23:33:21 +0100 Subject: [PATCH 357/590] UI: add a message to indicate when using a modifier that wasn't compiled. This adds a short message to the smoke, remesh and boolean modifiers' UI when trying to use them when their compilation was turned off. This was already implemented for the fluid and ocean simulation modifiers. This also makes the 'quick fluid' and 'quick smoke' operator abort and report when trying to use them when unavailable. --- .../scripts/startup/bl_operators/object_quick_effects.py | 8 ++++++++ release/scripts/startup/bl_ui/properties_data_modifier.py | 8 ++++++++ release/scripts/startup/bl_ui/properties_physics_smoke.py | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index 414855c7e35..cdab380bb9c 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -317,6 +317,10 @@ class QuickSmoke(Operator): ) def execute(self, context): + if not bpy.app.build_options.mod_smoke: + self.report({'ERROR'}, "Build without Smoke modifier support") + return {'CANCELLED'} + fake_context = context.copy() mesh_objects = [obj for obj in context.selected_objects if obj.type == 'MESH'] @@ -562,6 +566,10 @@ class QuickFluid(Operator): ) def execute(self, context): + if not bpy.app.build_options.mod_fluid: + self.report({'ERROR'}, "Build without Fluid modifier support") + return {'CANCELLED'} + fake_context = context.copy() mesh_objects = [obj for obj in context.selected_objects if (obj.type == 'MESH' and 0.0 not in obj.dimensions)] diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 540c29f31e4..d66fb08bcd6 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -146,6 +146,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): layout.row().prop(md, "offset_type", expand=True) def BOOLEAN(self, layout, ob, md): + if not bpy.app.build_options.mod_boolean: + layout.label("Built without Boolean modifier") + return + split = layout.split() col = split.column() @@ -1077,6 +1081,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col.prop(md, "narrowness", slider=True) def REMESH(self, layout, ob, md): + if not bpy.app.build_options.mod_remesh: + layout.label("Built without Remesh modifier") + return + layout.prop(md, "mode") row = layout.row() diff --git a/release/scripts/startup/bl_ui/properties_physics_smoke.py b/release/scripts/startup/bl_ui/properties_physics_smoke.py index 0374d032141..ee9135b9dbf 100644 --- a/release/scripts/startup/bl_ui/properties_physics_smoke.py +++ b/release/scripts/startup/bl_ui/properties_physics_smoke.py @@ -45,6 +45,10 @@ class PHYSICS_PT_smoke(PhysicButtonsPanel, Panel): def draw(self, context): layout = self.layout + if not bpy.app.build_options.mod_smoke: + layout.label("Built without Smoke modifier") + return + md = context.smoke ob = context.object From 8ce6de3bdd9f8869457ea39d20d7e08a01663c39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Tue, 6 Dec 2016 00:04:15 +0100 Subject: [PATCH 358/590] Fix T50020: adding a background image does not set image user data. --- source/blender/editors/space_image/image_ops.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 6ca738b0e11..f5da7d57010 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -52,6 +52,7 @@ #include "DNA_node_types.h" #include "DNA_packedFile_types.h" #include "DNA_scene_types.h" +#include "DNA_screen_types.h" #include "BKE_colortools.h" #include "BKE_context.h" @@ -1218,7 +1219,7 @@ static Image *image_open_single( static int image_open_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - SpaceImage *sima = CTX_wm_space_image(C); /* XXX other space types can call */ + ScrArea *sa = CTX_wm_area(C); Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); ImageUser *iuser = NULL; @@ -1297,10 +1298,21 @@ static int image_open_exec(bContext *C, wmOperator *op) if (iod->iuser) { iuser = iod->iuser; } - else if (sima) { + else if (sa->spacetype == SPACE_IMAGE) { + SpaceImage *sima = sa->spacedata.first; ED_space_image_set(sima, scene, obedit, ima); iuser = &sima->iuser; } + else if (sa->spacetype == SPACE_VIEW3D) { + View3D *v3d = sa->spacedata.first; + + for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + if (bgpic->ima == ima) { + iuser = &bgpic->iuser; + break; + } + } + } else { Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; if (tex && tex->type == TEX_IMAGE) { From 1de79c896019c7fa20dee9dabb25a331463767d2 Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Tue, 6 Dec 2016 07:43:47 -0500 Subject: [PATCH 359/590] Fix T50003, Bevel makes non-manifold mesh. Problem was setting prev/next faces for edges around a vertex on valence-2 vertices. --- source/blender/bmesh/tools/bmesh_bevel.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 6c168bd9114..8340be81aa8 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -3557,7 +3557,7 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme) { BMEdge *bme, *bme2; BMIter iter; - BMFace *f; + BMFace *f, *bestf; EdgeHalf *e; EdgeHalf *e2; BMLoop *l; @@ -3595,10 +3595,21 @@ static void find_bevel_edge_order(BMesh *bm, BevVert *bv, BMEdge *first_bme) bme = e->e; bme2 = e2->e; BLI_assert(bme != NULL); + if (e->fnext != NULL || e2->fprev != NULL) + continue; + /* Which faces have successive loops that are for bme and bme2? + * There could be more than one. E.g., in manifold ntot==2 case. + * Prefer one that has loop in same direction as e. */ + bestf = NULL; BM_ITER_ELEM(l, &iter, bme, BM_LOOPS_OF_EDGE) { f = l->f; - if ((l->prev->e == bme2 || l->next->e == bme2) && !e->fnext && !e2->fprev) - e->fnext = e2->fprev = f; + if ((l->prev->e == bme2 || l->next->e == bme2)) { + if (!bestf || l->v == bv->v) + bestf = f; + } + if (bestf) { + e->fnext = e2->fprev = bestf; + } } } } From 1b9cae9d04c222d1ce8dc05abbd5692c30fe3e57 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 6 Dec 2016 14:19:17 +0100 Subject: [PATCH 360/590] Fix T50122: SEGFAULT: OCIO configuration typo leads to segfault --- source/blender/imbuf/intern/colormanagement.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index 01348549bc4..a45346279d9 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -1227,7 +1227,12 @@ const char *IMB_colormanagement_get_float_colorspace(ImBuf *ibuf) const char *IMB_colormanagement_get_rect_colorspace(ImBuf *ibuf) { - return ibuf->rect_colorspace->name; + if (ibuf->rect_colorspace) { + return ibuf->rect_colorspace->name; + } + else { + return IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_BYTE); + } } /*********************** Threaded display buffer transform routines *************************/ From 0371ef16ee029a8a27938e4d29cb19cc96dc6194 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 6 Dec 2016 14:48:48 +0100 Subject: [PATCH 361/590] Depsgraph: Only re-schedule objects which are on visible layers Otherwise it's possible to cause infinite update loop in Cycles viewport. Gets a bit messy logic, need to revisit this.. --- .../depsgraph/intern/builder/deg_builder.cc | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index aedd00685b3..cb2f057a090 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -154,19 +154,21 @@ void deg_graph_build_finalize(Depsgraph *graph) } GHASH_FOREACH_END(); - ID *id = id_node->id; - if ((id->tag & LIB_TAG_ID_RECALC_ALL) && - (id->tag & LIB_TAG_DOIT)) - { - id_node->tag_update(graph); - id->tag &= ~LIB_TAG_DOIT; - } - else if (GS(id->name) == ID_OB) { - Object *object = (Object *)id; - if (object->recalc & OB_RECALC_ALL) { + if ((id_node->layers & graph->layers) != 0) { + ID *id = id_node->id; + if ((id->tag & LIB_TAG_ID_RECALC_ALL) && + (id->tag & LIB_TAG_DOIT)) + { id_node->tag_update(graph); id->tag &= ~LIB_TAG_DOIT; } + else if (GS(id->name) == ID_OB) { + Object *object = (Object *)id; + if (object->recalc & OB_RECALC_ALL) { + id_node->tag_update(graph); + id->tag &= ~LIB_TAG_DOIT; + } + } } id_node->finalize_build(); } From 4b69b6d316c581630a5a8f3d86c1d63639b9ef2b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 6 Dec 2016 15:36:35 +0100 Subject: [PATCH 362/590] Cycles :Cleanup, indentation --- intern/cycles/render/nodes.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 3fb2bb1cf92..c7f37a13fba 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -1442,14 +1442,14 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler) else { if(use_density) { compiler.add_node(NODE_VALUE_F, - __float_as_int(0.0f), - compiler.stack_assign(density_out)); + __float_as_int(0.0f), + compiler.stack_assign(density_out)); } if(use_color) { compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out)); compiler.add_node(NODE_VALUE_V, make_float3(TEX_IMAGE_MISSING_R, - TEX_IMAGE_MISSING_G, - TEX_IMAGE_MISSING_B)); + TEX_IMAGE_MISSING_G, + TEX_IMAGE_MISSING_B)); } } } @@ -2421,7 +2421,7 @@ void BackgroundNode::compile(SVMCompiler& compiler) if(color_in->link || strength_in->link) { compiler.add_node(NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), - compiler.stack_assign(strength_in)); + compiler.stack_assign(strength_in)); } else compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color*strength); From bfe34789d1301407e91841d61e24c7a8f0691aa5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 7 Dec 2016 11:27:27 +0100 Subject: [PATCH 363/590] Use proper defaults for Hue/Saturation node --- source/blender/makesrna/intern/rna_nodetree.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 34002f8d550..ada4dec1899 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4450,6 +4450,7 @@ static void def_cmp_hue_saturation(StructRNA *srna) prop = RNA_def_property(srna, "color_hue", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "hue"); RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_float_default(prop, 0.5f); RNA_def_property_ui_text(prop, "Hue", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); @@ -4457,12 +4458,14 @@ static void def_cmp_hue_saturation(StructRNA *srna) RNA_def_property_float_sdna(prop, NULL, "sat"); RNA_def_property_range(prop, 0.0f, 2.0f); RNA_def_property_ui_text(prop, "Saturation", ""); + RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "color_value", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "val"); RNA_def_property_range(prop, 0.0f, 2.0f); RNA_def_property_ui_text(prop, "Value", ""); + RNA_def_property_float_default(prop, 1.0f); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } From 2002167a9630d89fc37b13b486857bd87311c824 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 7 Dec 2016 11:39:12 +0100 Subject: [PATCH 364/590] Remove unused include statement --- .../compositor/nodes/COM_HueSaturationValueCorrectNode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp index e159886bb46..851d43fc062 100644 --- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp +++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp @@ -27,7 +27,6 @@ #include "COM_MixOperation.h" #include "COM_SetColorOperation.h" #include "COM_SetValueOperation.h" -#include "COM_ChangeHSVOperation.h" #include "DNA_node_types.h" #include "COM_HueSaturationValueCorrectOperation.h" From 8f29503b523f243ae00db9a490927e628e4bdc91 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 7 Dec 2016 14:16:07 +0100 Subject: [PATCH 365/590] Fix T49893: Crash in Video Sequence Editor with 'drop' effect. Code was not accounting for possibilities that width or height of given buffers may be smaller than XOFF/YOFF... Note that I seriously doubt that drop code actually works (as in, gives expected results) when applied to tiles like it seems to be done currently, but this is much more complex (and involved) topic. --- source/blender/blenkernel/intern/seqeffects.c | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index ce7c520438a..802f0ffb518 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -1074,29 +1074,31 @@ static void do_sub_effect(const SeqRenderData *context, Sequence *UNUSED(seq), f static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi) { - int height, width, temp, fac, fac1, fac2; + int temp, fac, fac1, fac2; unsigned char *rt1, *rt2, *out; int field = 1; - width = x; - height = y; + const int width = x; + const int height = y; + const int xoff = min_ii(XOFF, width); + const int yoff = min_ii(YOFF, height); fac1 = (int) (70.0f * facf0); fac2 = (int) (70.0f * facf1); - rt2 = (unsigned char *) (rect2i + YOFF * width); + rt2 = (unsigned char *) (rect2i + yoff * width); rt1 = (unsigned char *) rect1i; out = (unsigned char *) outi; - for (y = 0; y < height - YOFF; y++) { + for (y = 0; y < height - yoff; y++) { if (field) fac = fac1; else fac = fac2; field = !field; - memcpy(out, rt1, sizeof(int) * XOFF); - rt1 += XOFF * 4; - out += XOFF * 4; + memcpy(out, rt1, sizeof(int) * xoff); + rt1 += xoff * 4; + out += xoff * 4; - for (x = XOFF; x < width; x++) { + for (x = xoff; x < width; x++) { temp = ((fac * rt2[3]) >> 8); *(out++) = MAX2(0, *rt1 - temp); rt1++; @@ -1105,37 +1107,38 @@ static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned *(out++) = MAX2(0, *rt1 - temp); rt1++; rt2 += 4; } - rt2 += XOFF * 4; + rt2 += xoff * 4; } - memcpy(out, rt1, sizeof(int) * YOFF * width); + memcpy(out, rt1, sizeof(int) * yoff * width); } static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi) { - int height, width; float temp, fac, fac1, fac2; float *rt1, *rt2, *out; int field = 1; - width = x; - height = y; + const int width = x; + const int height = y; + const int xoff = min_ii(XOFF, width); + const int yoff = min_ii(YOFF, height); fac1 = 70.0f * facf0; fac2 = 70.0f * facf1; - rt2 = (rect2i + YOFF * width); + rt2 = (rect2i + yoff * width); rt1 = rect1i; out = outi; - for (y = 0; y < height - YOFF; y++) { + for (y = 0; y < height - yoff; y++) { if (field) fac = fac1; else fac = fac2; field = !field; - memcpy(out, rt1, 4 * sizeof(float) * XOFF); - rt1 += XOFF * 4; - out += XOFF * 4; + memcpy(out, rt1, 4 * sizeof(float) * xoff); + rt1 += xoff * 4; + out += xoff * 4; - for (x = XOFF; x < width; x++) { + for (x = xoff; x < width; x++) { temp = fac * rt2[3]; *(out++) = MAX2(0.0f, *rt1 - temp); rt1++; @@ -1144,9 +1147,9 @@ static void do_drop_effect_float(float facf0, float facf1, int x, int y, float * *(out++) = MAX2(0.0f, *rt1 - temp); rt1++; rt2 += 4; } - rt2 += XOFF * 4; + rt2 += xoff * 4; } - memcpy(out, rt1, 4 * sizeof(float) * YOFF * width); + memcpy(out, rt1, 4 * sizeof(float) * yoff * width); } /*********************** Mul *************************/ From fc4a51e3faa567fcbcbdc8202fc6e6a9aff2113c Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 7 Dec 2016 14:53:57 +0100 Subject: [PATCH 366/590] Fix (unreported) Sequencer Drop effect: wrong initial offset in second input buffer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reading rest of the code, it's obvious we want to start à YOFF lines from start of rect2i, so we have to also multiply by number of components. Also did some minor cleanup. --- source/blender/blenkernel/intern/seqeffects.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 802f0ffb518..298671beedb 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -1086,15 +1086,15 @@ static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned fac1 = (int) (70.0f * facf0); fac2 = (int) (70.0f * facf1); - rt2 = (unsigned char *) (rect2i + yoff * width); - rt1 = (unsigned char *) rect1i; - out = (unsigned char *) outi; + rt2 = rect2i + yoff * 4 * width; + rt1 = rect1i; + out = outi; for (y = 0; y < height - yoff; y++) { if (field) fac = fac1; else fac = fac2; field = !field; - memcpy(out, rt1, sizeof(int) * xoff); + memcpy(out, rt1, sizeof(*out) * xoff * 4); rt1 += xoff * 4; out += xoff * 4; @@ -1109,7 +1109,7 @@ static void do_drop_effect_byte(float facf0, float facf1, int x, int y, unsigned } rt2 += xoff * 4; } - memcpy(out, rt1, sizeof(int) * yoff * width); + memcpy(out, rt1, sizeof(*out) * yoff * 4 * width); } static void do_drop_effect_float(float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi) @@ -1126,7 +1126,7 @@ static void do_drop_effect_float(float facf0, float facf1, int x, int y, float * fac1 = 70.0f * facf0; fac2 = 70.0f * facf1; - rt2 = (rect2i + yoff * width); + rt2 = rect2i + yoff * 4 * width; rt1 = rect1i; out = outi; for (y = 0; y < height - yoff; y++) { @@ -1134,7 +1134,7 @@ static void do_drop_effect_float(float facf0, float facf1, int x, int y, float * else fac = fac2; field = !field; - memcpy(out, rt1, 4 * sizeof(float) * xoff); + memcpy(out, rt1, sizeof(*out) * xoff * 4); rt1 += xoff * 4; out += xoff * 4; @@ -1149,7 +1149,7 @@ static void do_drop_effect_float(float facf0, float facf1, int x, int y, float * } rt2 += xoff * 4; } - memcpy(out, rt1, 4 * sizeof(float) * yoff * width); + memcpy(out, rt1, sizeof(*out) * yoff * 4 * width); } /*********************** Mul *************************/ From a63108efb195ab2cf751875f26ce2293cc158e47 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 7 Dec 2016 17:17:31 +0100 Subject: [PATCH 367/590] Fix install_deps.sh failing to build ffmpeg 3. --disable-libfaac is no more ffmpeg build option. --- build_files/build_environment/install_deps.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 44334612a3a..ecb1cf87511 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -2480,7 +2480,7 @@ compile_FFmpeg() { --enable-avfilter --disable-vdpau \ --disable-bzlib --disable-libgsm --disable-libspeex \ --enable-pthreads --enable-zlib --enable-stripping --enable-runtime-cpudetect \ - --disable-vaapi --disable-libfaac --disable-nonfree --enable-gpl \ + --disable-vaapi --disable-nonfree --enable-gpl \ --disable-postproc --disable-librtmp --disable-libopencore-amrnb \ --disable-libopencore-amrwb --disable-libdc1394 --disable-version3 --disable-outdev=sdl \ --disable-libxcb \ From 62a2ed97bacc3bc891a0ea3d3ab730d8253ab366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Wed, 7 Dec 2016 23:01:51 +0100 Subject: [PATCH 368/590] Fix crash when opening a Blender file containing Alembic data. Was also affecting object linking. --- source/blender/blenkernel/intern/constraint.c | 1 + source/blender/blenloader/intern/readfile.c | 4 ++++ source/blender/modifiers/intern/MOD_meshsequencecache.c | 1 + 3 files changed, 6 insertions(+) diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 9d4de30aa2c..cb74dbcd8d1 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -4404,6 +4404,7 @@ static void transformcache_free(bConstraint *con) #ifdef WITH_ALEMBIC CacheReader_free(data->reader); #endif + data->reader = NULL; } } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index af73410728b..03c5d083456 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5302,6 +5302,10 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb) csmd->delta_cache = NULL; csmd->delta_cache_num = 0; } + else if (md->type == eModifierType_MeshSequenceCache) { + MeshSeqCacheModifierData *msmcd = (MeshSeqCacheModifierData *)md; + msmcd->reader = NULL; + } } } diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index 72644d56323..2f00a7c71b0 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -81,6 +81,7 @@ static void freeData(ModifierData *md) #ifdef WITH_ALEMBIC CacheReader_free(mcmd->reader); #endif + mcmd->reader = NULL; } } From d5708fdad6a09e1c3b8c6f68e9e852ae673705f2 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 8 Dec 2016 11:53:48 +0100 Subject: [PATCH 369/590] Fix expanding enum property in sub-layout of pie menus //ui_item_enum_expand// function replaces all pie menu's sub-layouts with radial layout. It should replace only root layout. To reproduce the issue paste the code in Blender's text editor and press Run Script button. ``` import bpy class VIEW3D_PIE_template(bpy.types.Menu): bl_label = "Select Mode" def draw(self, context): layout = self.layout.menu_pie() layout.column().prop( context.scene.render.image_settings, "color_mode", expand=True) def register(): bpy.utils.register_class(VIEW3D_PIE_template) def unregister(): bpy.utils.unregister_class(VIEW3D_PIE_template) if __name__ == "__main__": register() bpy.ops.wm.call_menu_pie(name="VIEW3D_PIE_template") ``` Differential Revision: https://developer.blender.org/D2394 by @raa --- source/blender/editors/interface/interface_layout.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index b128bf47b5f..342c7182453 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -570,8 +570,13 @@ static void ui_item_enum_expand( /* we dont want nested rows, cols in menus */ if (radial) { - layout_radial = uiLayoutRadial(layout); - UI_block_layout_set_current(block, layout_radial); + if (layout->root->layout == layout) { + layout_radial = uiLayoutRadial(layout); + UI_block_layout_set_current(block, layout_radial); + } + else { + UI_block_layout_set_current(block, layout); + } } else if (layout->root->type != UI_LAYOUT_MENU) { UI_block_layout_set_current(block, ui_item_local_sublayout(layout, layout, 1)); From 0a26904a75100da3e7084a80a74b1269d95dfa65 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 8 Dec 2016 12:41:27 +0100 Subject: [PATCH 370/590] Fix T49872: 3D cursor places with camera shift in ortographic mode --- .../blender/editors/armature/armature_add.c | 2 +- source/blender/editors/curve/editcurve.c | 2 +- .../blender/editors/curve/editcurve_paint.c | 4 +-- .../blender/editors/gpencil/gpencil_convert.c | 2 +- source/blender/editors/include/ED_view3d.h | 10 +++++-- .../editors/interface/interface_eyedropper.c | 3 +- source/blender/editors/mesh/editmesh_bisect.c | 3 +- .../blender/editors/mesh/editmesh_extrude.c | 4 +-- source/blender/editors/mesh/editmesh_knife.c | 2 +- source/blender/editors/sculpt_paint/sculpt.c | 2 +- .../editors/space_view3d/view3d_edit.c | 8 ++--- .../editors/space_view3d/view3d_project.c | 30 ++++++++++++++----- .../editors/space_view3d/view3d_ruler.c | 2 +- source/blender/editors/transform/transform.c | 2 +- 14 files changed, 49 insertions(+), 27 deletions(-) diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 559d93c7eb1..6228874343b 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -231,7 +231,7 @@ static int armature_click_extrude_invoke(bContext *C, wmOperator *op, const wmEv copy_v3_v3(oldcurs, fp); VECCOPY2D(mval_f, event->mval); - ED_view3d_win_to_3d(ar, fp, mval_f, tvec); + ED_view3d_win_to_3d(v3d, ar, fp, mval_f, tvec); copy_v3_v3(fp, tvec); /* extrude to the where new cursor is and store the operation result */ diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index e40dde24ce2..e9fd5fb5a43 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4993,7 +4993,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) copy_v3_v3(location, ED_view3d_cursor3d_get(vc.scene, vc.v3d)); } - ED_view3d_win_to_3d_int(vc.ar, location, event->mval, location); + ED_view3d_win_to_3d_int(vc.v3d, vc.ar, location, event->mval, location); if (use_proj) { const float mval[2] = {UNPACK2(event->mval)}; diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 2d8fc76ee7e..34e026a3ef4 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -353,7 +353,7 @@ static bool stroke_elem_project_fallback( surface_offset, radius, r_location_world, r_normal_world); if (is_depth_found == false) { - ED_view3d_win_to_3d(cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world); + ED_view3d_win_to_3d(cdd->vc.v3d, cdd->vc.ar, location_fallback_depth, mval_fl, r_location_world); zero_v3(r_normal_local); } mul_v3_m4v3(r_location_local, cdd->vc.obedit->imat, r_location_world); @@ -1135,7 +1135,7 @@ static int curve_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event) const float mval_fl[2] = {UNPACK2(event->mval)}; float center[3]; negate_v3_v3(center, cdd->vc.rv3d->ofs); - ED_view3d_win_to_3d(cdd->vc.ar, center, mval_fl, cdd->prev.location_world); + ED_view3d_win_to_3d(cdd->vc.v3d, cdd->vc.ar, center, mval_fl, cdd->prev.location_world); copy_v3_v3(cdd->prev.location_world_valid, cdd->prev.location_world); } diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index c502ed1aa83..d0f68c4b8f3 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -191,7 +191,7 @@ static void gp_strokepoint_convertcoords( } } - ED_view3d_win_to_3d(ar, fp, mvalf, p3d); + ED_view3d_win_to_3d(v3d, ar, fp, mvalf, p3d); } } diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 48c1e2d1996..79176d9e9cf 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -216,8 +216,14 @@ bool ED_view3d_win_to_ray_ex( const struct ARegion *ar, const struct View3D *v3d, const float mval[2], float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip); void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]); -void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]); -void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]); +void ED_view3d_win_to_3d( + const struct View3D *v3d, const struct ARegion *ar, + const float depth_pt[3], const float mval[2], + float r_out[3]); +void ED_view3d_win_to_3d_int( + const struct View3D *v3d, const struct ARegion *ar, + const float depth_pt[3], const int mval[2], + float r_out[3]); void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac); void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]); void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 5f7a018e4c2..5154a77ad21 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -882,7 +882,6 @@ static void depthdropper_exit(bContext *C, wmOperator *op) */ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, int my, float *r_depth) { - /* we could use some clever */ wmWindow *win = CTX_wm_window(C); ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my); @@ -923,7 +922,7 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx, float co_align[3]; /* quick way to get view-center aligned point */ - ED_view3d_win_to_3d(ar, co, mval_center_fl, co_align); + ED_view3d_win_to_3d(v3d, ar, co, mval_center_fl, co_align); *r_depth = len_v3v3(view_co, co_align); diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c index 0e1ba2b1c25..3a9e278f039 100644 --- a/source/blender/editors/mesh/editmesh_bisect.c +++ b/source/blender/editors/mesh/editmesh_bisect.c @@ -73,6 +73,7 @@ static bool mesh_bisect_interactive_calc( wmGesture *gesture = op->customdata; BisectData *opdata; + View3D *v3d = CTX_wm_view3d(C); ARegion *ar = CTX_wm_region(C); RegionView3D *rv3d = ar->regiondata; @@ -101,7 +102,7 @@ static bool mesh_bisect_interactive_calc( normalize_v3(plane_no); /* not needed but nicer for user */ /* point on plane, can use either start or endpoint */ - ED_view3d_win_to_3d(ar, co_ref, co_a_ss, plane_co); + ED_view3d_win_to_3d(v3d, ar, co_ref, co_a_ss, plane_co); if (opdata->is_first == false) EDBM_redo_state_restore(opdata->mesh_backup, em, false); diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index d4c49833c2c..0f1badd93cd 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -584,7 +584,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w copy_v3_v3(min, cent); mul_m4_v3(vc.obedit->obmat, min); /* view space */ - ED_view3d_win_to_3d_int(vc.ar, min, event->mval, min); + ED_view3d_win_to_3d_int(vc.v3d, vc.ar, min, event->mval, min); mul_m4_v3(vc.obedit->imat, min); // back in object space sub_v3_v3(min, cent); @@ -633,7 +633,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w BMOIter oiter; copy_v3_v3(min, curs); - ED_view3d_win_to_3d_int(vc.ar, min, event->mval, min); + ED_view3d_win_to_3d_int(vc.v3d, vc.ar, min, event->mval, min); invert_m4_m4(vc.obedit->imat, vc.obedit->obmat); mul_m4_v3(vc.obedit->imat, min); // back in object space diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 44453d03ade..bf59693b856 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -971,7 +971,7 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) copy_v3_v3(co_depth, kcd->prev.cage); mul_m4_v3(kcd->ob->obmat, co_depth); - ED_view3d_win_to_3d(kcd->ar, co_depth, kcd->curr.mval, curr_cage_adjust); + ED_view3d_win_to_3d(kcd->vc.v3d, kcd->ar, co_depth, kcd->curr.mval, curr_cage_adjust); mul_m4_v3(kcd->ob->imat, curr_cage_adjust); sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index ef2f2d36ab7..47f0220726b 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -4187,7 +4187,7 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru /* compute 3d coordinate at same z from original location + mouse */ mul_v3_m4v3(loc, ob->obmat, cache->orig_grab_location); - ED_view3d_win_to_3d(cache->vc->ar, loc, mouse, grab_location); + ED_view3d_win_to_3d(cache->vc->v3d, cache->vc->ar, loc, mouse, grab_location); /* compute delta to move verts by */ if (!cache->first_time) { diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 9e41ad6a8f6..080f205b530 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -789,7 +789,7 @@ static void viewops_data_create_ex(bContext *C, wmOperator *op, const wmEvent *e (float)vod->ar->winx / 2.0f, (float)vod->ar->winy / 2.0f}; - ED_view3d_win_to_3d(vod->ar, vod->dyn_ofs, mval_ar_mid, rv3d->ofs); + ED_view3d_win_to_3d(vod->v3d, vod->ar, vod->dyn_ofs, mval_ar_mid, rv3d->ofs); negate_v3(rv3d->ofs); } negate_v3(vod->dyn_ofs); @@ -3289,7 +3289,7 @@ static int viewcenter_pick_invoke(bContext *C, wmOperator *op, const wmEvent *ev else { /* fallback to simple pan */ negate_v3_v3(new_ofs, rv3d->ofs); - ED_view3d_win_to_3d_int(ar, new_ofs, event->mval, new_ofs); + ED_view3d_win_to_3d_int(v3d, ar, new_ofs, event->mval, new_ofs); } negate_v3(new_ofs); ED_view3d_smooth_view( @@ -4708,7 +4708,7 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2]) if (depth_used == false) { float depth_pt[3]; copy_v3_v3(depth_pt, fp); - ED_view3d_win_to_3d_int(ar, depth_pt, mval, fp); + ED_view3d_win_to_3d_int(v3d, ar, depth_pt, mval, fp); } } @@ -4957,7 +4957,7 @@ bool ED_view3d_autodist( } if (fallback_depth_pt) { - ED_view3d_win_to_3d_int(ar, fallback_depth_pt, mval, mouse_worldloc); + ED_view3d_win_to_3d_int(v3d, ar, fallback_depth_pt, mval, mouse_worldloc); return true; } else { diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index 7448d4c658e..65a6dee2f6c 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -28,6 +28,7 @@ * \ingroup spview3d */ +#include "DNA_camera_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_scene_types.h" @@ -40,6 +41,7 @@ #include "BLI_math_vector.h" +#include "BKE_camera.h" #include "BKE_screen.h" #include "ED_view3d.h" /* own include */ @@ -462,9 +464,12 @@ bool view3d_get_view_aligned_coordinate(ARegion *ar, float fp[3], const int mval * \param ar The region (used for the window width and height). * \param depth_pt The reference location used to calculate the Z depth. * \param mval The area relative location (such as event->mval converted to floats). - * \param out The resulting world-space location. + * \param r_out The resulting world-space location. */ -void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]) +void ED_view3d_win_to_3d( + const View3D *v3d, const ARegion *ar, + const float depth_pt[3], const float mval[2], + float r_out[3]) { RegionView3D *rv3d = ar->regiondata; @@ -488,11 +493,19 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float else { float dx = (2.0f * mval[0] / (float)ar->winx) - 1.0f; float dy = (2.0f * mval[1] / (float)ar->winy) - 1.0f; + if (rv3d->persp == RV3D_CAMOB) { /* ortho camera needs offset applied */ + const Camera *cam = v3d->camera->data; + const int sensor_fit = BKE_camera_sensor_fit(cam->sensor_fit, ar->winx, ar->winy); const float zoomfac = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom) * 4.0f; - dx += rv3d->camdx * zoomfac; - dy += rv3d->camdy * zoomfac; + const float aspx = ar->winx / (float)ar->winy; + const float aspy = ar->winy / (float)ar->winx; + const float shiftx = cam->shiftx * 0.5f * (sensor_fit == CAMERA_SENSOR_FIT_HOR ? 1.0f : aspy); + const float shifty = cam->shifty * 0.5f * (sensor_fit == CAMERA_SENSOR_FIT_HOR ? aspx : 1.0f); + + dx += (rv3d->camdx + shiftx) * zoomfac; + dy += (rv3d->camdy + shifty) * zoomfac; } ray_origin[0] = (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0]; ray_origin[1] = (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1]; @@ -502,13 +515,16 @@ void ED_view3d_win_to_3d(const ARegion *ar, const float depth_pt[3], const float lambda = ray_point_factor_v3(depth_pt, ray_origin, ray_direction); } - madd_v3_v3v3fl(out, ray_origin, ray_direction, lambda); + madd_v3_v3v3fl(r_out, ray_origin, ray_direction, lambda); } -void ED_view3d_win_to_3d_int(const ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]) +void ED_view3d_win_to_3d_int( + const View3D *v3d, const ARegion *ar, + const float depth_pt[3], const int mval[2], + float r_out[3]) { const float mval_fl[2] = {mval[0], mval[1]}; - ED_view3d_win_to_3d(ar, depth_pt, mval_fl, out); + ED_view3d_win_to_3d(v3d, ar, depth_pt, mval_fl, r_out); } /** diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 3c13ab9d595..688f459108b 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -700,7 +700,7 @@ static void view3d_ruler_free(RulerInfo *ruler_info) static void view3d_ruler_item_project(RulerInfo *ruler_info, float r_co[3], const int xy[2]) { - ED_view3d_win_to_3d_int(ruler_info->ar, r_co, xy, r_co); + ED_view3d_win_to_3d_int(ruler_info->sa->spacedata.first, ruler_info->ar, r_co, xy, r_co); } /* use for mousemove events */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index d4cd2351f46..20c62e91d01 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -2880,7 +2880,7 @@ static void initBend(TransInfo *t) curs = ED_view3d_cursor3d_get(t->scene, t->view); copy_v3_v3(data->warp_sta, curs); - ED_view3d_win_to_3d(t->ar, curs, mval_fl, data->warp_end); + ED_view3d_win_to_3d(t->sa->spacedata.first, t->ar, curs, mval_fl, data->warp_end); copy_v3_v3(data->warp_nor, t->viewinv[2]); if (t->flag & T_EDIT) { From dd58390d71d7bee96bddded9106099086b078f5d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 8 Sep 2016 17:07:58 +0200 Subject: [PATCH 371/590] Fix emissive volumes generates unexpected fireflies around intersections Discard the whole volume stack on the last bounce (but keep world volume if present). Volumes are expected to be closed manifol meshes, meaning if ray entered the volume there should be an intersection event of ray exisintg the volume. Case when ray hit nothing and there are still non-world volumes in the stack can happen in either of cases. 1. Mesh is not closed manifold. Such configurations are not really supported anyway and should not be used. Previous code would have consider the infinite length of the ray to sample across, so render result wasn't really correct anyway. 2. Exit intersection is more far away than the camera far clip distance. This case also will behave differently now, but previously it wasn't really correct either, so it's not like we're breaking something which was working as expected. 3. We missed exit event due to intersection precision issues. This is exact the case which this patch fixes and avoid fireflies. 4. Volume has Camera only visibility (all the rest visibility is set to off) This is what could be considered a regression but could be solved quite easily by checking volume stack's objects flags and keep entries which doesn't have Volume Scatter visibility (or even better: ensure Volume Scatter visibility for objects with volume closure), Fixes T46108: Cycles - Overlapping emissive volumes generates unexpected bright hotspots around the intersection Also fixes fireflies appearing on the edges of cube with emissive volue. Reviewers: juicyfruit, brecht Reviewed By: brecht Maniphest Tasks: T46108 Differential Revision: https://developer.blender.org/D2212 --- intern/cycles/kernel/kernel_path.h | 8 +++++++ intern/cycles/kernel/kernel_path_branched.h | 4 ++++ intern/cycles/kernel/kernel_volume.h | 26 +++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 6d89a89ed5b..6a36c68d69f 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -141,6 +141,10 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, #endif /* __LAMP_MIS__ */ #ifdef __VOLUME__ + /* Sanitize volume stack. */ + if(!hit) { + kernel_volume_clean_stack(kg, state->volume_stack); + } /* volume attenuation, emission, scatter */ if(state->volume_stack[0].shader != SHADER_NONE) { Ray volume_ray = *ray; @@ -658,6 +662,10 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, #endif /* __LAMP_MIS__ */ #ifdef __VOLUME__ + /* Sanitize volume stack. */ + if(!hit) { + kernel_volume_clean_stack(kg, state.volume_stack); + } /* volume attenuation, emission, scatter */ if(state.volume_stack[0].shader != SHADER_NONE) { Ray volume_ray = ray; diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index c84727ace99..10174e1c4ce 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -294,6 +294,10 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #endif /* __KERNEL_DEBUG__ */ #ifdef __VOLUME__ + /* Sanitize volume stack. */ + if(!hit) { + kernel_volume_clean_stack(kg, state.volume_stack); + } /* volume attenuation, emission, scatter */ if(state.volume_stack[0].shader != SHADER_NONE) { Ray volume_ray = ray; diff --git a/intern/cycles/kernel/kernel_volume.h b/intern/cycles/kernel/kernel_volume.h index a07ce6be077..c7cb29b5af2 100644 --- a/intern/cycles/kernel/kernel_volume.h +++ b/intern/cycles/kernel/kernel_volume.h @@ -1262,4 +1262,30 @@ ccl_device void kernel_volume_stack_update_for_subsurface(KernelGlobals *kg, } #endif +/* Clean stack after the last bounce. + * + * It is expected that all volumes are closed manifolds, so at the time when ray + * hits nothing (for example, it is a last bounce which goes to environment) the + * only expected volume in the stack is the world's one. All the rest volume + * entries should have been exited already. + * + * This isn't always true because of ray intersection precision issues, which + * could lead us to an infinite non-world volume in the stack, causing render + * artifacts. + * + * Use this function after the last bounce to get rid of all volumes apart from + * the world's one after the last bounce to avoid render artifacts. + */ +ccl_device_inline void kernel_volume_clean_stack(KernelGlobals *kg, + VolumeStack *volume_stack) +{ + if(kernel_data.background.volume_shader != SHADER_NONE) { + /* Keep the world's volume in stack. */ + volume_stack[1].shader = SHADER_NONE; + } + else { + volume_stack[0].shader = SHADER_NONE; + } +} + CCL_NAMESPACE_END From 3bd94b9f45e921186352bed9908f5bb851714d4f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 9 Dec 2016 13:05:39 +0100 Subject: [PATCH 372/590] Depsgraph: Bone parent should also include armature transform relation It is required to have world-space bone position, which consists of armature object transform and local bone transform. --- .../intern/builder/deg_builder_relations.cc | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index d9a21d2b888..b5272d3acf2 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -528,8 +528,20 @@ void DepsgraphRelationBuilder::build_object_parent(Object *ob) case PARBONE: /* Bone Parent */ { - ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_BONE, ob->parsubstr); - add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Bone Parent"); + ComponentKey parent_bone_key(&ob->parent->id, + DEPSNODE_TYPE_BONE, + ob->parsubstr); + OperationKey parent_transform_key(&ob->parent->id, + DEPSNODE_TYPE_TRANSFORM, + DEG_OPCODE_TRANSFORM_FINAL); + add_relation(parent_bone_key, + ob_key, + DEPSREL_TYPE_TRANSFORM, + "Bone Parent"); + add_relation(parent_transform_key, + ob_key, + DEPSREL_TYPE_TRANSFORM, + "Armature Parent"); break; } From 1846a7884974a3cde5ce62ee1faaa8295647398d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 9 Dec 2016 13:40:12 +0100 Subject: [PATCH 373/590] Depsgraph: Add missing relation for cast modifier When control object is used we need to known our own transformation as well. --- source/blender/modifiers/intern/MOD_cast.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c index 33e5b3615d9..2fe27730370 100644 --- a/source/blender/modifiers/intern/MOD_cast.c +++ b/source/blender/modifiers/intern/MOD_cast.c @@ -124,12 +124,13 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, static void updateDepsgraph(ModifierData *md, struct Main *UNUSED(bmain), struct Scene *UNUSED(scene), - Object *UNUSED(ob), + Object *object, struct DepsNodeHandle *node) { CastModifierData *cmd = (CastModifierData *)md; if (cmd->object != NULL) { DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier"); + DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "Cast Modifier"); } } From 5a8b5a0377781b5d03b39543a58175d8f4bc2bab Mon Sep 17 00:00:00 2001 From: lazydodo Date: Fri, 9 Dec 2016 08:28:04 -0700 Subject: [PATCH 374/590] Land D2339 by bliblu bli --- intern/cycles/device/device.cpp | 2 ++ intern/cycles/device/device.h | 10 +++++++++- intern/cycles/kernel/kernel_types.h | 3 +++ intern/cycles/render/session.cpp | 1 + intern/cycles/render/shader.cpp | 3 +++ 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index ff9387b0a8a..31c99f49d6d 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -64,6 +64,8 @@ std::ostream& operator <<(std::ostream &os, << string_from_bool(requested_features.use_integrator_branched) << std::endl; os << "Use Patch Evaluation: " << string_from_bool(requested_features.use_patch_evaluation) << std::endl; + os << "Use Transparent Shadows: " + << string_from_bool(requested_features.use_transparent) << std::endl; return os; } diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 988ad10607d..ccee25ae34e 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -117,6 +117,9 @@ public: /* Use OpenSubdiv patch evaluation */ bool use_patch_evaluation; + + /* Use Transparent shadows */ + bool use_transparent; DeviceRequestedFeatures() { @@ -133,6 +136,7 @@ public: use_volume = false; use_integrator_branched = false; use_patch_evaluation = false; + use_transparent = false; } bool modified(const DeviceRequestedFeatures& requested_features) @@ -148,7 +152,8 @@ public: use_subsurface == requested_features.use_subsurface && use_volume == requested_features.use_volume && use_integrator_branched == requested_features.use_integrator_branched && - use_patch_evaluation == requested_features.use_patch_evaluation); + use_patch_evaluation == requested_features.use_patch_evaluation && + use_transparent == requested_features.use_transparent); } /* Convert the requested features structure to a build options, @@ -189,6 +194,9 @@ public: if(!use_patch_evaluation) { build_options += " -D__NO_PATCH_EVAL__"; } + if(!use_transparent) { + build_options += " -D__NO_TRANSPARENT__"; + } return build_options; } }; diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index a6c31d4a518..fd961836ec9 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -192,6 +192,9 @@ CCL_NAMESPACE_BEGIN #ifdef __NO_PATCH_EVAL__ # undef __PATCH_EVAL__ #endif +#ifdef __NO_TRANSPARENT__ +# undef __TRANSPARENT_SHADOWS__ +#endif /* Random Numbers */ diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 8e902243211..33721048722 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -636,6 +636,7 @@ DeviceRequestedFeatures Session::get_requested_device_features() BakeManager *bake_manager = scene->bake_manager; requested_features.use_baking = bake_manager->get_baking(); requested_features.use_integrator_branched = (scene->integrator->method == Integrator::BRANCHED_PATH); + requested_features.use_transparent &= scene->integrator->transparent_shadows; return requested_features; } diff --git a/intern/cycles/render/shader.cpp b/intern/cycles/render/shader.cpp index 06b6dd969d8..335edcbe609 100644 --- a/intern/cycles/render/shader.cpp +++ b/intern/cycles/render/shader.cpp @@ -571,6 +571,9 @@ void ShaderManager::get_requested_graph_features(ShaderGraph *graph, if(node->has_surface_bssrdf()) { requested_features->use_subsurface = true; } + if(node->has_surface_transparent()) { + requested_features->use_transparent = true; + } } } From 2bb7a135aee8b3f60660cef0aa87215e8275f3bb Mon Sep 17 00:00:00 2001 From: Gaia Clary Date: Fri, 9 Dec 2016 17:19:59 +0100 Subject: [PATCH 375/590] Added --debug-io flag to command line --- source/blender/blenkernel/BKE_global.h | 3 ++- source/creator/creator_args.c | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 5ef5a807f63..4bb2b950901 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -129,10 +129,11 @@ enum { G_DEBUG_GPU_MEM = (1 << 10), /* gpu memory in status bar */ G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 11), /* single threaded depsgraph */ G_DEBUG_GPU = (1 << 12), /* gpu debug */ + G_DEBUG_IO = (1 << 13), /* IO Debugging (for Collada, ...)*/ }; #define G_DEBUG_ALL (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \ - G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_GPU_MEM) + G_DEBUG_FREESTYLE | G_DEBUG_DEPSGRAPH | G_DEBUG_GPU_MEM | G_DEBUG_IO) /* G.fileflags */ diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index ab3410d2b7b..9f845d29c18 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -554,6 +554,7 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo BLI_argsPrintArgDoc(ba, "--debug-gpumem"); BLI_argsPrintArgDoc(ba, "--debug-wm"); BLI_argsPrintArgDoc(ba, "--debug-all"); + BLI_argsPrintArgDoc(ba, "--debug-io"); printf("\n"); BLI_argsPrintArgDoc(ba, "--debug-fpe"); @@ -756,6 +757,14 @@ static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUS return 0; } +static const char arg_handle_debug_mode_io_doc[] = +"\n\tEnable debug messages for I/O (collada, ...)"; +static int arg_handle_debug_mode_io(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) +{ + G.debug |= G_DEBUG_IO; + return 0; +} + static const char arg_handle_debug_mode_all_doc[] = "\n\tEnable all debug messages"; static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) @@ -1805,6 +1814,8 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle) CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM); BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL); + BLI_argsAdd(ba, 1, NULL, "--debug-io", CB(arg_handle_debug_mode_io), NULL); + BLI_argsAdd(ba, 1, NULL, "--debug-fpe", CB(arg_handle_debug_fpe_set), NULL); From b21938f3d4cdaae1c8cbddaf5fb97a2eca968609 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 12 Dec 2016 10:19:49 +0100 Subject: [PATCH 376/590] Cycles: Cleanup, variables names Use underscore instead of camel case. --- intern/cycles/kernel/geom/geom_triangle_intersect.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index eb7340583c8..8cd1b1a8897 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -129,10 +129,10 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, const avxf AB = tri_ab - avxf_P; const avxf BC = tri_bc - avxf_P; - const __m256i permuteMask = _mm256_set_epi32(0x3, kz, ky, kx, 0x3, kz, ky, kx); + const __m256i permute_mask = _mm256_set_epi32(0x3, kz, ky, kx, 0x3, kz, ky, kx); - const avxf AB_k = shuffle(AB, permuteMask); - const avxf BC_k = shuffle(BC, permuteMask); + const avxf AB_k = shuffle(AB, permute_mask); + const avxf BC_k = shuffle(BC, permute_mask); /* Akz, Akz, Bkz, Bkz, Bkz, Bkz, Ckz, Ckz */ const avxf ABBC_kz = shuffle<2>(AB_k, BC_k); @@ -155,14 +155,14 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, /* By, Bx, Cy, Cx, By, Bx, Ay, Ax */ const avxf BCBA_yx = permute<3,2,7,6,3,2,1,0>(ABBC_xy); - const avxf negMask(0,0,0,0,0x80000000, 0x80000000, 0x80000000, 0x80000000); + const avxf neg_mask(0,0,0,0,0x80000000, 0x80000000, 0x80000000, 0x80000000); /* W U V * (AxBy-AyBx) (BxCy-ByCx) XX XX (BxBy-ByBx) (CxAy-CyAx) XX XX */ - const avxf WUxxxxVxx_neg = _mm256_hsub_ps(ABBC_xy * BCBA_yx, negMask /* Dont care */); + const avxf WUxxxxVxx_neg = _mm256_hsub_ps(ABBC_xy * BCBA_yx, neg_mask /* Dont care */); - const avxf WUVWnegWUVW = permute<0,1,5,0,0,1,5,0>(WUxxxxVxx_neg) ^ negMask; + const avxf WUVWnegWUVW = permute<0,1,5,0,0,1,5,0>(WUxxxxVxx_neg) ^ neg_mask; /* Calculate scaled barycentric coordinates. */ float WUVW_array[4]; From 968e01d4072459dbb5587cb44f342280e057394d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 12 Dec 2016 12:10:37 +0100 Subject: [PATCH 377/590] Cycles: Cleanup, variable names Use underscore again and also solve confusing part then in BVH smae thing is called prim_addr but in intersection funcitons it was called triAddr. --- .../cycles/kernel/geom/geom_motion_triangle.h | 18 +++++++++--------- .../kernel/geom/geom_triangle_intersect.h | 14 +++++++------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h index 3cbe59aaece..538c332c63a 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -323,11 +323,11 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderD * time and do a ray intersection with the resulting triangle */ ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg, Intersection *isect, - float3 P, float3 dir, float time, uint visibility, int object, int triAddr) + float3 P, float3 dir, float time, uint visibility, int object, int prim_addr) { /* primitive index for vertex location lookup */ - int prim = kernel_tex_fetch(__prim_index, triAddr); - int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, triAddr): object; + int prim = kernel_tex_fetch(__prim_index, prim_addr); + int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; /* get vertex locations for intersection */ float3 verts[3]; @@ -340,13 +340,13 @@ ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg, Intersection #ifdef __VISIBILITY_FLAG__ /* visibility flag test. we do it here under the assumption * that most triangles are culled by node flags */ - if(kernel_tex_fetch(__prim_visibility, triAddr) & visibility) + if(kernel_tex_fetch(__prim_visibility, prim_addr) & visibility) #endif { isect->t = t; isect->u = u; isect->v = v; - isect->prim = triAddr; + isect->prim = prim_addr; isect->object = object; isect->type = PRIMITIVE_MOTION_TRIANGLE; @@ -369,14 +369,14 @@ ccl_device_inline void motion_triangle_intersect_subsurface( float3 dir, float time, int object, - int triAddr, + int prim_addr, float tmax, uint *lcg_state, int max_hits) { /* primitive index for vertex location lookup */ - int prim = kernel_tex_fetch(__prim_index, triAddr); - int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, triAddr): object; + int prim = kernel_tex_fetch(__prim_index, prim_addr); + int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; /* get vertex locations for intersection */ float3 verts[3]; @@ -413,7 +413,7 @@ ccl_device_inline void motion_triangle_intersect_subsurface( isect->t = t; isect->u = u; isect->v = v; - isect->prim = triAddr; + isect->prim = prim_addr; isect->object = object; isect->type = PRIMITIVE_MOTION_TRIANGLE; diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index 8cd1b1a8897..4db121d94f4 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -108,7 +108,7 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, float3 P, uint visibility, int object, - int triAddr) + int prim_addr) { const int kx = isect_precalc->kx; const int ky = isect_precalc->ky; @@ -118,7 +118,7 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, const float Sz = isect_precalc->Sz; /* Calculate vertices relative to ray origin. */ - const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr); + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, prim_addr); #if defined(__KERNEL_AVX2__) && defined(__KERNEL_SSE__) const avxf avxf_P(P.m128, P.m128); @@ -231,7 +231,7 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, #ifdef __VISIBILITY_FLAG__ /* visibility flag test. we do it here under the assumption * that most triangles are culled by node flags */ - if(kernel_tex_fetch(__prim_visibility, triAddr) & visibility) + if(kernel_tex_fetch(__prim_visibility, prim_addr) & visibility) #endif { #ifdef __KERNEL_CUDA__ @@ -241,7 +241,7 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, #endif /* Normalize U, V, W, and T. */ const float inv_det = 1.0f / det; - isect->prim = triAddr; + isect->prim = prim_addr; isect->object = object; isect->type = PRIMITIVE_TRIANGLE; isect->u = U * inv_det; @@ -264,7 +264,7 @@ ccl_device_inline void triangle_intersect_subsurface( SubsurfaceIntersection *ss_isect, float3 P, int object, - int triAddr, + int prim_addr, float tmax, uint *lcg_state, int max_hits) @@ -277,7 +277,7 @@ ccl_device_inline void triangle_intersect_subsurface( const float Sz = isect_precalc->Sz; /* Calculate vertices relative to ray origin. */ - const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr); + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, prim_addr); const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); @@ -415,7 +415,7 @@ ccl_device_inline void triangle_intersect_subsurface( /* record intersection */ Intersection *isect = &ss_isect->hits[hit]; - isect->prim = triAddr; + isect->prim = prim_addr; isect->object = object; isect->type = PRIMITIVE_TRIANGLE; isect->u = U * inv_det; From efadc8051eaca1202d5f7074b8a644b26eb54e75 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 12 Dec 2016 14:31:50 +0100 Subject: [PATCH 378/590] Cleanup: Get rid of ntreeSwitchID(_ex) functions, use generic BKE_libblock_relink_ex instead. --- source/blender/blenkernel/BKE_node.h | 2 -- source/blender/blenkernel/intern/node.c | 27 ------------------------ source/blender/blenkernel/intern/scene.c | 3 ++- 3 files changed, 2 insertions(+), 30 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 95f06e9f695..546f0d97c2b 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -337,8 +337,6 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char void ntreeFreeTree(struct bNodeTree *ntree); struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user); struct bNodeTree *ntreeCopyTree(struct Main *bmain, struct bNodeTree *ntree); -void ntreeSwitchID_ex(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to, const bool do_id_user); -void ntreeSwitchID(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to); /* node->id user count */ void ntreeUserIncrefID(struct bNodeTree *ntree); void ntreeUserDecrefID(struct bNodeTree *ntree); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index a227228ceb5..f16e8f328d4 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1307,33 +1307,6 @@ bNodeTree *ntreeCopyTree(Main *bmain, bNodeTree *ntree) return ntreeCopyTree_ex(ntree, bmain, true); } -/* use when duplicating scenes */ -void ntreeSwitchID_ex(bNodeTree *ntree, ID *id_from, ID *id_to, const bool do_id_user) -{ - bNode *node; - - if (id_from == id_to) { - /* should never happen but may as well skip if it does */ - return; - } - - /* for scene duplication only */ - for (node = ntree->nodes.first; node; node = node->next) { - if (node->id == id_from) { - if (do_id_user) { - id_us_min(id_from); - id_us_plus(id_to); - } - - node->id = id_to; - } - } -} -void ntreeSwitchID(bNodeTree *ntree, ID *id_from, ID *id_to) -{ - ntreeSwitchID_ex(ntree, id_from, id_to, true); -} - void ntreeUserIncrefID(bNodeTree *ntree) { bNode *node; diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a699427315e..091b8100d27 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -78,6 +78,7 @@ #include "BKE_idprop.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_mask.h" @@ -209,7 +210,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) if (sce->nodetree) { /* ID's are managed on both copy and switch */ scen->nodetree = ntreeCopyTree(bmain, sce->nodetree); - ntreeSwitchID(scen->nodetree, &sce->id, &scen->id); + BKE_libblock_relink_ex(bmain, scen->nodetree, &sce->id, &scen->id, false); } obase = sce->base.first; From b708dce34f8caa52efba7ddf7ed00582a36e38f9 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 12 Dec 2016 14:58:10 +0100 Subject: [PATCH 379/590] Cleanup: Rename BKE_libblock_relink, and move it to BKE_library_remap.h Was a waaaaayyyyy to much generic name for such a specific func, renamed to much more descriptive BKE_libblock_relink_to_newid(). In near future (few weeks, to limit as much as possible silent mismatch in branches), will rename BKE_libblock_relink_ex to BKE_libblock_relink, this is the real generic data-block relinking func! --- source/blender/blenkernel/BKE_library.h | 1 - source/blender/blenkernel/BKE_library_remap.h | 1 + source/blender/blenkernel/intern/library.c | 25 ---------------- .../blender/blenkernel/intern/library_remap.c | 29 +++++++++++++++++++ source/blender/editors/object/object_add.c | 7 +++-- .../blender/editors/object/object_relations.c | 3 +- 6 files changed, 36 insertions(+), 30 deletions(-) diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 77ea7ecbefb..2d9c35f7fd0 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -56,7 +56,6 @@ void BKE_libblock_init_empty(struct ID *id); void *BKE_libblock_copy(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL(); void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action); -void BKE_libblock_relink(struct ID *id); void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL(); void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL(); diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h index 89b087014b2..53d438a0fdd 100644 --- a/source/blender/blenkernel/BKE_library_remap.h +++ b/source/blender/blenkernel/BKE_library_remap.h @@ -64,6 +64,7 @@ void BKE_libblock_relink_ex( struct Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) ATTR_NONNULL(1, 2); +void BKE_libblock_relink_to_newid(struct ID *id) ATTR_NONNULL(); typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *); typedef void (*BKE_library_free_notifier_reference_cb)(const void *); diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 31c10c843da..65f37d0a5b1 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1173,31 +1173,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action) return idn; } -static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag) -{ - ID *id = *id_pointer; - if (id) { - /* See: NEW_ID macro */ - if (id->newid) { - BKE_library_update_ID_link_user(id->newid, id, cd_flag); - *id_pointer = id->newid; - } - else if (id->tag & LIB_TAG_NEW) { - id->tag &= ~LIB_TAG_NEW; - BKE_libblock_relink(id); - } - } - return IDWALK_RET_NOP; -} - -void BKE_libblock_relink(ID *id) -{ - if (ID_IS_LINKED_DATABLOCK(id)) - return; - - BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0); -} - void BKE_library_free(Library *lib) { if (lib->packedfile) diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 62f59832481..4f1f6d963ed 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -680,6 +680,35 @@ void BKE_libblock_relink_ex( } } +static int id_relink_to_newid_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag) +{ + ID *id = *id_pointer; + if (id) { + /* See: NEW_ID macro */ + if (id->newid) { + BKE_library_update_ID_link_user(id->newid, id, cd_flag); + *id_pointer = id->newid; + } + else if (id->tag & LIB_TAG_NEW) { + id->tag &= ~LIB_TAG_NEW; + BKE_libblock_relink_to_newid(id); + } + } + return IDWALK_RET_NOP; +} + +/** Similar to libblock_relink_ex, but is remapping IDs to their newid value if non-NULL, in given \a id. + * + * Very specific usage, not sure we'll keep it on the long run, currently only used in Object duplication code... + */ +void BKE_libblock_relink_to_newid(ID *id) +{ + if (ID_IS_LINKED_DATABLOCK(id)) + return; + + BKE_library_foreach_ID_link(id, id_relink_to_newid_looper, NULL, 0); +} + void BKE_libblock_free_data(Main *UNUSED(bmain), ID *id) { if (id->properties) { diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 02dd3ed2df5..f42dafd094c 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -75,6 +75,7 @@ #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_key.h" #include "BKE_main.h" #include "BKE_material.h" @@ -1241,7 +1242,7 @@ static void copy_object_set_idnew(bContext *C) CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - BKE_libblock_relink(&ob->id); + BKE_libblock_relink_to_newid(&ob->id); } CTX_DATA_END; @@ -1395,7 +1396,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, } /* Remap new object to itself, and clear again newid pointer of orig object. */ - BKE_libblock_relink(&ob->id); + BKE_libblock_relink_to_newid(&ob->id); set_sca_new_poins_ob(ob); BKE_id_clear_newpoin(&dob->ob->id); @@ -2219,7 +2220,7 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag ob = basen->object; /* link own references to the newly duplicated data [#26816] */ - BKE_libblock_relink(&ob->id); + BKE_libblock_relink_to_newid(&ob->id); set_sca_new_poins_ob(ob); /* DAG_relations_tag_update(bmain); */ /* caller must do */ diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index d670f4b8425..d30022c01f8 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -76,6 +76,7 @@ #include "BKE_lattice.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" @@ -1806,7 +1807,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in /* object and group pointers */ for (base = FIRSTBASE; base; base = base->next) { - BKE_libblock_relink(&base->object->id); + BKE_libblock_relink_to_newid(&base->object->id); } set_sca_new_poins(); From 62703850ad560b5832c4e42143f563d11ba21cf4 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 12 Dec 2016 15:05:19 +0100 Subject: [PATCH 380/590] Cleanup: Get rid of unused BKE_rigidbody_relink_constraint(). Also use proper ID_NEW_REMAP macro in BKE_rigidbody_world_groups_relink()! --- source/blender/blenkernel/BKE_rigidbody.h | 1 - source/blender/blenkernel/intern/rigidbody.c | 17 ++++------------- 2 files changed, 4 insertions(+), 14 deletions(-) diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h index 272abc42899..965a97f08ba 100644 --- a/source/blender/blenkernel/BKE_rigidbody.h +++ b/source/blender/blenkernel/BKE_rigidbody.h @@ -51,7 +51,6 @@ void BKE_rigidbody_free_constraint(struct Object *ob); struct RigidBodyOb *BKE_rigidbody_copy_object(struct Object *ob); struct RigidBodyCon *BKE_rigidbody_copy_constraint(struct Object *ob); -void BKE_rigidbody_relink_constraint(struct RigidBodyCon *rbc); /* Callback format for performing operations on ID-pointers for rigidbody world. */ typedef void (*RigidbodyWorldIDFunc)(struct RigidBodyWorld *rbw, struct ID **idpoin, void *userdata, int cd_flag); diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 628222ed306..747f5775aff 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -46,6 +46,7 @@ # include "RBI_api.h" #endif +#include "DNA_ID.h" #include "DNA_group_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -222,13 +223,6 @@ RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) return rbcN; } -/* preserve relationships between constraints and rigid bodies after duplication */ -void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) -{ - ID_NEW_REMAP(rbc->ob1); - ID_NEW_REMAP(rbc->ob2); -} - /* ************************************** */ /* Setup Utilities - Validate Sim Instances */ @@ -973,12 +967,9 @@ RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) void BKE_rigidbody_world_groups_relink(RigidBodyWorld *rbw) { - if (rbw->group && rbw->group->id.newid) - rbw->group = (Group *)rbw->group->id.newid; - if (rbw->constraints && rbw->constraints->id.newid) - rbw->constraints = (Group *)rbw->constraints->id.newid; - if (rbw->effector_weights->group && rbw->effector_weights->group->id.newid) - rbw->effector_weights->group = (Group *)rbw->effector_weights->group->id.newid; + ID_NEW_REMAP(rbw->group); + ID_NEW_REMAP(rbw->constraints); + ID_NEW_REMAP(rbw->effector_weights->group); } void BKE_rigidbody_world_id_loop(RigidBodyWorld *rbw, RigidbodyWorldIDFunc func, void *userdata) From 440d1042798113a0e8115ea1f1d016a44712e7a0 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 12 Dec 2016 15:23:55 +0100 Subject: [PATCH 381/590] Refactor RNA property: split flags in property flags, parameter flags, and internal flags. This gives us 9 flags available again for properties (we had none anymore), and also makes things slightly cleaner. To simplify (and make more clear the differences between mere properties and function parameters), also added RNA_def_parameter_flags function (and its clear counterpart), to be used instead of RNA_def_property_flag for function parameters. This patch is also a big cleanup (some RNA function definitions were still using 'prop' PropertyRNA pointer, etc.). And yes, am aware this will be annoying for all branches, but we really need to get new flags available for properties (will need at least one for override, etc.). Reviewers: sergey, Severin Subscribers: dfelinto, brecht Differential Revision: https://developer.blender.org/D2400 --- source/blender/makesrna/RNA_access.h | 3 + source/blender/makesrna/RNA_define.h | 7 +- source/blender/makesrna/RNA_types.h | 47 ++- source/blender/makesrna/intern/makesrna.c | 74 +++-- source/blender/makesrna/intern/rna_ID.c | 8 +- source/blender/makesrna/intern/rna_access.c | 41 ++- source/blender/makesrna/intern/rna_action.c | 22 +- .../makesrna/intern/rna_actuator_api.c | 4 +- .../blender/makesrna/intern/rna_animation.c | 26 +- source/blender/makesrna/intern/rna_armature.c | 17 +- .../makesrna/intern/rna_armature_api.c | 4 +- source/blender/makesrna/intern/rna_color.c | 28 +- source/blender/makesrna/intern/rna_curve.c | 14 +- .../blender/makesrna/intern/rna_curve_api.c | 2 +- source/blender/makesrna/intern/rna_define.c | 43 ++- .../blender/makesrna/intern/rna_depsgraph.c | 4 +- .../makesrna/intern/rna_dynamicpaint.c | 4 +- source/blender/makesrna/intern/rna_fcurve.c | 29 +- .../blender/makesrna/intern/rna_fcurve_api.c | 8 +- source/blender/makesrna/intern/rna_gpencil.c | 28 +- source/blender/makesrna/intern/rna_group.c | 4 +- .../blender/makesrna/intern/rna_image_api.c | 9 +- .../makesrna/intern/rna_internal_types.h | 19 +- source/blender/makesrna/intern/rna_key.c | 6 +- .../blender/makesrna/intern/rna_lattice_api.c | 2 +- .../blender/makesrna/intern/rna_linestyle.c | 32 +- source/blender/makesrna/intern/rna_main_api.c | 278 +++++++++--------- source/blender/makesrna/intern/rna_mask.c | 12 +- source/blender/makesrna/intern/rna_material.c | 4 +- source/blender/makesrna/intern/rna_mesh.c | 25 +- source/blender/makesrna/intern/rna_mesh_api.c | 10 +- source/blender/makesrna/intern/rna_meta.c | 4 +- source/blender/makesrna/intern/rna_meta_api.c | 2 +- source/blender/makesrna/intern/rna_nla.c | 12 +- source/blender/makesrna/intern/rna_nodetree.c | 170 +++++------ source/blender/makesrna/intern/rna_object.c | 43 +-- .../blender/makesrna/intern/rna_object_api.c | 52 ++-- source/blender/makesrna/intern/rna_palette.c | 4 +- source/blender/makesrna/intern/rna_particle.c | 98 +++--- source/blender/makesrna/intern/rna_pose.c | 10 +- source/blender/makesrna/intern/rna_pose_api.c | 2 +- source/blender/makesrna/intern/rna_render.c | 197 +++++++------ .../blender/makesrna/intern/rna_rigidbody.c | 44 ++- source/blender/makesrna/intern/rna_rna.c | 14 +- source/blender/makesrna/intern/rna_scene.c | 43 ++- .../blender/makesrna/intern/rna_scene_api.c | 62 ++-- source/blender/makesrna/intern/rna_screen.c | 12 +- .../blender/makesrna/intern/rna_sensor_api.c | 4 +- .../blender/makesrna/intern/rna_sequencer.c | 8 +- .../makesrna/intern/rna_sequencer_api.c | 68 ++--- source/blender/makesrna/intern/rna_space.c | 10 +- .../blender/makesrna/intern/rna_space_api.c | 8 +- source/blender/makesrna/intern/rna_text_api.c | 6 +- .../blender/makesrna/intern/rna_texture_api.c | 6 +- source/blender/makesrna/intern/rna_tracking.c | 22 +- source/blender/makesrna/intern/rna_ui.c | 44 +-- source/blender/makesrna/intern/rna_ui_api.c | 124 ++++---- source/blender/makesrna/intern/rna_userdef.c | 8 +- source/blender/makesrna/intern/rna_wm_api.c | 106 +++---- source/blender/python/intern/bpy_rna.c | 33 +-- 60 files changed, 1046 insertions(+), 984 deletions(-) diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 44d1a6bfaaf..f97a5735c94 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -793,6 +793,7 @@ PropertyType RNA_property_type(PropertyRNA *prop); PropertySubType RNA_property_subtype(PropertyRNA *prop); PropertyUnit RNA_property_unit(PropertyRNA *prop); int RNA_property_flag(PropertyRNA *prop); +bool RNA_property_builtin(PropertyRNA *prop); void *RNA_property_py_data_get(PropertyRNA *prop); int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop); @@ -1142,6 +1143,8 @@ const struct ListBase *RNA_function_defined_parameters(FunctionRNA *func); /* Utility */ +int RNA_parameter_flag(PropertyRNA *prop); + ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *ptr, FunctionRNA *func); void RNA_parameter_list_free(ParameterList *parms); int RNA_parameter_list_size(ParameterList *parms); diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index bf8ea048fae..2a680b6eaeb 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -137,8 +137,8 @@ void RNA_def_property_enum_bitflag_sdna(PropertyRNA *prop, const char *structnam void RNA_def_property_pointer_sdna(PropertyRNA *prop, const char *structname, const char *propname); void RNA_def_property_collection_sdna(PropertyRNA *prop, const char *structname, const char *propname, const char *lengthpropname); -void RNA_def_property_flag(PropertyRNA *prop, int flag); -void RNA_def_property_clear_flag(PropertyRNA *prop, int flag); +void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag); +void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag); void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype); void RNA_def_property_array(PropertyRNA *prop, int length); void RNA_def_property_multi_array(PropertyRNA *prop, int dimension, const int length[]); @@ -201,6 +201,9 @@ void RNA_def_function_output(FunctionRNA *func, PropertyRNA *ret); void RNA_def_function_flag(FunctionRNA *func, int flag); void RNA_def_function_ui_description(FunctionRNA *func, const char *description); +void RNA_def_parameter_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter); +void RNA_def_parameter_clear_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter); + /* Dynamic Enums * strings are not freed, assumed pointing to static location. */ diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 276531992f9..1a191a68668 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -155,7 +155,8 @@ typedef enum PropertySubType { } PropertySubType; /* Make sure enums are updated with these */ -/* HIGHEST FLAG IN USE: 1 << 31 */ +/* HIGHEST FLAG IN USE: 1 << 31 + * FREE FLAGS: 2, 3, 7, 9, 11, 13, 14, 15, 30 */ typedef enum PropertyFlag { /* editable means the property is editable in the user * interface, properties are editable by default except @@ -185,20 +186,6 @@ typedef enum PropertyFlag { /* do not write in presets */ PROP_SKIP_SAVE = (1 << 28), - /* function parameter flags */ - PROP_REQUIRED = (1 << 2), - PROP_OUTPUT = (1 << 3), - PROP_RNAPTR = (1 << 11), - /* This allows for non-breaking API updates, when adding non-critical new parameter to a callback function. - * This way, old py code defining funcs without that parameter would still work. - * WARNING: any parameter after the first PYFUNC_OPTIONAL one will be considered as optional! - * NOTE: only for input parameters! - */ - PROP_PYFUNC_OPTIONAL = (1 << 30), - /* registering */ - PROP_REGISTER = (1 << 4), - PROP_REGISTER_OPTIONAL = PROP_REGISTER | (1 << 5), - /* numbers */ /* each value is related proportionally (object scale, image size) */ @@ -229,25 +216,37 @@ typedef enum PropertyFlag { /* need context for update function */ PROP_CONTEXT_UPDATE = (1 << 22), - PROP_CONTEXT_PROPERTY_UPDATE = (1 << 22) | (1 << 27), + PROP_CONTEXT_PROPERTY_UPDATE = PROP_CONTEXT_UPDATE | (1 << 27), + + /* registering */ + PROP_REGISTER = (1 << 4), + PROP_REGISTER_OPTIONAL = PROP_REGISTER | (1 << 5), /* Use for arrays or for any data that should not have a reference kept * most common case is functions that return arrays where the array */ PROP_THICK_WRAP = (1 << 23), - /* internal flags */ - PROP_BUILTIN = (1 << 7), - PROP_EXPORT = (1 << 8), - PROP_RUNTIME = (1 << 9), - PROP_IDPROPERTY = (1 << 10), - PROP_RAW_ACCESS = (1 << 13), - PROP_RAW_ARRAY = (1 << 14), - PROP_FREE_POINTERS = (1 << 15), + PROP_EXPORT = (1 << 8), /* XXX Is this still used? makesrna.c seems to ignore it currently... */ + PROP_IDPROPERTY = (1 << 10), /* This is an IDProperty, not a DNA one. */ PROP_DYNAMIC = (1 << 17), /* for dynamic arrays, and retvals of type string */ PROP_ENUM_NO_CONTEXT = (1 << 24), /* for enum that shouldn't be contextual */ PROP_ENUM_NO_TRANSLATE = (1 << 29), /* for enums not to be translated (e.g. renderlayers' names in nodes) */ } PropertyFlag; +/* Function parameters flags. + * WARNING: 16bits only. */ +typedef enum ParameterFlag { + PARM_REQUIRED = (1 << 0), + PARM_OUTPUT = (1 << 1), + PARM_RNAPTR = (1 << 2), + /* This allows for non-breaking API updates, when adding non-critical new parameter to a callback function. + * This way, old py code defining funcs without that parameter would still work. + * WARNING: any parameter after the first PYFUNC_OPTIONAL one will be considered as optional! + * NOTE: only for input parameters! + */ + PARM_PYFUNC_OPTIONAL = (1 << 3), +} ParameterFlag; + struct CollectionPropertyIterator; struct Link; typedef int (*IteratorSkipFunc)(struct CollectionPropertyIterator *iter, void *data); diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 309d39a379f..d5576978e23 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -463,7 +463,7 @@ static const char *rna_parameter_type_name(PropertyRNA *parm) { PointerPropertyRNA *pparm = (PointerPropertyRNA *)parm; - if (parm->flag & PROP_RNAPTR) + if (parm->flag_parameter & PARM_RNAPTR) return "PointerRNA"; else return rna_find_dna_type((const char *)pparm->type); @@ -1409,23 +1409,23 @@ static void rna_set_raw_property(PropertyDefRNA *dp, PropertyRNA *prop) if (STREQ(dp->dnatype, "char")) { prop->rawtype = PROP_RAW_CHAR; - prop->flag |= PROP_RAW_ACCESS; + prop->flag_internal |= PROP_INTERN_RAW_ACCESS; } else if (STREQ(dp->dnatype, "short")) { prop->rawtype = PROP_RAW_SHORT; - prop->flag |= PROP_RAW_ACCESS; + prop->flag_internal |= PROP_INTERN_RAW_ACCESS; } else if (STREQ(dp->dnatype, "int")) { prop->rawtype = PROP_RAW_INT; - prop->flag |= PROP_RAW_ACCESS; + prop->flag_internal |= PROP_INTERN_RAW_ACCESS; } else if (STREQ(dp->dnatype, "float")) { prop->rawtype = PROP_RAW_FLOAT; - prop->flag |= PROP_RAW_ACCESS; + prop->flag_internal |= PROP_INTERN_RAW_ACCESS; } else if (STREQ(dp->dnatype, "double")) { prop->rawtype = PROP_RAW_DOUBLE; - prop->flag |= PROP_RAW_ACCESS; + prop->flag_internal |= PROP_INTERN_RAW_ACCESS; } } @@ -1553,7 +1553,7 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp) if (STREQ((const char *)cprop->next, "rna_iterator_array_next") && STREQ((const char *)cprop->get, "rna_iterator_array_get")) { - prop->flag |= PROP_RAW_ARRAY; + prop->flag_internal |= PROP_INTERN_RAW_ARRAY; } cprop->get = (void *)rna_def_property_get_func(f, srna, prop, dp, (const char *)cprop->get); @@ -1599,8 +1599,9 @@ static void rna_def_property_funcs_header(FILE *f, StructRNA *srna, PropertyDefR prop = dp->prop; - if (prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)) + if (prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN) { return; + } func = rna_alloc_function_name(srna->identifier, rna_safe_id(prop->identifier), ""); @@ -1719,8 +1720,9 @@ static void rna_def_property_funcs_header_cpp(FILE *f, StructRNA *srna, Property prop = dp->prop; - if (prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)) + if (prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN) { return; + } /* disabled for now to avoid msvc compiler error due to large file size */ #if 0 @@ -1822,8 +1824,9 @@ static void rna_def_property_funcs_header_cpp(FILE *f, StructRNA *srna, Property CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)dp->prop; const char *collection_funcs = "DefaultCollectionFunctions"; - if (!(dp->prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)) && cprop->property.srna) + if (!(dp->prop->flag & PROP_IDPROPERTY || dp->prop->flag_internal & PROP_INTERN_BUILTIN) && cprop->property.srna) { collection_funcs = (char *)cprop->property.srna; + } if (cprop->item_type) fprintf(f, "\tCOLLECTION_PROPERTY(%s, %s, %s, %s, %s, %s, %s)", collection_funcs, (const char *)cprop->item_type, srna->identifier, @@ -1879,7 +1882,7 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn WRITE_PARAM("Context C"); for (dp = dfunc->cont.properties.first; dp; dp = dp->next) { - int type, flag, pout; + int type, flag, flag_parameter, pout; const char *ptrstr; if (dp->prop == func->c_ret) @@ -1887,7 +1890,8 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn type = dp->prop->type; flag = dp->prop->flag; - pout = (flag & PROP_OUTPUT); + flag_parameter = dp->prop->flag_parameter; + pout = (flag_parameter & PARM_OUTPUT); if (flag & PROP_DYNAMIC) ptrstr = pout ? "**" : "*"; @@ -1903,7 +1907,7 @@ static void rna_def_struct_function_prototype_cpp(FILE *f, StructRNA *UNUSED(srn WRITE_COMMA; if (flag & PROP_DYNAMIC) - fprintf(f, "int %s%s_len, ", (flag & PROP_OUTPUT) ? "*" : "", dp->prop->identifier); + fprintf(f, "int %s%s_len, ", (flag_parameter & PARM_OUTPUT) ? "*" : "", dp->prop->identifier); if (!(flag & PROP_DYNAMIC) && dp->prop->arraydimension) fprintf(f, "%s %s[%u]", rna_parameter_type_cpp_name(dp->prop), @@ -1941,8 +1945,9 @@ static void rna_def_property_funcs_impl_cpp(FILE *f, StructRNA *srna, PropertyDe prop = dp->prop; - if (prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN)) + if (prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN) { return; + } switch (prop->type) { case PROP_BOOLEAN: @@ -2075,9 +2080,9 @@ static void rna_def_struct_function_call_impl_cpp(FILE *f, StructRNA *srna, Func fprintf(f, "%s_len, ", dp->prop->identifier); if (dp->prop->type == PROP_POINTER) - if ((dp->prop->flag & PROP_RNAPTR) && !(dp->prop->flag & PROP_THICK_WRAP)) + if ((dp->prop->flag_parameter & PARM_RNAPTR) && !(dp->prop->flag & PROP_THICK_WRAP)) fprintf(f, "(::%s *) &%s.ptr", rna_parameter_type_name(dp->prop), rna_safe_id(dp->prop->identifier)); - else if (dp->prop->flag & PROP_OUTPUT) + else if (dp->prop->flag_parameter & PARM_OUTPUT) fprintf(f, "(::%s **) &%s->ptr.data", rna_parameter_type_name(dp->prop), rna_safe_id(dp->prop->identifier)); else fprintf(f, "(::%s *) %s.ptr.data", rna_parameter_type_name(dp->prop), rna_safe_id(dp->prop->identifier)); @@ -2110,7 +2115,7 @@ static void rna_def_struct_function_impl_cpp(FILE *f, StructRNA *srna, FunctionD fprintf(f, "\t\tPointerRNA result;\n"); - if ((dp->prop->flag & PROP_RNAPTR) == 0) { + if ((dp->prop->flag_parameter & PARM_RNAPTR) == 0) { StructRNA *ret_srna = rna_find_struct((const char *) pprop->type); fprintf(f, "\t\t::%s *retdata = ", rna_parameter_type_name(dp->prop)); rna_def_struct_function_call_impl_cpp(f, srna, dfunc); @@ -2221,7 +2226,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA const char *funcname, *valstr; const char *ptrstr; const bool has_data = (dfunc->cont.properties.first != NULL); - int flag, pout, cptr, first; + int flag, flag_parameter, pout, cptr, first; srna = dsrna->srna; func = dfunc->func; @@ -2254,8 +2259,9 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA for (; dparm; dparm = dparm->next) { type = dparm->prop->type; flag = dparm->prop->flag; - pout = (flag & PROP_OUTPUT); - cptr = ((type == PROP_POINTER) && !(flag & PROP_RNAPTR)); + flag_parameter = dparm->prop->flag_parameter; + pout = (flag_parameter & PARM_OUTPUT); + cptr = ((type == PROP_POINTER) && !(flag_parameter & PARM_RNAPTR)); if (dparm->prop == func->c_ret) ptrstr = cptr || dparm->prop->arraydimension ? "*" : ""; @@ -2265,7 +2271,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA /* fixed size arrays and RNA pointers are pre-allocated on the ParameterList stack, pass a pointer to it */ else if (type == PROP_POINTER || dparm->prop->arraydimension) ptrstr = "*"; - else if ((type == PROP_POINTER) && (flag & PROP_RNAPTR) && !(flag & PROP_THICK_WRAP)) + else if ((type == PROP_POINTER) && (flag_parameter & PARM_RNAPTR) && !(flag & PROP_THICK_WRAP)) ptrstr = "*"; /* PROP_THICK_WRAP strings are pre-allocated on the ParameterList stack, * but type name for string props is already (char *), so leave empty */ @@ -2311,8 +2317,9 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA for (; dparm; dparm = dparm->next) { type = dparm->prop->type; flag = dparm->prop->flag; - pout = (flag & PROP_OUTPUT); - cptr = ((type == PROP_POINTER) && !(flag & PROP_RNAPTR)); + flag_parameter = dparm->prop->flag_parameter; + pout = (flag_parameter & PARM_OUTPUT); + cptr = ((type == PROP_POINTER) && !(flag_parameter & PARM_RNAPTR)); if (dparm->prop == func->c_ret) fprintf(f, "\t_retdata = _data;\n"); @@ -2422,7 +2429,7 @@ static void rna_def_function_funcs(FILE *f, StructDefRNA *dsrna, FunctionDefRNA if (func->c_ret) { dparm = rna_find_parameter_def(func->c_ret); - ptrstr = (((dparm->prop->type == PROP_POINTER) && !(dparm->prop->flag & PROP_RNAPTR)) || + ptrstr = (((dparm->prop->type == PROP_POINTER) && !(dparm->prop->flag_parameter & PARM_RNAPTR)) || (dparm->prop->arraydimension)) ? "*" : ""; fprintf(f, "\t*((%s%s %s*)_retdata) = %s;\n", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop), ptrstr, func->c_ret->identifier); @@ -2657,7 +2664,7 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F PropertyDefRNA *dparm; StructDefRNA *dsrna; PropertyType type; - int flag, pout, cptr, first; + int flag, flag_parameter, pout, cptr, first; const char *ptrstr; dsrna = rna_find_struct_def(srna); @@ -2668,7 +2675,7 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F if (dparm->prop == func->c_ret) { if (dparm->prop->arraydimension) fprintf(f, "XXX no array return types yet"); /* XXX not supported */ - else if (dparm->prop->type == PROP_POINTER && !(dparm->prop->flag & PROP_RNAPTR)) + else if (dparm->prop->type == PROP_POINTER && !(dparm->prop->flag_parameter & PARM_RNAPTR)) fprintf(f, "%s%s *", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop)); else fprintf(f, "%s%s ", rna_type_struct(dparm->prop), rna_parameter_type_name(dparm->prop)); @@ -2730,8 +2737,9 @@ static void rna_generate_static_parameter_prototypes(FILE *f, StructRNA *srna, F for (dparm = dfunc->cont.properties.first; dparm; dparm = dparm->next) { type = dparm->prop->type; flag = dparm->prop->flag; - pout = (flag & PROP_OUTPUT); - cptr = ((type == PROP_POINTER) && !(flag & PROP_RNAPTR)); + flag_parameter = dparm->prop->flag_parameter; + pout = (flag_parameter & PARM_OUTPUT); + cptr = ((type == PROP_POINTER) && !(flag_parameter & PARM_RNAPTR)); if (dparm->prop == func->c_ret) continue; @@ -2986,7 +2994,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr else fprintf(f, "NULL,\n"); fprintf(f, "\t%d, ", prop->magic); rna_print_c_string(f, prop->identifier); - fprintf(f, ", %d, ", prop->flag); + fprintf(f, ", %d, %d, %d, ", prop->flag, prop->flag_parameter, prop->flag_internal); rna_print_c_string(f, prop->name); fprintf(f, ",\n\t"); rna_print_c_string(f, prop->description); fprintf(f, ",\n\t"); fprintf(f, "%d, ", prop->icon); @@ -3008,7 +3016,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr rna_function_string(prop->editable), rna_function_string(prop->itemeditable)); - if (prop->flag & PROP_RAW_ACCESS) rna_set_raw_offset(f, srna, prop); + if (prop->flag_internal & PROP_INTERN_RAW_ACCESS) rna_set_raw_offset(f, srna, prop); else fprintf(f, "\t0, -1"); /* our own type - collections/arrays only */ @@ -3796,9 +3804,11 @@ static const char *cpp_classes = "" static int rna_is_collection_prop(PropertyRNA *prop) { - if (!(prop->flag & (PROP_IDPROPERTY | PROP_BUILTIN))) - if (prop->type == PROP_COLLECTION) + if (!(prop->flag & PROP_IDPROPERTY || prop->flag_internal & PROP_INTERN_BUILTIN)) { + if (prop->type == PROP_COLLECTION) { return 1; + } + } return 0; } diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 896d4979089..ee43a619f41 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -840,7 +840,7 @@ static void rna_def_ID_materials(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Add a new material to the data-block"); parm = RNA_def_pointer(func, "material", "Material", "", "Material to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "pop", "rna_IDMaterials_pop_id"); RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN); @@ -1014,7 +1014,7 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_function_ui_description(func, "Replace all usage in the .blend file of this ID by new given one"); RNA_def_function_flag(func, FUNC_USE_MAIN); parm = RNA_def_pointer(func, "new_id", "ID", "", "New ID to use"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); func = RNA_def_function(srna, "make_local", "rna_ID_make_local"); RNA_def_function_ui_description(func, "Make this datablock local, return local one " @@ -1023,14 +1023,14 @@ static void rna_def_ID(BlenderRNA *brna) parm = RNA_def_boolean(func, "clear_proxy", true, "", "Whether to clear proxies (the default behavior, " "note that if object has to be duplicated to be made local, proxies are always cleared)"); - RNA_def_property_flag(parm, PROP_PYFUNC_OPTIONAL); + RNA_def_property_flag(parm, PARM_PYFUNC_OPTIONAL); parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID"); RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one"); parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_int(func, "count", 0, 0, INT_MAX, "", "Number of usages/references of given id by current data-block", 0, INT_MAX); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 6f054e586ec..bb839fd77f8 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -79,9 +79,11 @@ void RNA_init(void) if (!srna->cont.prophash) { srna->cont.prophash = BLI_ghash_str_new("RNA_init gh"); - for (prop = srna->cont.properties.first; prop; prop = prop->next) - if (!(prop->flag & PROP_BUILTIN)) + for (prop = srna->cont.properties.first; prop; prop = prop->next) { + if (!(prop->flag_internal & PROP_INTERN_BUILTIN)) { BLI_ghash_insert(srna->cont.prophash, (void *)prop->identifier, prop); + } + } } } } @@ -824,6 +826,11 @@ int RNA_property_flag(PropertyRNA *prop) return rna_ensure_property(prop)->flag; } +bool RNA_property_builtin(PropertyRNA *prop) +{ + return (rna_ensure_property(prop)->flag_internal & PROP_INTERN_BUILTIN) != 0; +} + void *RNA_property_py_data_get(PropertyRNA *prop) { return prop->py_data; @@ -3107,7 +3114,7 @@ void RNA_property_collection_skip(CollectionPropertyIterator *iter, int num) CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)rna_ensure_property(iter->prop); int i; - if (num > 1 && (iter->idprop || (cprop->property.flag & PROP_RAW_ARRAY))) { + if (num > 1 && (iter->idprop || (cprop->property.flag_internal & PROP_INTERN_RAW_ARRAY))) { /* fast skip for array */ ArrayIterator *internal = &iter->internal.array; @@ -3449,7 +3456,7 @@ int RNA_property_collection_raw_array(PointerRNA *ptr, PropertyRNA *prop, Proper BLI_assert(RNA_property_type(prop) == PROP_COLLECTION); - if (!(prop->flag & PROP_RAW_ARRAY) || !(itemprop->flag & PROP_RAW_ACCESS)) + if (!(prop->flag_internal & PROP_INTERN_RAW_ARRAY) || !(itemprop->flag_internal & PROP_INTERN_RAW_ACCESS)) return 0; RNA_property_collection_begin(ptr, prop, &iter); @@ -5570,15 +5577,16 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr, DynStr *dynstr = BLI_dynstr_new(); char *cstring, *buf; bool first_iter = true; - int flag; + int flag, flag_parameter; RNA_PROP_BEGIN (ptr, propptr, iterprop) { prop = propptr.data; flag = RNA_property_flag(prop); + flag_parameter = RNA_parameter_flag(prop); - if (as_function && (flag & PROP_OUTPUT)) { + if (as_function && (flag_parameter & PARM_OUTPUT)) { continue; } @@ -5592,7 +5600,7 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr, continue; } - if (as_function && (flag & PROP_REQUIRED)) { + if (as_function && (prop->flag_parameter & PARM_REQUIRED)) { /* required args don't have useful defaults */ BLI_dynstr_appendf(dynstr, first_iter ? "%s" : ", %s", arg_name); first_iter = false; @@ -5913,6 +5921,11 @@ const ListBase *RNA_function_defined_parameters(FunctionRNA *func) /* Utility */ +int RNA_parameter_flag(PropertyRNA *prop) +{ + return (int)rna_ensure_property(prop)->flag_parameter; +} + ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSED(ptr), FunctionRNA *func) { PropertyRNA *parm; @@ -5926,7 +5939,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSE for (parm = func->cont.properties.first; parm; parm = parm->next) { alloc_size += rna_parameter_size(parm); - if (parm->flag & PROP_OUTPUT) + if (parm->flag_parameter & PARM_OUTPUT) parms->ret_count++; else parms->arg_count++; @@ -5949,7 +5962,7 @@ ParameterList *RNA_parameter_list_create(ParameterList *parms, PointerRNA *UNUSE data_alloc->array = NULL; } - if (!(parm->flag & PROP_REQUIRED) && !(parm->flag & PROP_DYNAMIC)) { + if (!(parm->flag_parameter & PARM_REQUIRED) && !(parm->flag & PROP_DYNAMIC)) { switch (parm->type) { case PROP_BOOLEAN: if (parm->arraydimension) memcpy(data, ((BoolPropertyRNA *)parm)->defaultarray, size); @@ -6373,7 +6386,7 @@ static int rna_function_parameter_parse(PointerRNA *ptr, PropertyRNA *prop, Prop ptype = RNA_property_pointer_type(ptr, prop); - if (prop->flag & PROP_RNAPTR) { + if (prop->flag_parameter & PARM_RNAPTR) { *((PointerRNA *)dest) = *((PointerRNA *)src); break; } @@ -6443,7 +6456,7 @@ int RNA_function_call_direct_va(bContext *C, ReportList *reports, PointerRNA *pt ParameterIterator iter; PropertyRNA *pret, *parm; PropertyType type; - int i, ofs, flen, flag, len, alen, err = 0; + int i, ofs, flen, flag_parameter, len, alen, err = 0; const char *tid, *fid, *pid = NULL; char ftype; void **retdata = NULL; @@ -6460,20 +6473,20 @@ int RNA_function_call_direct_va(bContext *C, ReportList *reports, PointerRNA *pt for (i = 0, ofs = 0; iter.valid; RNA_parameter_list_next(&iter), i++) { parm = iter.parm; - flag = RNA_property_flag(parm); + flag_parameter = RNA_parameter_flag(parm); if (parm == pret) { retdata = iter.data; continue; } - else if (flag & PROP_OUTPUT) { + else if (flag_parameter & PARM_OUTPUT) { continue; } pid = RNA_property_identifier(parm); if (ofs >= flen || format[ofs] == 'N') { - if (flag & PROP_REQUIRED) { + if (parm->flag_parameter & PARM_REQUIRED) { err = -1; fprintf(stderr, "%s.%s: missing required parameter %s\n", tid, fid, pid); break; diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 3f2c0f3d434..0c4c7ddac81 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -586,7 +586,7 @@ static void rna_def_action_groups(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Action_groups_new"); RNA_def_function_ui_description(func, "Create a new action group and add it to the action"); parm = RNA_def_string(func, "name", "Group", 0, "", "New name for the action group"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "action_group", "ActionGroup", "", "Newly created action group"); RNA_def_function_return(func, parm); @@ -596,8 +596,8 @@ static void rna_def_action_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove action group"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "action_group", "ActionGroup", "", "Action group to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop) @@ -617,7 +617,7 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add an F-Curve to the action"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path to use"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX); RNA_def_string(func, "action_group", NULL, 0, "Action Group", "Acton group to add this F-Curve into"); @@ -630,9 +630,8 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop) "of all F-Curves in the action."); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX); - parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist"); RNA_def_function_return(func, parm); @@ -641,8 +640,8 @@ static void rna_def_action_fcurves(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove action group"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "F-Curve to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop) @@ -661,8 +660,7 @@ static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Action_pose_markers_new"); RNA_def_function_ui_description(func, "Add a pose marker to the action"); parm = RNA_def_string(func, "name", "Marker", 0, NULL, "New name for the marker (not unique)"); - RNA_def_property_flag(parm, PROP_REQUIRED); - + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Newly created marker"); RNA_def_function_return(func, parm); @@ -670,8 +668,8 @@ static void rna_def_action_pose_markers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a timeline marker"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Timeline marker to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "TimelineMarker"); diff --git a/source/blender/makesrna/intern/rna_actuator_api.c b/source/blender/makesrna/intern/rna_actuator_api.c index 4a34961964d..23fdd8a1d5b 100644 --- a/source/blender/makesrna/intern/rna_actuator_api.c +++ b/source/blender/makesrna/intern/rna_actuator_api.c @@ -63,13 +63,13 @@ void RNA_api_actuator(StructRNA *srna) func = RNA_def_function(srna, "link", "rna_Actuator_link"); RNA_def_function_ui_description(func, "Link the actuator to a controller"); parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to link to"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_update(parm, NC_LOGIC, NULL); func = RNA_def_function(srna, "unlink", "rna_Actuator_unlink"); RNA_def_function_ui_description(func, "Unlink the actuator from a controller"); parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to unlink from"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_update(parm, NC_LOGIC, NULL); } diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c index cdbf7582fa7..9adbf5f6b2e 100644 --- a/source/blender/makesrna/intern/rna_animation.c +++ b/source/blender/makesrna/intern/rna_animation.c @@ -693,27 +693,27 @@ static void rna_def_keyingset_info(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_REGISTER); RNA_def_function_return(func, RNA_def_boolean(func, "ok", 1, "", "")); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* iterator */ func = RNA_def_function(srna, "iterator", NULL); RNA_def_function_ui_description(func, "Call generate() on the structs which have properties to be keyframed"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "ks", "KeyingSet", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* generate */ func = RNA_def_function(srna, "generate", NULL); RNA_def_function_ui_description(func, "Add Paths to the Keying Set to keyframe the properties of the given data"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "ks", "KeyingSet", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "data", "AnyType", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); } static void rna_def_keyingset_path(BlenderRNA *brna) @@ -807,11 +807,11 @@ static void rna_def_keyingset_paths(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_return(func, parm); /* ID-block for target */ parm = RNA_def_pointer(func, "target_id", "ID", "Target ID", "ID data-block for the destination"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* rna-path */ /* XXX hopefully this is long enough */ parm = RNA_def_string(func, "data_path", NULL, 256, "Data-Path", "RNA-Path to destination property"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* index (defaults to -1 for entire array) */ RNA_def_int(func, "index", -1, -1, INT_MAX, "Index", "The index of the destination property (i.e. axis of Location/Rotation/etc.), " @@ -829,8 +829,8 @@ static void rna_def_keyingset_paths(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); /* path to remove */ parm = RNA_def_pointer(func, "path", "KeyingSetPath", "Path", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); /* Remove All Paths */ @@ -939,8 +939,8 @@ static void rna_api_animdata_nla_tracks(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_CONTEXT); RNA_def_function_ui_description(func, "Remove a NLA Track"); parm = RNA_def_pointer(func, "track", "NlaTrack", "", "NLA Track to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "NlaTrack"); @@ -979,7 +979,7 @@ static void rna_api_animdata_drivers(BlenderRNA *brna, PropertyRNA *cprop) "of all driver F-Curves."); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX); /* return type */ parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist"); diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c index 5c7f51516cb..07d295c8bbc 100644 --- a/source/blender/makesrna/intern/rna_armature.c +++ b/source/blender/makesrna/intern/rna_armature.c @@ -948,8 +948,7 @@ static void rna_def_armature_edit_bones(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Add a new bone"); parm = RNA_def_string(func, "name", "Object", 0, "", "New name for the bone"); - RNA_def_property_flag(parm, PROP_REQUIRED); - + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "bone", "EditBone", "", "Newly created edit bone"); RNA_def_function_return(func, parm); @@ -960,16 +959,18 @@ static void rna_def_armature_edit_bones(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove an existing bone from the armature"); /* target to remove*/ parm = RNA_def_pointer(func, "bone", "EditBone", "", "EditBone to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_armature(BlenderRNA *brna) { StructRNA *srna; - FunctionRNA *func; PropertyRNA *prop; - + + FunctionRNA *func; + PropertyRNA *parm; + static EnumPropertyItem prop_drawtype_items[] = { {ARM_OCTA, "OCTAHEDRAL", 0, "Octahedral", "Display bones as octahedral shape (default)"}, {ARM_LINE, "STICK", 0, "Stick", "Display bones as simple 2D lines with dots"}, @@ -1005,8 +1006,8 @@ static void rna_def_armature(BlenderRNA *brna) func = RNA_def_function(srna, "transform", "rna_Armature_transform"); RNA_def_function_ui_description(func, "Transform armature bones by a matrix"); - prop = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* Animation Data */ rna_def_animdata_common(srna); diff --git a/source/blender/makesrna/intern/rna_armature_api.c b/source/blender/makesrna/intern/rna_armature_api.c index 1a4a9492543..0616331bc05 100644 --- a/source/blender/makesrna/intern/rna_armature_api.c +++ b/source/blender/makesrna/intern/rna_armature_api.c @@ -67,7 +67,7 @@ void RNA_api_armature_edit_bone(StructRNA *srna) RNA_def_function_ui_description(func, "Align the bone to a localspace roll so the Z axis " "points in the direction of the vector given"); parm = RNA_def_float_vector(func, "vector", 3, NULL, -FLT_MAX, FLT_MAX, "Vector", "", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } void RNA_api_bone(StructRNA *srna) @@ -79,7 +79,7 @@ void RNA_api_bone(StructRNA *srna) RNA_def_function_ui_description(func, "Calculate bone envelope at given point"); parm = RNA_def_float_vector_xyz(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "Position in 3d space to evaluate", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return value */ parm = RNA_def_float(func, "factor", 0, -FLT_MAX, FLT_MAX, "Factor", "Envelope factor", -FLT_MAX, FLT_MAX); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 24f2d8174af..d3cd3d12c4d 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -727,9 +727,9 @@ static void rna_def_curvemap_points_api(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "curvemap_insert"); RNA_def_function_ui_description(func, "Add point to CurveMap"); parm = RNA_def_float(func, "position", 0.0f, -FLT_MAX, FLT_MAX, "Position", "Position to add point", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float(func, "value", 0.0f, -FLT_MAX, FLT_MAX, "Value", "Value of point", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "point", "CurveMapPoint", "", "New point"); RNA_def_function_return(func, parm); @@ -737,8 +737,8 @@ static void rna_def_curvemap_points_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Delete point from CurveMap"); parm = RNA_def_pointer(func, "point", "CurveMapPoint", "", "PointElement to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_curvemap(BlenderRNA *brna) @@ -771,7 +771,7 @@ static void rna_def_curvemap(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Evaluate curve at given location"); parm = RNA_def_float(func, "position", 0.0f, -FLT_MAX, FLT_MAX, "Position", "Position to evaluate curve at", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float(func, "value", 0.0f, -FLT_MAX, FLT_MAX, "Value", "Value of curve at given location", -FLT_MAX, FLT_MAX); RNA_def_function_return(func, parm); } @@ -889,7 +889,7 @@ static void rna_def_color_ramp_element_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add element to ColorRamp"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_float(func, "position", 0.0f, 0.0f, 1.0f, "Position", "Position to add element", 0.0f, 1.0f); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "element", "ColorRampElement", "", "New element"); RNA_def_function_return(func, parm); @@ -898,15 +898,17 @@ static void rna_def_color_ramp_element_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Delete element from ColorRamp"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "element", "ColorRampElement", "", "Element to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_color_ramp(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; static EnumPropertyItem prop_interpolation_items[] = { {COLBAND_INTERP_EASE, "EASE", 0, "Ease", ""}, @@ -974,13 +976,13 @@ static void rna_def_color_ramp(BlenderRNA *brna) func = RNA_def_function(srna, "evaluate", "rna_ColorRamp_eval"); RNA_def_function_ui_description(func, "Evaluate ColorRamp"); - prop = RNA_def_float(func, "position", 1.0f, 0.0f, 1.0f, "Position", "Evaluate ColorRamp at position", 0.0f, 1.0f); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_float(func, "position", 1.0f, 0.0f, 1.0f, "Position", "Evaluate ColorRamp at position", 0.0f, 1.0f); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return */ - prop = RNA_def_float_color(func, "color", 4, NULL, -FLT_MAX, FLT_MAX, "Color", "Color at given position", + parm = RNA_def_float_color(func, "color", 4, NULL, -FLT_MAX, FLT_MAX, "Color", "Color at given position", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); } static void rna_def_histogram(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index 22e45964742..7787533d311 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -1257,8 +1257,8 @@ static void rna_def_curve_spline_points(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a spline from a curve"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "spline", "Spline", "", "The spline to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); #endif } @@ -1285,8 +1285,8 @@ static void rna_def_curve_spline_bezpoints(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a spline from a curve"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "spline", "Spline", "", "The spline to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); #endif } @@ -1307,7 +1307,7 @@ static void rna_def_curve_splines(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Curve_spline_new"); RNA_def_function_ui_description(func, "Add a new spline to the curve"); parm = RNA_def_enum(func, "type", curve_type_items, CU_POLY, "", "type for the new spline"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "spline", "Spline", "", "The newly created spline"); RNA_def_function_return(func, parm); @@ -1315,8 +1315,8 @@ static void rna_def_curve_splines(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a spline from a curve"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "spline", "Spline", "", "The spline to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_Curve_spline_clear"); RNA_def_function_ui_description(func, "Remove all splines from a curve"); diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c index e85511f08e9..b4b3aa84ec5 100644 --- a/source/blender/makesrna/intern/rna_curve_api.c +++ b/source/blender/makesrna/intern/rna_curve_api.c @@ -59,7 +59,7 @@ void RNA_api_curve(StructRNA *srna) func = RNA_def_function(srna, "transform", "rna_Curve_transform"); RNA_def_function_ui_description(func, "Transform curve by a matrix"); parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys"); func = RNA_def_function(srna, "validate_material_indices", "BKE_curve_material_index_validate"); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 7ff4eaea169..dc97d39052b 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -618,7 +618,7 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna) RNA_def_property_free_pointers(prop); - if (prop->flag & PROP_RUNTIME) + if (prop->flag_internal & PROP_INTERN_RUNTIME) rna_freelinkN(&srna->cont.properties, prop); } @@ -630,7 +630,7 @@ void RNA_struct_free(BlenderRNA *brna, StructRNA *srna) RNA_def_property_free_pointers(parm); - if (parm->flag & PROP_RUNTIME) + if (parm->flag_internal & PROP_INTERN_RUNTIME) rna_freelinkN(&func->cont.properties, parm); } @@ -771,7 +771,7 @@ StructRNA *RNA_def_struct_ptr(BlenderRNA *brna, const char *identifier, StructRN else { /* define some builtin properties */ prop = RNA_def_property(&srna->cont, "rna_properties", PROP_COLLECTION, PROP_NONE); - RNA_def_property_flag(prop, PROP_BUILTIN); + prop->flag_internal |= PROP_INTERN_BUILTIN; RNA_def_property_ui_text(prop, "Properties", "RNA property collection"); if (DefRNA.preprocess) { @@ -1097,7 +1097,7 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier break; } case PROP_POINTER: - prop->flag |= PROP_THICK_WRAP; /* needed for default behavior when PROP_RNAPTR is set */ + prop->flag |= PROP_THICK_WRAP; /* needed for default behavior when PARM_RNAPTR is set */ break; case PROP_ENUM: case PROP_COLLECTION: @@ -1189,7 +1189,8 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier } } else { - prop->flag |= PROP_IDPROPERTY | PROP_RUNTIME; + prop->flag |= PROP_IDPROPERTY; + prop->flag_internal |= PROP_INTERN_RUNTIME; #ifdef RNA_RUNTIME if (cont->prophash) BLI_ghash_insert(cont->prophash, (void *)prop->identifier, prop); @@ -1201,16 +1202,28 @@ PropertyRNA *RNA_def_property(StructOrFunctionRNA *cont_, const char *identifier return prop; } -void RNA_def_property_flag(PropertyRNA *prop, int flag) +void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag) { prop->flag |= flag; } -void RNA_def_property_clear_flag(PropertyRNA *prop, int flag) +void RNA_def_property_clear_flag(PropertyRNA *prop, PropertyFlag flag) { prop->flag &= ~flag; } +void RNA_def_parameter_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter) +{ + prop->flag |= flag_property; + prop->flag_parameter |= flag_parameter; +} + +void RNA_def_parameter_clear_flags(PropertyRNA *prop, PropertyFlag flag_property, ParameterFlag flag_parameter) +{ + prop->flag &= ~flag_property; + prop->flag_parameter &= ~flag_parameter; +} + void RNA_def_property_subtype(PropertyRNA *prop, PropertySubType subtype) { prop->subtype = subtype; @@ -3097,7 +3110,7 @@ void RNA_def_function_return(FunctionRNA *func, PropertyRNA *ret) void RNA_def_function_output(FunctionRNA *UNUSED(func), PropertyRNA *ret) { - ret->flag |= PROP_OUTPUT; + ret->flag_parameter |= PARM_OUTPUT; } void RNA_def_function_flag(FunctionRNA *func, int flag) @@ -3149,7 +3162,7 @@ int rna_parameter_size(PropertyRNA *parm) case PROP_POINTER: { #ifdef RNA_RUNTIME - if (parm->flag & PROP_RNAPTR) + if (parm->flag_parameter & PARM_RNAPTR) if (parm->flag & PROP_THICK_WRAP) { return sizeof(PointerRNA); } @@ -3159,7 +3172,7 @@ int rna_parameter_size(PropertyRNA *parm) else return sizeof(void *); #else - if (parm->flag & PROP_RNAPTR) { + if (parm->flag_parameter & PARM_RNAPTR) { if (parm->flag & PROP_THICK_WRAP) { return sizeof(PointerRNA); } @@ -3357,12 +3370,12 @@ void RNA_def_property_duplicate_pointers(StructOrFunctionRNA *cont_, PropertyRNA break; } - prop->flag |= PROP_FREE_POINTERS; + prop->flag_internal |= PROP_INTERN_FREE_POINTERS; } void RNA_def_property_free_pointers(PropertyRNA *prop) { - if (prop->flag & PROP_FREE_POINTERS) { + if (prop->flag_internal & PROP_INTERN_FREE_POINTERS) { int a; if (prop->identifier) @@ -3429,7 +3442,7 @@ static void rna_def_property_free(StructOrFunctionRNA *cont_, PropertyRNA *prop) { ContainerRNA *cont = cont_; - if (prop->flag & PROP_RUNTIME) { + if (prop->flag_internal & PROP_INTERN_RUNTIME) { if (cont->prophash) BLI_ghash_remove(cont->prophash, prop->identifier, NULL, NULL); @@ -3449,7 +3462,7 @@ int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *ide for (prop = cont->properties.first; prop; prop = prop->next) { if (STREQ(prop->identifier, identifier)) { - if (prop->flag & PROP_RUNTIME) { + if (prop->flag_internal & PROP_INTERN_RUNTIME) { rna_def_property_free(cont_, prop); return 1; } @@ -3460,7 +3473,7 @@ int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *ide } return 0; } -#endif +#endif /* RNA_RUNTIME */ const char *RNA_property_typename(PropertyType type) { diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index 8ac1e2acc60..b0e02a4eeb0 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -93,11 +93,11 @@ static void rna_def_depsgraph(BlenderRNA *brna) func = RNA_def_function(srna, "debug_graphviz", "rna_Depsgraph_debug_graphviz"); parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name", "File in which to store graphviz debug output"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "debug_rebuild", "rna_Depsgraph_debug_rebuild"); RNA_def_function_flag(func, FUNC_USE_MAIN); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "debug_stats", "rna_Depsgraph_debug_stats"); RNA_def_function_ui_description(func, "Report the number of elements in the Dependency Graph"); diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c index fc2b028e829..4bb7f3a9ffd 100644 --- a/source/blender/makesrna/intern/rna_dynamicpaint.c +++ b/source/blender/makesrna/intern/rna_dynamicpaint.c @@ -651,9 +651,9 @@ static void rna_def_canvas_surface(BlenderRNA *brna) func = RNA_def_function(srna, "output_exists", "rna_DynamicPaint_is_output_exists"); RNA_def_function_ui_description(func, "Checks if surface output layer of given name exists"); parm = RNA_def_pointer(func, "object", "Object", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_int(func, "index", 0, 0, 1, "Index", "", 0, 1); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_boolean(func, "exists", 0, "", ""); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 1d3b65bb7ba..4acdee490b8 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -1029,7 +1029,7 @@ static void rna_def_fmodifier_envelope_control_points(BlenderRNA *brna, Property RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_float(func, "frame", 0.0f, -FLT_MAX, FLT_MAX, "", "Frame to add this control-point", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "point", "FModifierEnvelopeControlPoint", "", "Newly created control-point"); RNA_def_function_return(func, parm); @@ -1037,7 +1037,7 @@ static void rna_def_fmodifier_envelope_control_points(BlenderRNA *brna, Property RNA_def_function_ui_description(func, "Remove a control-point from an FModifierEnvelope"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "point", "FModifierEnvelopeControlPoint", "", "Control-point to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); } @@ -1554,8 +1554,8 @@ static void rna_def_channeldriver_variables(BlenderRNA *brna, PropertyRNA *cprop RNA_def_function_flag(func, FUNC_USE_REPORTS); /* target to remove */ parm = RNA_def_pointer(func, "variable", "DriverVariable", "", "Variable to remove from the driver"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_channeldriver(BlenderRNA *brna) @@ -1774,15 +1774,15 @@ static void rna_def_fcurve_modifiers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_return(func, parm); /* object to add */ parm = RNA_def_enum(func, "type", rna_enum_fmodifier_type_items, 1, "", "Constraint type to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "remove", "rna_FCurve_modifiers_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a modifier from this F-Curve"); /* modifier to remove */ parm = RNA_def_pointer(func, "modifier", "FModifier", "", "Removed modifier"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } /* fcurve.keyframe_points */ @@ -1809,14 +1809,13 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a keyframe point to a F-Curve"); parm = RNA_def_float(func, "frame", 0.0f, -FLT_MAX, FLT_MAX, "", "X Value of this keyframe point", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float(func, "value", 0.0f, -FLT_MAX, FLT_MAX, "", "Y Value of this keyframe point", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_enum_flag(func, "options", keyframe_flag_items, 0, "", "Keyframe options"); RNA_def_enum(func, "keyframe_type", rna_enum_beztriple_keyframe_type_items, BEZT_KEYTYPE_KEYFRAME, "", "Type of keyframe to insert"); - parm = RNA_def_pointer(func, "keyframe", "Keyframe", "", "Newly created keyframe"); RNA_def_function_return(func, parm); @@ -1828,8 +1827,8 @@ static void rna_def_fcurve_keyframe_points(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove keyframe from an F-Curve"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "keyframe", "Keyframe", "", "Keyframe to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); /* optional */ RNA_def_boolean(func, "fast", 0, "Fast", "Fast keyframe removal to avoid recalculating the curve each time"); } @@ -1961,7 +1960,7 @@ static void rna_def_fcurve(BlenderRNA *brna) RNA_def_function_ui_description(func, "Evaluate F-Curve"); parm = RNA_def_float(func, "frame", 1.0f, -FLT_MAX, FLT_MAX, "Frame", "Evaluate F-Curve at given frame", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return value */ parm = RNA_def_float(func, "value", 0, -FLT_MAX, FLT_MAX, "Value", "Value of F-Curve specific frame", -FLT_MAX, FLT_MAX); RNA_def_function_return(func, parm); @@ -1976,7 +1975,7 @@ static void rna_def_fcurve(BlenderRNA *brna) /* return value */ parm = RNA_def_float_vector(func, "range", 2, NULL, -FLT_MAX, FLT_MAX, "Range", "Min/Max values", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); /* -- auto-flag validity (ensures valid handling for data type) -- */ @@ -1986,7 +1985,7 @@ static void rna_def_fcurve(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "data", "AnyType", "Data", "Data containing the property controlled by given FCurve"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); /* Functions */ diff --git a/source/blender/makesrna/intern/rna_fcurve_api.c b/source/blender/makesrna/intern/rna_fcurve_api.c index 8551ca609f4..d8ed908f2df 100644 --- a/source/blender/makesrna/intern/rna_fcurve_api.c +++ b/source/blender/makesrna/intern/rna_fcurve_api.c @@ -144,9 +144,9 @@ void RNA_api_fcurves(StructRNA *srna) "Convert current FCurve from keyframes to sample points, if necessary"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_int(func, "start", 0, MINAFRAME, MAXFRAME, "Start Frame", "", MINAFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "end", 0, MINAFRAME, MAXFRAME, "End Frame", "", MINAFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "convert_to_keyframes", "rna_FCurve_convert_to_keyframes"); RNA_def_function_ui_description(func, @@ -154,9 +154,9 @@ void RNA_api_fcurves(StructRNA *srna) "if necessary"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_int(func, "start", 0, MINAFRAME, MAXFRAME, "Start Frame", "", MINAFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "end", 0, MINAFRAME, MAXFRAME, "End Frame", "", MINAFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } void RNA_api_drivers(StructRNA *UNUSED(srna)) diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 16aa60e1b91..69ee671901a 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1051,8 +1051,8 @@ static void rna_def_gpencil_strokes_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a grease pencil stroke"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "stroke", "GPencilStroke", "Stroke", "The stroke to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_gpencil_frame(BlenderRNA *brna) @@ -1112,7 +1112,7 @@ static void rna_def_gpencil_frames_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_int(func, "frame_number", 1, MINAFRAME, MAXFRAME, "Frame Number", "The frame on which this sketch appears", MINAFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "frame", "GPencilFrame", "", "The newly created frame"); RNA_def_function_return(func, parm); @@ -1120,13 +1120,13 @@ static void rna_def_gpencil_frames_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a grease pencil frame"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "frame", "GPencilFrame", "Frame", "The frame to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "copy", "rna_GPencil_frame_copy"); RNA_def_function_ui_description(func, "Copy a grease pencil frame"); parm = RNA_def_pointer(func, "source", "GPencilFrame", "Source", "The source frame"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "copy", "GPencilFrame", "", "The newly copied frame"); RNA_def_function_return(func, parm); } @@ -1353,7 +1353,7 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_GPencil_layer_new"); RNA_def_function_ui_description(func, "Add a new grease pencil layer"); parm = RNA_def_string(func, "name", "GPencilLayer", MAX_NAME, "Name", "Name of the layer"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "set_active", true, "Set Active", "Set the newly created layer to the active layer"); parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "The newly created layer"); RNA_def_function_return(func, parm); @@ -1362,8 +1362,8 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a grease pencil layer"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "layer", "GPencilLayer", "", "The layer to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "GPencilLayer"); @@ -1495,8 +1495,8 @@ static void rna_def_gpencil_palettecolors_api(BlenderRNA *brna, PropertyRNA *cpr RNA_def_function_ui_description(func, "Remove a color from the palette"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "color", "GPencilPaletteColor", "", "The color to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "GPencilPaletteColor"); @@ -1556,7 +1556,7 @@ static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_GPencil_palette_new"); RNA_def_function_ui_description(func, "Add a new grease pencil palette"); parm = RNA_def_string(func, "name", "GPencilPalette", MAX_NAME, "Name", "Name of the palette"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "set_active", true, "Set Active", "Activate the newly created palette"); parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The newly created palette"); RNA_def_function_return(func, parm); @@ -1565,8 +1565,8 @@ static void rna_def_gpencil_palettes_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a grease pencil palette"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "palette", "GPencilPalette", "", "The palette to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "GPencilPalette"); diff --git a/source/blender/makesrna/intern/rna_group.c b/source/blender/makesrna/intern/rna_group.c index 47bee589615..aa02a3c159d 100644 --- a/source/blender/makesrna/intern/rna_group.c +++ b/source/blender/makesrna/intern/rna_group.c @@ -95,7 +95,7 @@ static void rna_def_group_objects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add this object to a group"); /* object to add */ parm = RNA_def_pointer(func, "object", "Object", "", "Object to add"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* remove object */ func = RNA_def_function(srna, "unlink", "rna_Group_objects_unlink"); @@ -103,7 +103,7 @@ static void rna_def_group_objects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); /* object to remove */ parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c index 6530e0938f6..344c1781b46 100644 --- a/source/blender/makesrna/intern/rna_image_api.c +++ b/source/blender/makesrna/intern/rna_image_api.c @@ -314,7 +314,7 @@ void RNA_api_image(StructRNA *srna) RNA_def_function_ui_description(func, "Save image to a specific path using a scenes render settings"); RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); parm = RNA_def_string_file_path(func, "filepath", NULL, 0, "", "Save path"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_pointer(func, "scene", "Scene", "", "Scene to take image parameters from"); func = RNA_def_function(srna, "save", "rna_Image_save"); @@ -346,9 +346,9 @@ void RNA_api_image(StructRNA *srna) RNA_def_function_ui_description(func, "Scale the image in pixels"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_int(func, "width", 1, 1, 10000, "", "Width", 1, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "height", 1, 1, 10000, "", "Height", 1, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "gl_touch", "rna_Image_gl_touch"); RNA_def_function_ui_description(func, "Delay the image from being cleaned from the cache due inactivity"); @@ -372,7 +372,6 @@ void RNA_api_image(StructRNA *srna) "The texture minifying function", -INT_MAX, INT_MAX); RNA_def_int(func, "mag", GL_LINEAR, -INT_MAX, INT_MAX, "Magnification", "The texture magnification function", -INT_MAX, INT_MAX); - /* return value */ parm = RNA_def_int(func, "error", 0, -INT_MAX, INT_MAX, "Error", "OpenGL error value", -INT_MAX, INT_MAX); RNA_def_function_return(func, parm); @@ -386,7 +385,7 @@ void RNA_api_image(StructRNA *srna) RNA_def_pointer(func, "image_user", "ImageUser", "", "Image user of the image to get filepath for"); parm = RNA_def_string_file_path(func, "filepath", NULL, FILE_MAX, "File Path", "The resulting filepath from the image and it's user"); - RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */ + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */ RNA_def_function_output(func, parm); func = RNA_def_function(srna, "buffers_free", "rna_Image_buffers_free"); diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index 04b85b8997e..fce81e6967e 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -162,6 +162,10 @@ struct PropertyRNA { const char *identifier; /* various options */ int flag; + /* Function parameters flags. */ + short flag_parameter; + /* Internal ("private") flags. */ + short flag_internal; /* user readable name */ const char *name; @@ -183,7 +187,7 @@ struct PropertyRNA { /* array lengths lengths for all dimensions (when arraydimension > 0) */ unsigned int arraylength[RNA_MAX_ARRAY_DIMENSION]; unsigned int totarraylength; - + /* callback for updates on change */ UpdateFunc update; int noteflag; @@ -209,6 +213,15 @@ struct PropertyRNA { void *py_data; }; +/* internal flags WARNING! 16bits only! */ +typedef enum PropertyFlagIntern { + PROP_INTERN_BUILTIN = (1 << 0), + PROP_INTERN_RUNTIME = (1 << 1), + PROP_INTERN_RAW_ACCESS = (1 << 2), + PROP_INTERN_RAW_ARRAY = (1 << 3), + PROP_INTERN_FREE_POINTERS = (1 << 4), +} PropertyFlagIntern; + /* Property Types */ typedef struct BoolPropertyRNA { @@ -347,7 +360,7 @@ struct StructRNA { * which is useful for subclassing RNA */ void *py_type; void *blender_type; - + /* various options */ int flag; @@ -359,7 +372,7 @@ struct StructRNA { const char *translation_context; /* icon ID */ int icon; - + /* property that defines the name */ PropertyRNA *nameproperty; diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index f20e8fb8ed4..2d669986485 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -748,7 +748,7 @@ static void rna_def_keyblock(BlenderRNA *brna) RNA_def_function_ui_description(func, "Compute local space vertices' normals for this shape key"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE); - RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT); + RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT); RNA_def_property_multi_array(parm, 2, NULL); RNA_def_property_range(parm, -1.0f, 1.0f); RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_vert_len"); @@ -757,7 +757,7 @@ static void rna_def_keyblock(BlenderRNA *brna) RNA_def_function_ui_description(func, "Compute local space faces' normals for this shape key"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE); - RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT); + RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT); RNA_def_property_multi_array(parm, 2, NULL); RNA_def_property_range(parm, -1.0f, 1.0f); RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_poly_len"); @@ -766,7 +766,7 @@ static void rna_def_keyblock(BlenderRNA *brna) RNA_def_function_ui_description(func, "Compute local space face corners' normals for this shape key"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_property(func, "normals", PROP_FLOAT, /* PROP_DIRECTION */ PROP_NONE); - RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT); + RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT); RNA_def_property_multi_array(parm, 2, NULL); RNA_def_property_range(parm, -1.0f, 1.0f); RNA_def_property_dynamic_array_funcs(parm, "rna_KeyBlock_normals_loop_len"); diff --git a/source/blender/makesrna/intern/rna_lattice_api.c b/source/blender/makesrna/intern/rna_lattice_api.c index ed0489db1a2..2ea59d31262 100644 --- a/source/blender/makesrna/intern/rna_lattice_api.c +++ b/source/blender/makesrna/intern/rna_lattice_api.c @@ -57,7 +57,7 @@ void RNA_api_lattice(StructRNA *srna) func = RNA_def_function(srna, "transform", "rna_Lattice_transform"); RNA_def_function_ui_description(func, "Transform lattice by a matrix"); parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys"); } diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index 9b28009d161..622c61beaeb 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -1447,9 +1447,9 @@ static void rna_def_freestyle_color_modifiers(BlenderRNA *brna, PropertyRNA *cpr RNA_def_function_ui_description(func, "Add a color modifier to line style"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "name", "ColorModifier", 0, "", "New name for the color modifier (not unique)"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", rna_enum_linestyle_color_modifier_type_items, 0, "", "Color modifier type to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "modifier", "LineStyleColorModifier", "", "Newly added color modifier"); RNA_def_function_return(func, parm); @@ -1457,8 +1457,8 @@ static void rna_def_freestyle_color_modifiers(BlenderRNA *brna, PropertyRNA *cpr RNA_def_function_ui_description(func, "Remove a color modifier from line style"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "modifier", "LineStyleColorModifier", "", "Color modifier to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cprop) @@ -1476,9 +1476,9 @@ static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cpr RNA_def_function_ui_description(func, "Add a alpha modifier to line style"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "name", "AlphaModifier", 0, "", "New name for the alpha modifier (not unique)"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", rna_enum_linestyle_alpha_modifier_type_items, 0, "", "Alpha modifier type to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "modifier", "LineStyleAlphaModifier", "", "Newly added alpha modifier"); RNA_def_function_return(func, parm); @@ -1486,8 +1486,8 @@ static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cpr RNA_def_function_ui_description(func, "Remove a alpha modifier from line style"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "modifier", "LineStyleAlphaModifier", "", "Alpha modifier to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA *cprop) @@ -1505,10 +1505,10 @@ static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA 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); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); 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); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Newly added thickness modifier"); RNA_def_function_return(func, parm); @@ -1516,8 +1516,8 @@ static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA RNA_def_function_ui_description(func, "Remove a thickness modifier from line style"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Thickness modifier to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *cprop) @@ -1535,10 +1535,10 @@ static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA * 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); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); 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); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Newly added geometry modifier"); RNA_def_function_return(func, parm); @@ -1546,8 +1546,8 @@ static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA * RNA_def_function_ui_description(func, "Remove a geometry modifier from line style"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Geometry modifier to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_linestyle(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 594c1752328..cecdb6bad51 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -553,7 +553,7 @@ void RNA_api_main(StructRNA *UNUSED(srna)) func = RNA_def_function(srna, "add_image", "rna_Main_add_image"); RNA_def_function_ui_description(func, "Add a new image"); parm = RNA_def_string_file_path(func, "filepath", NULL, 0, "", "File path to load image from"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "image", "Image", "", "New image"); RNA_def_function_return(func, parm); #endif @@ -574,7 +574,7 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_cameras_new"); RNA_def_function_ui_description(func, "Add a new camera to the main database"); parm = RNA_def_string(func, "name", "Camera", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block"); RNA_def_function_return(func, parm); @@ -583,15 +583,15 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a camera from the current blendfile"); parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this camera before deleting it " "(WARNING: will also delete objects instancing that camera data)"); func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -613,7 +613,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_scenes_new"); RNA_def_function_ui_description(func, "Add a new scene to the main database"); parm = RNA_def_string(func, "name", "Scene", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "scene", "Scene", "", "New scene data-block"); RNA_def_function_return(func, parm); @@ -622,13 +622,13 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a scene from the current blendfile"); parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this scene before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -651,9 +651,9 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Add a new object to the main database"); parm = RNA_def_string(func, "name", "Object", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "object_data", "ID", "", "Object data or None for an empty object"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block"); @@ -663,13 +663,13 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a object from the current blendfile"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this object before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_objects_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -691,7 +691,7 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_materials_new"); RNA_def_function_ui_description(func, "Add a new material to the main database"); parm = RNA_def_string(func, "name", "Material", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block"); RNA_def_function_return(func, parm); @@ -700,13 +700,13 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a material from the current blendfile"); parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this material before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_materials_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -732,10 +732,10 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_nodetree_new"); RNA_def_function_ui_description(func, "Add a new node tree to the main database"); parm = RNA_def_string(func, "name", "NodeGroup", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", dummy_items, 0, "Type", "The type of node_group to add"); RNA_def_property_enum_funcs(parm, NULL, NULL, "rna_Main_nodetree_type_itemf"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block"); RNA_def_function_return(func, parm); @@ -744,13 +744,13 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a node tree from the current blendfile"); parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this node tree before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -777,7 +777,7 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_meshes_new"); RNA_def_function_ui_description(func, "Add a new mesh to the main database"); parm = RNA_def_string(func, "name", "Mesh", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "mesh", "Mesh", "", "New mesh data-block"); RNA_def_function_return(func, parm); @@ -786,13 +786,13 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a new mesh created from object with modifiers applied"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "object", "Object", "", "Object to create mesh from"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "calc_tessface", true, "Calculate Tessellation", "Calculate tessellation faces"); RNA_def_boolean(func, "calc_undeformed", false, "Calculate Undeformed", "Calculate undeformed vertex coordinates"); parm = RNA_def_pointer(func, "mesh", "Mesh", "", @@ -803,15 +803,15 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile"); parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mesh before deleting it " "(WARNING: will also delete objects instancing that mesh data)"); func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -832,9 +832,9 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_lamps_new"); RNA_def_function_ui_description(func, "Add a new lamp to the main database"); parm = RNA_def_string(func, "name", "Lamp", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", rna_enum_lamp_type_items, 0, "Type", "The type of texture to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block"); RNA_def_function_return(func, parm); @@ -843,15 +843,15 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a lamp from the current blendfile"); parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lamp before deleting it " "(WARNING: will also delete objects instancing that lamp data)"); func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -872,7 +872,7 @@ void RNA_def_main_libraries(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "tag", "rna_Main_libraries_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -893,7 +893,7 @@ void RNA_def_main_screens(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "tag", "rna_Main_screens_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -914,7 +914,7 @@ void RNA_def_main_window_managers(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "tag", "rna_Main_window_managers_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -935,11 +935,11 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_images_new"); RNA_def_function_ui_description(func, "Add a new image to the main database"); parm = RNA_def_string(func, "name", "Image", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "width", 1024, 1, INT_MAX, "", "Width of the image", 1, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "height", 1024, 1, INT_MAX, "", "Height of the image", 1, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "alpha", 0, "Alpha", "Use alpha channel"); RNA_def_boolean(func, "float_buffer", 0, "Float Buffer", "Create an image with floating point color"); RNA_def_boolean(func, "stereo3d", 0, "Stereo 3D", "Create left and right views"); @@ -951,7 +951,7 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Load a new image into the main database"); parm = RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the file to load"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded"); /* return type */ parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block"); @@ -961,13 +961,13 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove an image from the current blendfile"); parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this image before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_images_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -989,7 +989,7 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_lattices_new"); RNA_def_function_ui_description(func, "Add a new lattice to the main database"); parm = RNA_def_string(func, "name", "Lattice", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block"); RNA_def_function_return(func, parm); @@ -998,15 +998,15 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a lattice from the current blendfile"); parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this lattice before deleting it " "(WARNING: will also delete objects instancing that lattice data)"); func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1027,9 +1027,9 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_curves_new"); RNA_def_function_ui_description(func, "Add a new curve to the main database"); parm = RNA_def_string(func, "name", "Curve", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", rna_enum_object_type_curve_items, 0, "Type", "The type of curve to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block"); RNA_def_function_return(func, parm); @@ -1038,15 +1038,15 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a curve from the current blendfile"); parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this curve before deleting it " "(WARNING: will also delete objects instancing that curve data)"); func = RNA_def_function(srna, "tag", "rna_Main_curves_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1067,7 +1067,7 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_metaballs_new"); RNA_def_function_ui_description(func, "Add a new metaball to the main database"); parm = RNA_def_string(func, "name", "MetaBall", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block"); RNA_def_function_return(func, parm); @@ -1076,15 +1076,15 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a metaball from the current blendfile"); parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this metaball before deleting it " "(WARNING: will also delete objects instancing that metaball data)"); func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1106,7 +1106,7 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Load a new font into the main database"); parm = RNA_def_string_file_path(func, "filepath", "File Path", 0, "", "path of the font to load"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded"); /* return type */ parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block"); @@ -1116,13 +1116,13 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a font from the current blendfile"); parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this font before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1143,9 +1143,9 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_textures_new"); RNA_def_function_ui_description(func, "Add a new texture to the main database"); parm = RNA_def_string(func, "name", "Texture", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", rna_enum_texture_type_items, 0, "Type", "The type of texture to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block"); RNA_def_function_return(func, parm); @@ -1154,13 +1154,13 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a texture from the current blendfile"); parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this texture before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_textures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1181,7 +1181,7 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_brushes_new"); RNA_def_function_ui_description(func, "Add a new brush to the main database"); parm = RNA_def_string(func, "name", "Brush", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "mode", rna_enum_object_mode_items, OB_MODE_TEXTURE_PAINT, "", "Paint Mode for the new brush"); /* return type */ parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block"); @@ -1191,13 +1191,13 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a brush from the current blendfile"); parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this brush before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1219,7 +1219,7 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_worlds_new"); RNA_def_function_ui_description(func, "Add a new world to the main database"); parm = RNA_def_string(func, "name", "World", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "world", "World", "", "New world data-block"); RNA_def_function_return(func, parm); @@ -1228,13 +1228,13 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a world from the current blendfile"); parm = RNA_def_pointer(func, "world", "World", "", "World to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this world before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1256,7 +1256,7 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_groups_new"); RNA_def_function_ui_description(func, "Add a new group to the main database"); parm = RNA_def_string(func, "name", "Group", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block"); RNA_def_function_return(func, parm); @@ -1265,13 +1265,13 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a group from the current blendfile"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this group before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1293,7 +1293,7 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_speakers_new"); RNA_def_function_ui_description(func, "Add a new speaker to the main database"); parm = RNA_def_string(func, "name", "Speaker", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block"); RNA_def_function_return(func, parm); @@ -1302,15 +1302,15 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a speaker from the current blendfile"); parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this speaker before deleting it " "(WARNING: will also delete objects instancing that speaker data)"); func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1332,7 +1332,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_texts_new"); RNA_def_function_ui_description(func, "Add a new text to the main database"); parm = RNA_def_string(func, "name", "Text", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block"); RNA_def_function_return(func, parm); @@ -1341,8 +1341,8 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a text from the current blendfile"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this text before deleting it"); /* load func */ @@ -1350,7 +1350,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Add a new text to the main database from a file"); parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_boolean(func, "internal", 0, "Make internal", "Make text file internal after loading"); /* return type */ parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block"); @@ -1358,7 +1358,7 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "tag", "rna_Main_texts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1381,7 +1381,7 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "load", "rna_Main_sounds_load"); RNA_def_function_ui_description(func, "Add a new sound to the main database from a file"); parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded"); /* return type */ parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block"); @@ -1391,13 +1391,13 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a sound from the current blendfile"); parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this sound before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1419,7 +1419,7 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_armatures_new"); RNA_def_function_ui_description(func, "Add a new armature to the main database"); parm = RNA_def_string(func, "name", "Armature", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block"); RNA_def_function_return(func, parm); @@ -1428,15 +1428,15 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a armature from the current blendfile"); parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this armature before deleting it " "(WARNING: will also delete objects instancing that armature data)"); func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1457,7 +1457,7 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_actions_new"); RNA_def_function_ui_description(func, "Add a new action to the main database"); parm = RNA_def_string(func, "name", "Action", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block"); RNA_def_function_return(func, parm); @@ -1466,13 +1466,13 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a action from the current blendfile"); parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this action before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_actions_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1493,7 +1493,7 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_particles_new"); RNA_def_function_ui_description(func, "Add a new particle settings instance to the main database"); parm = RNA_def_string(func, "name", "ParticleSettings", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "New particle settings data-block"); RNA_def_function_return(func, parm); @@ -1502,13 +1502,13 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a particle settings instance from the current blendfile"); parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "Particle Settings to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of those particle settings before deleting them"); func = RNA_def_function(srna, "tag", "rna_Main_particles_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1529,7 +1529,7 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_Main_palettes_new"); RNA_def_function_ui_description(func, "Add a new palette to the main database"); parm = RNA_def_string(func, "name", "Palette", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block"); RNA_def_function_return(func, parm); @@ -1538,13 +1538,13 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a palette from the current blendfile"); parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this palette before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1552,31 +1552,41 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) } void RNA_def_main_cachefiles(BlenderRNA *brna, PropertyRNA *cprop) { + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + PropertyRNA *prop; + RNA_def_property_srna(cprop, "BlendDataCacheFiles"); - StructRNA *srna = RNA_def_struct(brna, "BlendDataCacheFiles", NULL); + srna = RNA_def_struct(brna, "BlendDataCacheFiles", NULL); RNA_def_struct_sdna(srna, "Main"); RNA_def_struct_ui_text(srna, "Main Cache Files", "Collection of cache files"); - FunctionRNA *func = RNA_def_function(srna, "tag", "rna_Main_cachefiles_tag"); - PropertyRNA *parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + func = RNA_def_function(srna, "tag", "rna_Main_cachefiles_tag"); + parm = RNA_def_boolean(func, "value", 0, "Value", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - PropertyRNA *prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_Main_cachefiles_is_updated_get", NULL); } void RNA_def_main_paintcurves(BlenderRNA *brna, PropertyRNA *cprop) { + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + PropertyRNA *prop; + RNA_def_property_srna(cprop, "BlendDataPaintCurves"); - StructRNA *srna = RNA_def_struct(brna, "BlendDataPaintCurves", NULL); + srna = RNA_def_struct(brna, "BlendDataPaintCurves", NULL); RNA_def_struct_sdna(srna, "Main"); RNA_def_struct_ui_text(srna, "Main Paint Curves", "Collection of paint curves"); - FunctionRNA *func = RNA_def_function(srna, "tag", "rna_Main_paintcurves_tag"); - PropertyRNA *parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + func = RNA_def_function(srna, "tag", "rna_Main_paintcurves_tag"); + parm = RNA_def_boolean(func, "value", 0, "Value", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - PropertyRNA *prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); + prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_boolean_funcs(prop, "rna_Main_paintcurves_is_updated_get", NULL); } @@ -1594,12 +1604,12 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "tag", "rna_Main_gpencil_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "new", "BKE_gpencil_data_addnew"); RNA_def_function_flag(func, FUNC_NO_SELF); parm = RNA_def_string(func, "name", "GreasePencil", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block"); RNA_def_function_return(func, parm); @@ -1608,8 +1618,8 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a grease pencil instance from the current blendfile"); parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this grease pencil before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); @@ -1631,14 +1641,14 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "tag", "rna_Main_movieclips_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a movie clip from the current blendfile."); parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this movie clip before deleting it"); /* load func */ @@ -1649,7 +1659,7 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) "(while ``check_existing`` is disabled for consistency with other load functions, " "behavior with multiple movie-clips using the same file may incorrectly generate proxies)"); parm = RNA_def_string_file_path(func, "filepath", "Path", FILE_MAX, "", "path for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "check_existing", false, "", "Using existing data-block if this file is already loaded"); /* return type */ parm = RNA_def_pointer(func, "clip", "MovieClip", "", "New movie clip data-block"); @@ -1674,7 +1684,7 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "tag", "rna_Main_masks_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* new func */ func = RNA_def_function(srna, "new", "rna_Main_mask_new"); @@ -1689,8 +1699,8 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a masks from the current blendfile."); parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this mask before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); @@ -1712,12 +1722,12 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "tag", "rna_Main_linestyle_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "new", "rna_Main_linestyles_new"); RNA_def_function_ui_description(func, "Add a new line style instance to the main database"); parm = RNA_def_string(func, "name", "FreestyleLineStyle", 0, "", "New name for the data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block"); RNA_def_function_return(func, parm); @@ -1726,8 +1736,8 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a line style instance from the current blendfile"); parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); RNA_def_boolean(func, "do_unlink", true, "", "Unlink all usages of this line style before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c index faf36d28ff9..24dfff89832 100644 --- a/source/blender/makesrna/intern/rna_mask.c +++ b/source/blender/makesrna/intern/rna_mask.c @@ -778,8 +778,8 @@ static void rna_def_mask_splines(BlenderRNA *brna) RNA_def_function_ui_description(func, "Remove a spline from a layer"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "spline", "MaskSpline", "", "The spline to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); /* active spline */ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); @@ -818,8 +818,8 @@ static void rna_def_maskSplinePoints(BlenderRNA *brna) RNA_def_function_ui_description(func, "Remove a point from a spline"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "point", "MaskSplinePoint", "", "The point to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_maskSpline(BlenderRNA *brna) @@ -1014,8 +1014,8 @@ static void rna_def_masklayers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove layer from this mask"); parm = RNA_def_pointer(func, "layer", "MaskLayer", "", "Shape to be removed"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); /* clear all layers */ func = RNA_def_function(srna, "clear", "rna_Mask_layers_clear"); diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index 752f406264a..b293f20dd95 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -2163,14 +2163,14 @@ static void rna_def_texture_slots(BlenderRNA *brna, PropertyRNA *cprop, const ch func = RNA_def_function(srna, "create", "rna_mtex_texture_slots_create"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT | FUNC_USE_REPORTS); parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Slot index to initialize", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "mtex", structname, "", "The newly initialized mtex"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "clear", "rna_mtex_texture_slots_clear"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT | FUNC_USE_REPORTS); parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Slot index to clear", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } void rna_def_mtex_common(BlenderRNA *brna, StructRNA *srna, const char *begin, diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 7c66f43fe00..3dc58442851 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -2229,7 +2229,6 @@ static void rna_def_mpolygon(BlenderRNA *brna) func = RNA_def_function(srna, "flip", "rna_MeshPolygon_flip"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Invert winding of this polygon (flip its normal)"); - } /* mesh.loop_uvs */ @@ -2878,7 +2877,7 @@ static void rna_def_tessface_vertex_colors(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a vertex color layer to Mesh"); RNA_def_string(func, "name", "Col", 0, "", "Vertex color name"); parm = RNA_def_pointer(func, "layer", "MeshColorLayer", "", "The newly created layer"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); @@ -2912,14 +2911,14 @@ static void rna_def_loop_colors(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a vertex color layer to Mesh"); RNA_def_string(func, "name", "Col", 0, "", "Vertex color name"); parm = RNA_def_pointer(func, "layer", "MeshLoopColorLayer", "", "The newly created layer"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_Mesh_vertex_color_remove"); RNA_def_function_ui_description(func, "Remove a vertex color layer"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "layer", "MeshLoopColorLayer", "", "The layer to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); @@ -2982,7 +2981,7 @@ static void rna_def_vertex_float_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a float property layer to Mesh"); RNA_def_string(func, "name", "Float Prop", 0, "", "Float property name"); parm = RNA_def_pointer(func, "layer", "MeshVertexFloatPropertyLayer", "", "The newly created layer"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); } @@ -3003,7 +3002,7 @@ static void rna_def_vertex_int_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a integer property layer to Mesh"); RNA_def_string(func, "name", "Int Prop", 0, "", "Int property name"); parm = RNA_def_pointer(func, "layer", "MeshVertexIntPropertyLayer", "", "The newly created layer"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); } @@ -3024,7 +3023,7 @@ static void rna_def_vertex_string_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a string property layer to Mesh"); RNA_def_string(func, "name", "String Prop", 0, "", "String property name"); parm = RNA_def_pointer(func, "layer", "MeshVertexStringPropertyLayer", "", "The newly created layer"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); } @@ -3045,7 +3044,7 @@ static void rna_def_polygon_float_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a float property layer to Mesh"); RNA_def_string(func, "name", "Float Prop", 0, "", "Float property name"); parm = RNA_def_pointer(func, "layer", "MeshPolygonFloatPropertyLayer", "", "The newly created layer"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); } @@ -3066,7 +3065,7 @@ static void rna_def_polygon_int_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a integer property layer to Mesh"); RNA_def_string(func, "name", "Int Prop", 0, "", "Int property name"); parm = RNA_def_pointer(func, "layer", "MeshPolygonIntPropertyLayer", "", "The newly created layer"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); } @@ -3087,7 +3086,7 @@ static void rna_def_polygon_string_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a string property layer to Mesh"); RNA_def_string(func, "name", "String Prop", 0, "", "String property name"); parm = RNA_def_pointer(func, "layer", "MeshPolygonStringPropertyLayer", "", "The newly created layer"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); } @@ -3111,7 +3110,7 @@ static void rna_def_tessface_uv_textures(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a UV tessface-texture layer to Mesh (only for meshes with no polygons)"); RNA_def_string(func, "name", "UVMap", 0, "", "UV map name"); parm = RNA_def_pointer(func, "layer", "MeshTextureFaceLayer", "", "The newly created layer"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); @@ -3147,14 +3146,14 @@ static void rna_def_uv_textures(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a UV map layer to Mesh"); RNA_def_string(func, "name", "UVMap", 0, "", "UV map name"); parm = RNA_def_pointer(func, "layer", "MeshTexturePolyLayer", "", "The newly created layer"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_Mesh_uv_texture_layers_remove"); RNA_def_function_ui_description(func, "Remove a vertex color layer"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "layer", "MeshTexturePolyLayer", "", "The layer to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "MeshTexturePolyLayer"); diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index a3bc21b0170..4a078ef9182 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -221,7 +221,7 @@ void RNA_api_mesh(StructRNA *srna) RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix " "(Warning: inverts normals if matrix is negative)"); parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys"); func = RNA_def_function(srna, "flip_normals", "rna_Mesh_flip_normals"); @@ -264,9 +264,9 @@ void RNA_api_mesh(StructRNA *srna) RNA_def_boolean(func, "use_bitflags", false, "", "Produce bitflags groups instead of simple numeric values"); /* return values */ parm = RNA_def_int_array(func, "poly_groups", 1, NULL, 0, 0, "", "Smooth Groups", 0, 0); - RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_OUTPUT); + RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT); parm = RNA_def_int(func, "groups", 0, 0, INT_MAX, "groups", "Total number of groups", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_OUTPUT); + RNA_def_parameter_flags(parm, 0, PARM_OUTPUT); func = RNA_def_function(srna, "normals_split_custom_set", "rna_Mesh_normals_split_custom_set"); RNA_def_function_ui_description(func, @@ -276,7 +276,7 @@ void RNA_api_mesh(StructRNA *srna) /* TODO, see how array size of 0 works, this shouldnt be used */ parm = RNA_def_float_array(func, "normals", 1, NULL, -1.0f, 1.0f, "", "Normals", 0.0f, 0.0f); RNA_def_property_multi_array(parm, 2, normals_array_dim); - RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_REQUIRED); + RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED); func = RNA_def_function(srna, "normals_split_custom_set_from_vertices", "rna_Mesh_normals_split_custom_set_from_vertices"); @@ -287,7 +287,7 @@ void RNA_api_mesh(StructRNA *srna) /* TODO, see how array size of 0 works, this shouldnt be used */ parm = RNA_def_float_array(func, "normals", 1, NULL, -1.0f, 1.0f, "", "Normals", 0.0f, 0.0f); RNA_def_property_multi_array(parm, 2, normals_array_dim); - RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_REQUIRED); + RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED); func = RNA_def_function(srna, "update", "ED_mesh_update"); RNA_def_boolean(func, "calc_edges", 0, "Calculate Edges", "Force recalculation of edges"); diff --git a/source/blender/makesrna/intern/rna_meta.c b/source/blender/makesrna/intern/rna_meta.c index 9d13bc90e72..91a65c7ccc5 100644 --- a/source/blender/makesrna/intern/rna_meta.c +++ b/source/blender/makesrna/intern/rna_meta.c @@ -280,8 +280,8 @@ static void rna_def_metaball_elements(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove an element from the metaball"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "element", "MetaElement", "", "The element to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_MetaBall_elements_clear"); RNA_def_function_ui_description(func, "Remove all elements from the metaball"); diff --git a/source/blender/makesrna/intern/rna_meta_api.c b/source/blender/makesrna/intern/rna_meta_api.c index 43dca6fe4f1..3d8f375fd88 100644 --- a/source/blender/makesrna/intern/rna_meta_api.c +++ b/source/blender/makesrna/intern/rna_meta_api.c @@ -59,7 +59,7 @@ void RNA_api_meta(StructRNA *srna) func = RNA_def_function(srna, "transform", "rna_Meta_transform"); RNA_def_function_ui_description(func, "Transform meta elements by a matrix"); parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } #endif diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index 55bc40f573c..078f6e237f0 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -508,7 +508,7 @@ static void rna_def_strip_fcurves(BlenderRNA *brna, PropertyRNA *cprop) "of all F-Curves in the NLA strip."); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "F-Curve data path"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX); parm = RNA_def_pointer(func, "fcurve", "FCurve", "", "The found F-Curve, or None if it doesn't exist"); @@ -733,12 +733,12 @@ static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Add a new Action-Clip strip to the track"); parm = RNA_def_string(func, "name", "NlaStrip", 0, "", "Name for the NLA Strips"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "start", 0, INT_MIN, INT_MAX, "Start Frame", "Start frame for this strip", INT_MIN, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "action", "Action", "", "Action to assign to this strip"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "strip", "NlaStrip", "", "New NLA Strip"); RNA_def_function_return(func, parm); @@ -747,8 +747,8 @@ static void rna_api_nlatrack_strips(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a NLA Strip"); parm = RNA_def_pointer(func, "strip", "NlaStrip", "", "NLA Strip to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_nlatrack(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index ada4dec1899..a9e78428212 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4025,7 +4025,9 @@ static void def_sh_tex_wireframe(StructRNA *srna) static void def_sh_tex_pointdensity(StructRNA *srna) { PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; static EnumPropertyItem point_source_items[] = { {SHD_POINTDENSITY_SOURCE_PSYS, "PARTICLE_SYSTEM", 0, "Particle System", @@ -4145,22 +4147,22 @@ static void def_sh_tex_pointdensity(StructRNA *srna) RNA_def_pointer(func, "scene", "Scene", "", ""); RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering"); /* TODO, See how array size of 0 works, this shouldnt be used. */ - prop = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0); - RNA_def_property_flag(prop, PROP_DYNAMIC); - RNA_def_function_output(func, prop); + parm = RNA_def_float_array(func, "rgba_values", 1, NULL, 0, 0, "", "RGBA Values", 0, 0); + RNA_def_parameter_flags(parm, PROP_DYNAMIC, 0); + RNA_def_function_output(func, parm); func = RNA_def_function(srna, "calc_point_density_minmax", "rna_ShaderNodePointDensity_density_minmax"); RNA_def_function_ui_description(func, "Calculate point density"); RNA_def_pointer(func, "scene", "Scene", "", ""); RNA_def_enum(func, "settings", calc_mode_items, 1, "", "Calculate density for rendering"); - prop = RNA_def_property(func, "min", PROP_FLOAT, PROP_COORDS); - RNA_def_property_array(prop, 3); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); - prop = RNA_def_property(func, "max", PROP_FLOAT, PROP_COORDS); - RNA_def_property_array(prop, 3); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); + parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_COORDS); + RNA_def_property_array(parm, 3); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); + parm = RNA_def_property(func, "max", PROP_FLOAT, PROP_COORDS); + RNA_def_property_array(parm, 3); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); } static void def_glossy(StructRNA *srna) @@ -4396,7 +4398,7 @@ static void def_sh_script(StructRNA *srna) func = RNA_def_function(srna, "find_socket", "rna_ShaderNodeScript_find_socket"); RNA_def_function_ui_description(func, "Find a socket by name"); parm = RNA_def_string(func, "name", NULL, 0, "Socket name", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /*parm =*/ RNA_def_boolean(func, "is_output", false, "Output", "Whether the socket is an output"); parm = RNA_def_pointer(func, "result", "NodeSocket", "", ""); RNA_def_function_return(func, parm); @@ -4405,9 +4407,9 @@ static void def_sh_script(StructRNA *srna) RNA_def_function_ui_description(func, "Add a socket socket"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_string(func, "name", NULL, 0, "Name", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", node_socket_type_items, SOCK_FLOAT, "Type", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /*parm =*/ RNA_def_boolean(func, "is_output", false, "Output", "Whether the socket is an output"); parm = RNA_def_pointer(func, "result", "NodeSocket", "", ""); RNA_def_function_return(func, parm); @@ -4416,7 +4418,7 @@ static void def_sh_script(StructRNA *srna) RNA_def_function_ui_description(func, "Remove a socket socket"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_pointer(func, "sock", "NodeSocket", "Socket", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); #endif } @@ -4861,7 +4863,7 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cpr RNA_def_function_ui_description(func, "Add a file slot to this node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS | FUNC_USE_CONTEXT); parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return value */ parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket"); RNA_def_function_return(func, parm); @@ -4874,7 +4876,7 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cpr RNA_def_function_ui_description(func, "Remove a file slot from this node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "The socket to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "clear", "rna_Node_inputs_clear"); RNA_def_function_ui_description(func, "Remove all file slots from this node"); @@ -4884,9 +4886,9 @@ static void rna_def_cmp_output_file_slots_api(BlenderRNA *brna, PropertyRNA *cpr RNA_def_function_ui_description(func, "Move a file slot to another position"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } static void def_cmp_output_file(BlenderRNA *brna, StructRNA *srna) { @@ -6972,29 +6974,29 @@ static void rna_def_node_socket(BlenderRNA *brna) RNA_def_function_ui_description(func, "Draw socket"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "Node"); RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_property(func, "text", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(parm, "Text", "Text label to draw alongside properties"); // RNA_def_property_string_default(parm, ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "draw_color", NULL); RNA_def_function_ui_description(func, "Color of the socket icon"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "Node"); RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f); RNA_def_function_output(func, parm); } @@ -7045,17 +7047,17 @@ static void rna_def_node_socket_interface(BlenderRNA *brna) RNA_def_function_ui_description(func, "Draw template settings"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); func = RNA_def_function(srna, "draw_color", NULL); RNA_def_function_ui_description(func, "Color of the socket icon"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f); RNA_def_function_output(func, parm); @@ -7063,25 +7065,25 @@ static void rna_def_node_socket_interface(BlenderRNA *brna) RNA_def_function_ui_description(func, "Define RNA properties of a socket"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "data_rna_type", "Struct", "Data RNA Type", "RNA type for special socket properties"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "init_socket", NULL); RNA_def_function_ui_description(func, "Initialize a node socket instance"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "node", "Node", "Node", "Node of the socket to initialize"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_pointer(func, "socket", "NodeSocket", "Socket", "Socket to initialize"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "data_path", NULL, 0, "Data Path", "Path to specialized socket data"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "from_socket", NULL); RNA_def_function_ui_description(func, "Setup template parameters from an existing socket"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "node", "Node", "Node", "Node of the original socket"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_pointer(func, "socket", "NodeSocket", "Socket", "Original socket"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); } static void rna_def_node_socket_float(BlenderRNA *brna, const char *idname, const char *interface_idname, PropertySubType subtype) @@ -7416,29 +7418,29 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Draw socket"); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "Node"); RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_property(func, "text", PROP_STRING, PROP_NONE); RNA_def_property_ui_text(parm, "Text", "Text label to draw alongside properties"); // RNA_def_property_string_default(parm, ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "draw_color", "rna_NodeSocketStandard_draw_color"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Color of the socket icon"); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "node", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "Node"); RNA_def_property_ui_text(parm, "Node", "Node the socket belongs to"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f); RNA_def_function_output(func, parm); @@ -7458,17 +7460,17 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Draw template settings"); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); func = RNA_def_function(srna, "draw_color", "rna_NodeSocketInterfaceStandard_draw_color"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Color of the socket icon"); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_float_array(func, "color", 4, default_draw_color, 0.0f, 1.0f, "Color", "", 0.0f, 1.0f); RNA_def_function_output(func, parm); @@ -7550,13 +7552,13 @@ static void rna_def_internal_node(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE); RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", "")); parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "poll_instance", "rna_NodeInternal_poll_instance"); RNA_def_function_ui_description(func, "If non-null output is returned, the node can be added to the tree"); RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", "")); parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* update */ func = RNA_def_function(srna, "update", "rna_NodeInternal_update"); @@ -7568,22 +7570,22 @@ static void rna_def_internal_node(BlenderRNA *brna) RNA_def_function_ui_description(func, "Draw node buttons"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* draw buttons extended */ func = RNA_def_function(srna, "draw_buttons_ext", "rna_NodeInternal_draw_buttons_ext"); RNA_def_function_ui_description(func, "Draw node buttons in the sidebar"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); } static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int in_out) @@ -7606,9 +7608,9 @@ static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int i RNA_def_function_ui_description(func, "Add a socket to this node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS); parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_string(func, "identifier", NULL, MAX_NAME, "Identifier", "Unique socket identifier"); /* return value */ parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "New socket"); @@ -7618,7 +7620,7 @@ static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int i RNA_def_function_ui_description(func, "Remove a socket from this node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "socket", "NodeSocket", "", "The socket to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "clear", clearfunc); RNA_def_function_ui_description(func, "Remove all sockets from this node"); @@ -7628,9 +7630,9 @@ static void rna_def_node_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, int i RNA_def_function_ui_description(func, "Move a socket to another position"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } static void rna_def_node(BlenderRNA *brna) @@ -7781,7 +7783,7 @@ static void rna_def_node(BlenderRNA *brna) RNA_def_function_ui_description(func, "Update after property changes"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); func = RNA_def_function(srna, "is_registered_node_type", "rna_Node_is_registered_node_type"); RNA_def_function_ui_description(func, "True if a registered node type"); @@ -7856,14 +7858,14 @@ static void rna_def_node(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER); RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", "")); parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "poll_instance", NULL); RNA_def_function_ui_description(func, "If non-null output is returned, the node can be added to the tree"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", "")); parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* update */ func = RNA_def_function(srna, "update", NULL); @@ -7875,21 +7877,21 @@ static void rna_def_node(BlenderRNA *brna) RNA_def_function_ui_description(func, "Handle creation of a link to or from the node"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "link", "NodeLink", "Link", "Node link that will be inserted"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* init */ func = RNA_def_function(srna, "init", NULL); RNA_def_function_ui_description(func, "Initialize a new instance of this node"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* copy */ func = RNA_def_function(srna, "copy", NULL); RNA_def_function_ui_description(func, "Initialize a new instance of this node from an existing node"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "node", "Node", "Node", "Existing node to copy"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* free */ func = RNA_def_function(srna, "free", NULL); @@ -7901,29 +7903,29 @@ static void rna_def_node(BlenderRNA *brna) RNA_def_function_ui_description(func, "Draw node buttons"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* draw buttons extended */ func = RNA_def_function(srna, "draw_buttons_ext", NULL); RNA_def_function_ui_description(func, "Draw node buttons in the sidebar"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_property(func, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "UILayout"); RNA_def_property_ui_text(parm, "Layout", "Layout in the UI"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* dynamic label */ func = RNA_def_function(srna, "draw_label", NULL); RNA_def_function_ui_description(func, "Returns a dynamic label string"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_string(func, "label", NULL, MAX_NAME, "Label", ""); - RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */ + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */ RNA_def_function_output(func, parm); } @@ -7990,7 +7992,7 @@ static void rna_def_nodetree_nodes_api(BlenderRNA *brna, PropertyRNA *cprop) * added this here to avoid frequent confusion with API changes from "type" to "bl_idname" */ parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Type of node to add (Warning: should be same as node.bl_idname, not node.type!)"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return value */ parm = RNA_def_pointer(func, "node", "Node", "", "New node"); RNA_def_function_return(func, parm); @@ -7999,8 +8001,8 @@ static void rna_def_nodetree_nodes_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a node from this node tree"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "node", "Node", "", "The node to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_NodeTree_node_clear"); RNA_def_function_ui_description(func, "Remove all nodes from this node tree"); @@ -8029,9 +8031,9 @@ static void rna_def_nodetree_link_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a node link to this node tree"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "input", "NodeSocket", "", "The input socket"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "output", "NodeSocket", "", "The output socket"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); RNA_def_boolean(func, "verify_limits", true, "Verify Limits", "Remove existing links if connection limit is exceeded"); /* return */ parm = RNA_def_pointer(func, "link", "NodeLink", "", "New node link"); @@ -8041,8 +8043,8 @@ static void rna_def_nodetree_link_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "remove a node link from the node tree"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "link", "NodeLink", "", "The node link to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_NodeTree_link_clear"); RNA_def_function_ui_description(func, "remove all node links from the node tree"); @@ -8069,9 +8071,9 @@ static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, RNA_def_function_ui_description(func, "Add a socket to this node tree"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "type", NULL, MAX_NAME, "Type", "Data type"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return value */ parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "New socket"); RNA_def_function_return(func, parm); @@ -8080,7 +8082,7 @@ static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, RNA_def_function_ui_description(func, "Remove a socket from this node tree"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "socket", "NodeSocketInterface", "", "The socket to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "clear", clearfunc); RNA_def_function_ui_description(func, "Remove all sockets from this node tree"); @@ -8089,9 +8091,9 @@ static void rna_def_node_tree_sockets_api(BlenderRNA *brna, PropertyRNA *cprop, func = RNA_def_function(srna, "move", movefunc); RNA_def_function_ui_description(func, "Move a socket to another position"); parm = RNA_def_int(func, "from_index", -1, 0, INT_MAX, "From Index", "Index of the socket to move", 0, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "to_index", -1, 0, INT_MAX, "To Index", "Target index for the socket", 0, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } static void rna_def_nodetree(BlenderRNA *brna) @@ -8179,7 +8181,7 @@ static void rna_def_nodetree(BlenderRNA *brna) func = RNA_def_function(srna, "interface_update", "rna_NodeTree_interface_update"); RNA_def_function_ui_description(func, "Updated node group interface"); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* registration */ prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE); @@ -8208,7 +8210,7 @@ static void rna_def_nodetree(BlenderRNA *brna) RNA_def_function_ui_description(func, "Check visibility in the editor"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); RNA_def_function_return(func, RNA_def_boolean(func, "visible", false, "", "")); /* update */ @@ -8221,7 +8223,7 @@ static void rna_def_nodetree(BlenderRNA *brna) RNA_def_function_ui_description(func, "Get a node tree from the context"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "result_1", "NodeTree", "Node Tree", "Active node tree from context"); RNA_def_function_output(func, parm); parm = RNA_def_pointer(func, "result_2", "ID", "Owner ID", "ID data-block that owns the node tree"); @@ -8325,10 +8327,10 @@ static StructRNA *define_specific_node(BlenderRNA *brna, const char *struct_name RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE); parm = RNA_def_property(func, "index", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(parm, "Index", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_property(func, "result", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "NodeInternalSocketTemplate"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "output_template", "rna_NodeInternal_output_template"); @@ -8336,10 +8338,10 @@ static StructRNA *define_specific_node(BlenderRNA *brna, const char *struct_name RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_SELF_TYPE); parm = RNA_def_property(func, "index", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(parm, "Index", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_property(func, "result", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(parm, "NodeInternalSocketTemplate"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); if (def_func) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 0e735350e05..0cffba47f16 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -1521,6 +1521,7 @@ static void rna_def_vertex_group(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; FunctionRNA *func; + PropertyRNA *parm; static EnumPropertyItem assign_mode_items[] = { {WEIGHT_REPLACE, "REPLACE", 0, "Replace", "Replace"}, @@ -1556,27 +1557,27 @@ static void rna_def_vertex_group(BlenderRNA *brna) RNA_def_function_ui_description(func, "Add vertices to the group"); RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); /* TODO, see how array size of 0 works, this shouldnt be used */ - prop = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0); - RNA_def_property_flag(prop, PROP_DYNAMIC | PROP_REQUIRED); - prop = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_enum(func, "type", assign_mode_items, 0, "", "Vertex assign mode"); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0); + RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED); + parm = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_enum(func, "type", assign_mode_items, 0, "", "Vertex assign mode"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "remove", "rna_VertexGroup_vertex_remove"); RNA_def_function_ui_description(func, "Remove a vertex from the group"); RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); /* TODO, see how array size of 0 works, this shouldnt be used */ - prop = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0); - RNA_def_property_flag(prop, PROP_DYNAMIC | PROP_REQUIRED); + parm = RNA_def_int_array(func, "index", 1, NULL, 0, 0, "", "Index List", 0, 0); + RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_REQUIRED); func = RNA_def_function(srna, "weight", "rna_VertexGroup_weight"); RNA_def_function_ui_description(func, "Get a vertex weight from the group"); RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); - prop = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "The index of the vertex", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f); - RNA_def_function_return(func, prop); + parm = RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "The index of the vertex", 0, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_float(func, "weight", 0, 0.0f, 1.0f, "", "Vertex weight", 0.0f, 1.0f); + RNA_def_function_return(func, parm); } static void rna_def_material_slot(BlenderRNA *brna) @@ -1955,7 +1956,7 @@ static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a new constraint to this object"); /* object to add */ parm = RNA_def_enum(func, "type", rna_enum_constraint_type_items, 1, "", "Constraint type to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "constraint", "Constraint", "", "New constraint"); RNA_def_function_return(func, parm); @@ -1965,8 +1966,8 @@ static void rna_def_object_constraints(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); /* constraint to remove */ parm = RNA_def_pointer(func, "constraint", "Constraint", "", "Removed constraint"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_Object_constraints_clear"); RNA_def_function_ui_description(func, "Remove all constraint from this object"); @@ -2003,10 +2004,10 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Add a new modifier"); parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the modifier"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* modifier to add */ parm = RNA_def_enum(func, "type", rna_enum_object_modifier_type_items, 1, "", "Modifier type to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "modifier", "Modifier", "", "Newly created modifier"); RNA_def_function_return(func, parm); @@ -2017,8 +2018,8 @@ static void rna_def_object_modifiers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove an existing modifier from the object"); /* modifier to remove */ parm = RNA_def_pointer(func, "modifier", "Modifier", "", "Modifier to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); /* clear all modifiers */ func = RNA_def_function(srna, "clear", "rna_Object_modifier_clear"); @@ -2099,8 +2100,8 @@ static void rna_def_object_vertex_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Delete vertex group from object"); parm = RNA_def_pointer(func, "group", "VertexGroup", "", "Vertex group to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_Object_vgroup_clear"); RNA_def_function_ui_description(func, "Delete all vertex groups from object"); diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index b66556109e6..c680abe71a4 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -540,28 +540,28 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_ui_description(func, "Compute the coordinate (and scale for ortho cameras) " "given object should be to 'see' all given coordinates"); parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to get render size information from, if available"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float_array(func, "coordinates", 1, NULL, -FLT_MAX, FLT_MAX, "", "Coordinates to fit in", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_DYNAMIC); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL | PROP_DYNAMIC, PARM_REQUIRED); parm = RNA_def_property(func, "co_return", PROP_FLOAT, PROP_XYZ); RNA_def_property_array(parm, 3); RNA_def_property_ui_text(parm, "", "The location to aim to be able to see all given points"); - RNA_def_property_flag(parm, PROP_OUTPUT); + RNA_def_parameter_flags(parm, 0, PARM_OUTPUT); parm = RNA_def_property(func, "scale_return", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text(parm, "", "The ortho scale to aim to be able to see all given points (if relevant)"); - RNA_def_property_flag(parm, PROP_OUTPUT); + RNA_def_parameter_flags(parm, 0, PARM_OUTPUT); /* mesh */ func = RNA_def_function(srna, "to_mesh", "rna_Object_to_mesh"); RNA_def_function_ui_description(func, "Create a Mesh data-block with modifiers applied"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate modifiers"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_boolean(func, "apply_modifiers", 0, "", "Apply modifiers"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "calc_tessface", true, "Calculate Tessellation", "Calculate tessellation faces"); RNA_def_boolean(func, "calc_undeformed", false, "Calculate Undeformed", "Calculate undeformed vertex coordinates"); parm = RNA_def_pointer(func, "mesh", "Mesh", "", @@ -574,7 +574,7 @@ void RNA_api_object(StructRNA *srna) "be freed manually with free_dupli_list to restore the " "objects real matrix and layers"); parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate duplis"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); RNA_def_enum(func, "settings", dupli_eval_mode_items, 0, "", "Generate texture coordinates for rendering"); RNA_def_function_flag(func, FUNC_USE_REPORTS); @@ -594,15 +594,15 @@ void RNA_api_object(StructRNA *srna) RNA_def_string(func, "name", "Key", 0, "", "Unique name for the new keyblock"); /* optional */ RNA_def_boolean(func, "from_mix", 1, "", "Create new shape from existing mix of shapes"); parm = RNA_def_pointer(func, "key", "ShapeKey", "", "New shape keyblock"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "shape_key_remove", "rna_Object_shape_key_remove"); RNA_def_function_ui_description(func, "Remove a Shape Key from this object"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "key", "ShapeKey", "", "Keyblock to be removed"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); /* Ray Cast */ func = RNA_def_function(srna, "ray_cast", "rna_Object_ray_cast"); @@ -611,9 +611,9 @@ void RNA_api_object(StructRNA *srna) /* ray start and end */ parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_float(func, "distance", BVH_RAYCAST_DIST_MAX, 0.0, BVH_RAYCAST_DIST_MAX, "", "Maximum distance", 0.0, BVH_RAYCAST_DIST_MAX); @@ -622,11 +622,11 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_output(func, parm); parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "The hit location of this ray cast", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal", "The face normal at the ray cast hit location", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0); RNA_def_function_output(func, parm); @@ -638,7 +638,7 @@ void RNA_api_object(StructRNA *srna) /* location of point for test and max distance */ parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* default is sqrt(FLT_MAX) */ RNA_def_float(func, "distance", 1.844674352395373e+19, 0.0, FLT_MAX, "", "Maximum distance", 0.0, FLT_MAX); @@ -647,11 +647,11 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_output(func, parm); parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "The location on the object closest to the point", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal", "The face normal at the closest point", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0); @@ -661,7 +661,7 @@ void RNA_api_object(StructRNA *srna) func = RNA_def_function(srna, "is_visible", "rna_Object_is_visible"); RNA_def_function_ui_description(func, "Determine if object is visible in a given scene"); parm = RNA_def_pointer(func, "scene", "Scene", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_boolean(func, "result", 0, "", "Object visibility"); RNA_def_function_return(func, parm); @@ -669,18 +669,18 @@ void RNA_api_object(StructRNA *srna) func = RNA_def_function(srna, "is_modified", "rna_Object_is_modified"); RNA_def_function_ui_description(func, "Determine if this object is modified from the base mesh data"); parm = RNA_def_pointer(func, "scene", "Scene", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_boolean(func, "result", 0, "", "Object visibility"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "is_deform_modified", "rna_Object_is_deform_modified"); RNA_def_function_ui_description(func, "Determine if this object is modified by a deformation from the base mesh data"); parm = RNA_def_pointer(func, "scene", "Scene", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Modifier settings to apply"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_boolean(func, "result", 0, "", "Object visibility"); RNA_def_function_return(func, parm); @@ -690,10 +690,10 @@ void RNA_api_object(StructRNA *srna) RNA_def_function_ui_description(func, "Returns a string for derived mesh data"); parm = RNA_def_enum(func, "type", mesh_dm_info_items, 0, "", "Modifier settings to apply"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* weak!, no way to return dynamic string type */ parm = RNA_def_string(func, "result", NULL, 16384, "result", ""); - RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */ + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */ RNA_def_function_output(func, parm); #endif /* NDEBUG */ @@ -716,7 +716,7 @@ void RNA_api_object_base(StructRNA *srna) RNA_def_function_ui_description(func, "Sets the object layers from a 3D View (use when adding an object in local view)"); parm = RNA_def_pointer(func, "view", "SpaceView3D", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); } #endif /* RNA_RUNTIME */ diff --git a/source/blender/makesrna/intern/rna_palette.c b/source/blender/makesrna/intern/rna_palette.c index 8cbb57fde2c..4d6b94bf709 100644 --- a/source/blender/makesrna/intern/rna_palette.c +++ b/source/blender/makesrna/intern/rna_palette.c @@ -115,8 +115,8 @@ static void rna_def_palettecolors(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a color from the palette"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "color", "PaletteColor", "", "The color to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_Palette_color_clear"); RNA_def_function_ui_description(func, "Remove all colors from the palette"); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 5e3fa4b467d..362baed1e7c 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -1295,7 +1295,9 @@ static void rna_def_particle_hair_key(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; srna = RNA_def_struct(brna, "ParticleHairKey", NULL); RNA_def_struct_sdna(srna, "HairKey"); @@ -1323,18 +1325,16 @@ static void rna_def_particle_hair_key(BlenderRNA *brna) /* Aided co func */ func = RNA_def_function(srna, "co_object", "rna_ParticleHairKey_co_object"); RNA_def_function_ui_description(func, "Obtain hairkey location with particle and modifier data"); - - prop = RNA_def_pointer(func, "object", "Object", "", "Object"); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); - prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); - prop = RNA_def_pointer(func, "particle", "Particle", "", "hair particle"); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); - - prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co", + parm = RNA_def_pointer(func, "object", "Object", "", "Object"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_pointer(func, "particle", "Particle", "", "hair particle"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co", "Exported hairkey location", -1e4, 1e4); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); } static void rna_def_particle_key(BlenderRNA *brna) @@ -1386,7 +1386,9 @@ static void rna_def_particle(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; static EnumPropertyItem alive_items[] = { /*{PARS_KILLED, "KILLED", 0, "Killed", ""}, */ @@ -1496,12 +1498,12 @@ static void rna_def_particle(BlenderRNA *brna) func = RNA_def_function(srna, "uv_on_emitter", "rna_Particle_uv_on_emitter"); RNA_def_function_ui_description(func, "Obtain uv for particle on derived mesh"); RNA_def_function_flag(func, FUNC_USE_REPORTS); - prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); - prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS); - RNA_def_property_array(prop, 2); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); + parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS); + RNA_def_property_array(parm, 2); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); } static void rna_def_particle_dupliweight(BlenderRNA *brna) @@ -3194,7 +3196,9 @@ static void rna_def_particle_system(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; static EnumPropertyItem resolution_items[] = { {eModifierMode_Realtime, "PREVIEW", 0, "Preview", "Apply modifier preview settings"}, @@ -3503,53 +3507,51 @@ static void rna_def_particle_system(BlenderRNA *brna) /* set viewport or render resolution */ func = RNA_def_function(srna, "set_resolution", "rna_ParticleSystem_set_resolution"); RNA_def_function_ui_description(func, "Set the resolution to use for the number of particles"); - prop = RNA_def_pointer(func, "scene", "Scene", "", "Scene"); - prop = RNA_def_pointer(func, "object", "Object", "", "Object"); - prop = RNA_def_enum(func, "resolution", resolution_items, 0, "", "Resolution settings to apply"); + RNA_def_pointer(func, "scene", "Scene", "", "Scene"); + RNA_def_pointer(func, "object", "Object", "", "Object"); + RNA_def_enum(func, "resolution", resolution_items, 0, "", "Resolution settings to apply"); /* extract cached hair location data */ func = RNA_def_function(srna, "co_hair", "rna_ParticleSystem_co_hair"); RNA_def_function_ui_description(func, "Obtain cache hair data"); - - prop = RNA_def_pointer(func, "object", "Object", "", "Object"); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); - prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); - prop = RNA_def_int(func, "step", 0, INT_MIN, INT_MAX, "step no", "", INT_MIN, INT_MAX); - - prop = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co", + parm = RNA_def_pointer(func, "object", "Object", "", "Object"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); + RNA_def_int(func, "step", 0, INT_MIN, INT_MAX, "step no", "", INT_MIN, INT_MAX); + parm = RNA_def_float_vector(func, "co", 3, NULL, -FLT_MAX, FLT_MAX, "Co", "Exported hairkey location", -1e4, 1e4); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); /* extract hair UVs */ func = RNA_def_function(srna, "uv_on_emitter", "rna_ParticleSystem_uv_on_emitter"); RNA_def_function_ui_description(func, "Obtain uv for all particles"); RNA_def_function_flag(func, FUNC_USE_REPORTS); - prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); + parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle"); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); - prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); - prop = RNA_def_int(func, "uv_no", 0, INT_MIN, INT_MAX, "UV no", "", INT_MIN, INT_MAX); - prop = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS); - RNA_def_property_array(prop, 2); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); + RNA_def_int(func, "uv_no", 0, INT_MIN, INT_MAX, "UV no", "", INT_MIN, INT_MAX); + parm = RNA_def_property(func, "uv", PROP_FLOAT, PROP_COORDS); + RNA_def_property_array(parm, 2); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); /* extract hair mcols */ func = RNA_def_function(srna, "mcol_on_emitter", "rna_ParticleSystem_mcol_on_emitter"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Obtain mcol for all particles"); - prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); - prop = RNA_def_pointer(func, "particle", "Particle", "", "Particle"); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); - prop = RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); - prop = RNA_def_int(func, "vcol_no", 0, INT_MIN, INT_MAX, "vcol no", "", INT_MIN, INT_MAX); - prop = RNA_def_property(func, "mcol", PROP_FLOAT, PROP_COLOR); - RNA_def_property_array(prop, 3); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); + parm = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_pointer(func, "particle", "Particle", "", "Particle"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + RNA_def_int(func, "particle_no", 0, INT_MIN, INT_MAX, "Particle no", "", INT_MIN, INT_MAX); + RNA_def_int(func, "vcol_no", 0, INT_MIN, INT_MAX, "vcol no", "", INT_MIN, INT_MAX); + parm = RNA_def_property(func, "mcol", PROP_FLOAT, PROP_COLOR); + RNA_def_property_array(parm, 3); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); } diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 0591e877634..99d57147248 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -768,15 +768,15 @@ static void rna_def_pose_channel_constraints(BlenderRNA *brna, PropertyRNA *cpro RNA_def_function_return(func, parm); /* constraint to add */ parm = RNA_def_enum(func, "type", rna_enum_constraint_type_items, 1, "", "Constraint type to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "remove", "rna_PoseChannel_constraints_remove"); RNA_def_function_ui_description(func, "Remove a constraint from this object"); RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); /* ID needed for refresh */ /* constraint to remove */ parm = RNA_def_pointer(func, "constraint", "Constraint", "", "Removed constraint"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_pose_channel(BlenderRNA *brna) @@ -1359,8 +1359,8 @@ static void rna_def_bone_groups(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); /* ID needed for refresh */ /* bone group to remove */ parm = RNA_def_pointer(func, "group", "BoneGroup", "", "Removed bone group"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "BoneGroup"); diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c index 465a86adc31..f523b725b18 100644 --- a/source/blender/makesrna/intern/rna_pose_api.c +++ b/source/blender/makesrna/intern/rna_pose_api.c @@ -76,7 +76,7 @@ void RNA_api_pose_channel(StructRNA *srna) RNA_def_function_ui_description(func, "Calculate bone envelope at given point"); parm = RNA_def_float_vector_xyz(func, "point", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "Position in 3d space to evaluate", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return value */ parm = RNA_def_float(func, "factor", 0, -FLT_MAX, FLT_MAX, "Factor", "Envelope factor", -FLT_MAX, FLT_MAX); RNA_def_function_return(func, parm); diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 84382704b2b..946b20c916d 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -420,8 +420,10 @@ static void rna_def_render_engine(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; - + PropertyRNA *parm; + srna = RNA_def_struct(brna, "RenderEngine", NULL); RNA_def_struct_sdna(srna, "RenderEngine"); RNA_def_struct_ui_text(srna, "Render Engine", "Render engine"); @@ -444,25 +446,25 @@ static void rna_def_render_engine(BlenderRNA *brna) func = RNA_def_function(srna, "bake", NULL); RNA_def_function_ui_description(func, "Bake passes"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); - prop = RNA_def_pointer(func, "scene", "Scene", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_pointer(func, "object", "Object", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_enum(func, "pass_type", rna_enum_bake_pass_type_items, 0, "Pass", "Pass to bake"); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_int(func, "pass_filter", 0, 0, INT_MAX, "Pass Filter", "Filter to combined, diffuse, glossy, transmission and subsurface passes", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_int(func, "object_id", 0, 0, INT_MAX, "Object Id", "Id of the current object being baked in relation to the others", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_pointer(func, "pixel_array", "BakePixel", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_int(func, "num_pixels", 0, 0, INT_MAX, "Number of Pixels", "Size of the baking batch", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_int(func, "depth", 0, 0, INT_MAX, "Pixels depth", "Number of channels", 1, INT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_pointer(func, "scene", "Scene", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "object", "Object", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_enum(func, "pass_type", rna_enum_bake_pass_type_items, 0, "Pass", "Pass to bake"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "pass_filter", 0, 0, INT_MAX, "Pass Filter", "Filter to combined, diffuse, glossy, transmission and subsurface passes", 0, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "object_id", 0, 0, INT_MAX, "Object Id", "Id of the current object being baked in relation to the others", 0, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "pixel_array", "BakePixel", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "num_pixels", 0, 0, INT_MAX, "Number of Pixels", "Size of the baking batch", 0, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "depth", 0, 0, INT_MAX, "Pixels depth", "Number of channels", 1, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* TODO, see how array size of 0 works, this shouldnt be used */ - prop = RNA_def_pointer(func, "result", "AnyType", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_pointer(func, "result", "AnyType", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* viewport render callbacks */ func = RNA_def_function(srna, "view_update", NULL); @@ -479,8 +481,8 @@ static void rna_def_render_engine(BlenderRNA *brna) func = RNA_def_function(srna, "update_script_node", NULL); RNA_def_function_ui_description(func, "Compile shader script node"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); - prop = RNA_def_pointer(func, "node", "Node", "", ""); - RNA_def_property_flag(prop, PROP_RNAPTR); + parm = RNA_def_pointer(func, "node", "Node", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); /* tag for redraw */ func = RNA_def_function(srna, "tag_redraw", "engine_tag_redraw"); @@ -492,115 +494,115 @@ static void rna_def_render_engine(BlenderRNA *brna) func = RNA_def_function(srna, "begin_result", "RE_engine_begin_result"); RNA_def_function_ui_description(func, "Create render result to write linear floating point render layers and passes"); - prop = RNA_def_int(func, "x", 0, 0, INT_MAX, "X", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_int(func, "y", 0, 0, INT_MAX, "Y", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_int(func, "w", 0, 0, INT_MAX, "Width", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_int(func, "h", 0, 0, INT_MAX, "Height", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_int(func, "x", 0, 0, INT_MAX, "X", "", 0, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "y", 0, 0, INT_MAX, "Y", "", 0, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "w", 0, 0, INT_MAX, "Width", "", 0, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_int(func, "h", 0, 0, INT_MAX, "Height", "", 0, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_string(func, "layer", NULL, 0, "Layer", "Single layer to get render result for"); /* NULL ok here */ RNA_def_string(func, "view", NULL, 0, "View", "Single view to get render result for"); /* NULL ok here */ - prop = RNA_def_pointer(func, "result", "RenderResult", "Result", ""); - RNA_def_function_return(func, prop); + parm = RNA_def_pointer(func, "result", "RenderResult", "Result", ""); + RNA_def_function_return(func, parm); func = RNA_def_function(srna, "update_result", "RE_engine_update_result"); RNA_def_function_ui_description(func, "Signal that pixels have been updated and can be redrawn in the user interface"); - prop = RNA_def_pointer(func, "result", "RenderResult", "Result", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_pointer(func, "result", "RenderResult", "Result", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "end_result", "RE_engine_end_result"); RNA_def_function_ui_description(func, "All pixels in the render result have been set and are final"); - prop = RNA_def_pointer(func, "result", "RenderResult", "Result", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_pointer(func, "result", "RenderResult", "Result", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "cancel", 0, "Cancel", "Don't mark tile as done, don't merge results unless forced"); RNA_def_boolean(func, "do_merge_results", 0, "Merge Results", "Merge results even if cancel=true"); func = RNA_def_function(srna, "test_break", "RE_engine_test_break"); RNA_def_function_ui_description(func, "Test if the render operation should been canceled, this is a fast call that should be used regularly for responsiveness"); - prop = RNA_def_boolean(func, "do_break", 0, "Break", ""); - RNA_def_function_return(func, prop); + parm = RNA_def_boolean(func, "do_break", 0, "Break", ""); + RNA_def_function_return(func, parm); func = RNA_def_function(srna, "active_view_get", "RE_engine_active_view_get"); - prop = RNA_def_string(func, "view", NULL, 0, "View", "Single view active"); - RNA_def_function_return(func, prop); + parm = RNA_def_string(func, "view", NULL, 0, "View", "Single view active"); + RNA_def_function_return(func, parm); func = RNA_def_function(srna, "active_view_set", "RE_engine_active_view_set"); - RNA_def_string(func, "view", NULL, 0, "View", "Single view to set as active"); /* NULL ok here */ - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_string(func, "view", NULL, 0, "View", "Single view to set as active"); /* NULL ok here */ + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "camera_shift_x", "RE_engine_get_camera_shift_x"); - prop = RNA_def_pointer(func, "camera", "Object", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", ""); - prop = RNA_def_float(func, "shift_x", 0.0f, 0.0f, FLT_MAX, "Shift X", "", 0.0f, FLT_MAX); - RNA_def_function_return(func, prop); + parm = RNA_def_pointer(func, "camera", "Object", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", ""); + parm = RNA_def_float(func, "shift_x", 0.0f, 0.0f, FLT_MAX, "Shift X", "", 0.0f, FLT_MAX); + RNA_def_function_return(func, parm); func = RNA_def_function(srna, "camera_model_matrix", "RE_engine_get_camera_model_matrix"); - prop = RNA_def_pointer(func, "camera", "Object", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", ""); - prop = RNA_def_float_matrix(func, "r_model_matrix", 4, 4, NULL, 0.0f, 0.0f, "Model Matrix", "Normalized camera model matrix", 0.0f, 0.0f); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_pointer(func, "camera", "Object", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", ""); + parm = RNA_def_float_matrix(func, "r_model_matrix", 4, 4, NULL, 0.0f, 0.0f, "Model Matrix", "Normalized camera model matrix", 0.0f, 0.0f); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "use_spherical_stereo", "RE_engine_get_spherical_stereo"); - prop = RNA_def_pointer(func, "camera", "Object", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", ""); - RNA_def_function_return(func, prop); + parm = RNA_def_pointer(func, "camera", "Object", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_boolean(func, "use_spherical_stereo", 0, "Spherical Stereo", ""); + RNA_def_function_return(func, parm); func = RNA_def_function(srna, "update_stats", "RE_engine_update_stats"); RNA_def_function_ui_description(func, "Update and signal to redraw render status text"); - prop = RNA_def_string(func, "stats", NULL, 0, "Stats", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_string(func, "info", NULL, 0, "Info", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_string(func, "stats", NULL, 0, "Stats", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_string(func, "info", NULL, 0, "Info", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "frame_set", "RE_engine_frame_set"); RNA_def_function_ui_description(func, "Evaluate scene at a different frame (for motion blur)"); - prop = RNA_def_int(func, "frame", 0, INT_MIN, INT_MAX, "Frame", "", INT_MIN, INT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_float(func, "subframe", 0.0f, 0.0f, 1.0f, "Subframe", "", 0.0f, 1.0f); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_int(func, "frame", 0, INT_MIN, INT_MAX, "Frame", "", INT_MIN, INT_MAX); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_float(func, "subframe", 0.0f, 0.0f, 1.0f, "Subframe", "", 0.0f, 1.0f); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "update_progress", "RE_engine_update_progress"); RNA_def_function_ui_description(func, "Update progress percentage of render"); - prop = RNA_def_float(func, "progress", 0, 0.0f, 1.0f, "", "Percentage of render that's done", 0.0f, 1.0f); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_float(func, "progress", 0, 0.0f, 1.0f, "", "Percentage of render that's done", 0.0f, 1.0f); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "update_memory_stats", "RE_engine_update_memory_stats"); RNA_def_function_ui_description(func, "Update memory usage statistics"); RNA_def_float(func, "memory_used", 0, 0.0f, FLT_MAX, "", "Current memory usage in megabytes", 0.0f, FLT_MAX); RNA_def_float(func, "memory_peak", 0, 0.0f, FLT_MAX, "", "Peak memory usage in megabytes", 0.0f, FLT_MAX); - RNA_def_property_flag(prop, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "report", "RE_engine_report"); RNA_def_function_ui_description(func, "Report info, warning or error messages"); - prop = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_string(func, "message", NULL, 0, "Report Message", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_string(func, "message", NULL, 0, "Report Message", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "error_set", "RE_engine_set_error_message"); RNA_def_function_ui_description(func, "Set error message displaying after the render is finished"); - prop = RNA_def_string(func, "message", NULL, 0, "Report Message", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_string(func, "message", NULL, 0, "Report Message", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "bind_display_space_shader", "engine_bind_display_space_shader"); RNA_def_function_ui_description(func, "Bind GLSL fragment shader that converts linear colors to display space colors using scene color management settings"); - prop = RNA_def_pointer(func, "scene", "Scene", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_pointer(func, "scene", "Scene", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "unbind_display_space_shader", "engine_unbind_display_space_shader"); RNA_def_function_ui_description(func, "Unbind GLSL display space shader, must always be called after binding the shader"); func = RNA_def_function(srna, "support_display_space_shader", "engine_support_display_space_shader"); RNA_def_function_ui_description(func, "Test if GLSL display space shader is supported for the combination of graphics card and scene settings"); - prop = RNA_def_pointer(func, "scene", "Scene", "", ""); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_boolean(func, "supported", 0, "Supported", ""); - RNA_def_function_return(func, prop); + parm = RNA_def_pointer(func, "scene", "Scene", "", ""); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_boolean(func, "supported", 0, "Supported", ""); + RNA_def_function_return(func, parm); RNA_define_verify_sdna(0); @@ -689,6 +691,8 @@ static void rna_def_render_engine(BlenderRNA *brna) static void rna_def_render_result(BlenderRNA *brna) { StructRNA *srna; + PropertyRNA *prop; + FunctionRNA *func; PropertyRNA *parm; @@ -701,27 +705,27 @@ static void rna_def_render_result(BlenderRNA *brna) parm = RNA_def_string_file_name(func, "filename", NULL, FILE_MAX, "File Name", "Filename to load into this render tile, must be no smaller than " "the render result"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_define_verify_sdna(0); - parm = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_PIXEL); - RNA_def_property_int_sdna(parm, NULL, "rectx"); - RNA_def_property_clear_flag(parm, PROP_EDITABLE); + prop = RNA_def_property(srna, "resolution_x", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "rectx"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); - parm = RNA_def_property(srna, "resolution_y", PROP_INT, PROP_PIXEL); - RNA_def_property_int_sdna(parm, NULL, "recty"); - RNA_def_property_clear_flag(parm, PROP_EDITABLE); + prop = RNA_def_property(srna, "resolution_y", PROP_INT, PROP_PIXEL); + RNA_def_property_int_sdna(prop, NULL, "recty"); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); - parm = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(parm, "RenderLayer"); - RNA_def_property_collection_funcs(parm, "rna_RenderResult_layers_begin", "rna_iterator_listbase_next", + prop = RNA_def_property(srna, "layers", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "RenderLayer"); + RNA_def_property_collection_funcs(prop, "rna_RenderResult_layers_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", NULL, NULL, NULL, NULL); - parm = RNA_def_property(srna, "views", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(parm, "RenderView"); - RNA_def_property_collection_funcs(parm, "rna_RenderResult_views_begin", "rna_iterator_listbase_next", + prop = RNA_def_property(srna, "views", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "RenderView"); + RNA_def_property_collection_funcs(prop, "rna_RenderResult_views_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", NULL, NULL, NULL, NULL); @@ -761,19 +765,20 @@ static void rna_def_render_passes(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "find_by_type", "rna_RenderPass_find_by_type"); RNA_def_function_ui_description(func, "Get the render pass for a given type and view"); parm = RNA_def_enum(func, "pass_type", rna_enum_render_pass_type_items, SCE_PASS_COMBINED, "Pass", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "view", NULL, 0, "View", "Render view to get pass from"); /* NULL ok here */ - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "render_pass", "RenderPass", "", "The matching render pass"); RNA_def_function_return(func, parm); - } static void rna_def_render_layer(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; srna = RNA_def_struct(brna, "RenderLayer", NULL); RNA_def_struct_ui_text(srna, "Render Layer", ""); @@ -781,9 +786,9 @@ static void rna_def_render_layer(BlenderRNA *brna) func = RNA_def_function(srna, "load_from_file", "RE_layer_load_from_file"); RNA_def_function_ui_description(func, "Copies the pixels of this renderlayer from an image file"); RNA_def_function_flag(func, FUNC_USE_REPORTS); - prop = RNA_def_string(func, "filename", NULL, 0, "Filename", + parm = RNA_def_string(func, "filename", NULL, 0, "Filename", "Filename to load into this render tile, must be no smaller than the renderlayer"); - RNA_def_property_flag(prop, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_int(func, "x", 0, 0, INT_MAX, "Offset X", "Offset the position to copy from if the image is larger than the render layer", 0, INT_MAX); RNA_def_int(func, "y", 0, 0, INT_MAX, "Offset Y", diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index 85a34a94746..a1a7efdaba5 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -730,7 +730,9 @@ static void rna_def_rigidbody_world(BlenderRNA *brna) { StructRNA *srna; PropertyRNA *prop; + FunctionRNA *func; + PropertyRNA *parm; srna = RNA_def_struct(brna, "RigidBodyWorld", NULL); RNA_def_struct_sdna(srna, "RigidBodyWorld"); @@ -813,34 +815,28 @@ static void rna_def_rigidbody_world(BlenderRNA *brna) func = RNA_def_function(srna, "convex_sweep_test", "rna_RigidBodyWorld_convex_sweep_test"); RNA_def_function_ui_description(func, "Sweep test convex rigidbody against the current rigidbody world"); RNA_def_function_flag(func, FUNC_USE_REPORTS); - - prop = RNA_def_pointer(func, "object", "Object", "", "Rigidbody object with a convex collision shape"); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL); - RNA_def_property_clear_flag(prop, PROP_THICK_WRAP); - + parm = RNA_def_pointer(func, "object", "Object", "", "Rigidbody object with a convex collision shape"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); /* ray start and end */ - prop = RNA_def_float_vector(func, "start", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); - RNA_def_property_flag(prop, PROP_REQUIRED); - prop = RNA_def_float_vector(func, "end", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); - RNA_def_property_flag(prop, PROP_REQUIRED); - - prop = RNA_def_float_vector(func, "object_location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", + parm = RNA_def_float_vector(func, "start", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_float_vector(func, "end", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_float_vector(func, "object_location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "The hit location of this sweep test", -1e4, 1e4); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); - - prop = RNA_def_float_vector(func, "hitpoint", 3, NULL, -FLT_MAX, FLT_MAX, "Hitpoint", + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); + parm = RNA_def_float_vector(func, "hitpoint", 3, NULL, -FLT_MAX, FLT_MAX, "Hitpoint", "The hit location of this sweep test", -1e4, 1e4); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); - - prop = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal", + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); + parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal", "The face normal at the sweep test hit location", -1e4, 1e4); - RNA_def_property_flag(prop, PROP_THICK_WRAP); - RNA_def_function_output(func, prop); - - prop = RNA_def_int(func, "has_hit", 0, 0, 0, "", "If the function has found collision point, value is 1, otherwise 0", 0, 0); - RNA_def_function_output(func, prop); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); + RNA_def_function_output(func, parm); + parm = RNA_def_int(func, "has_hit", 0, 0, 0, "", "If the function has found collision point, value is 1, otherwise 0", 0, 0); + RNA_def_function_output(func, parm); } static void rna_def_rigidbody_object(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 727bdac087b..abded187b33 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -178,7 +178,7 @@ static int rna_idproperty_known(CollectionPropertyIterator *iter, void *data) * for the second loop where we go over unknown id properties */ do { for (prop = ptype->cont.properties.first; prop; prop = prop->next) - if ((prop->flag & PROP_BUILTIN) == 0 && STREQ(prop->identifier, idprop->name)) + if ((prop->flag_internal & PROP_INTERN_BUILTIN) == 0 && STREQ(prop->identifier, idprop->name)) return 1; } while ((ptype = ptype->base)); @@ -191,7 +191,7 @@ static int rna_property_builtin(CollectionPropertyIterator *UNUSED(iter), void * /* function to skip builtin rna properties */ - return (prop->flag & PROP_BUILTIN); + return (prop->flag_internal & PROP_INTERN_BUILTIN); } static int rna_function_builtin(CollectionPropertyIterator *UNUSED(iter), void *data) @@ -385,7 +385,7 @@ int rna_builtin_properties_lookup_string(PointerRNA *ptr, const char *key, Point } else { for (prop = srna->cont.properties.first; prop; prop = prop->next) { - if (!(prop->flag & PROP_BUILTIN) && STREQ(prop->identifier, key)) { + if (!(prop->flag_internal & PROP_INTERN_BUILTIN) && STREQ(prop->identifier, key)) { propptr.type = &RNA_Property; propptr.data = prop; @@ -557,19 +557,19 @@ static int rna_Property_animatable_get(PointerRNA *ptr) static int rna_Property_use_output_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; - return (prop->flag & PROP_OUTPUT) != 0; + return (prop->flag_parameter & PARM_OUTPUT) != 0; } static int rna_Property_is_required_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; - return (prop->flag & PROP_REQUIRED) != 0; + return (prop->flag_parameter & PARM_REQUIRED) != 0; } static int rna_Property_is_argument_optional_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; - return (prop->flag & PROP_PYFUNC_OPTIONAL) != 0; + return (prop->flag_parameter & PARM_PYFUNC_OPTIONAL) != 0; } static int rna_Property_is_never_none_get(PointerRNA *ptr) @@ -625,7 +625,7 @@ static int rna_Property_is_registered_optional_get(PointerRNA *ptr) static int rna_Property_is_runtime_get(PointerRNA *ptr) { PropertyRNA *prop = (PropertyRNA *)ptr->data; - return (prop->flag & PROP_RUNTIME) != 0; + return (prop->flag_internal & PROP_INTERN_RUNTIME) != 0; } diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index c63d4e775f8..ddfb5dc6d61 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2310,7 +2310,7 @@ static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_GPencil_brush_new"); RNA_def_function_ui_description(func, "Add a new grease pencil brush"); parm = RNA_def_string(func, "name", "GPencilBrush", MAX_NAME, "Name", "Name of the brush"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "set_active", 0, "Set Active", "Set the newly created brush to the active brush"); parm = RNA_def_pointer(func, "palette", "GPencilBrush", "", "The newly created brush"); RNA_def_function_return(func, parm); @@ -2319,8 +2319,8 @@ static void rna_def_gpencil_brushes(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a grease pencil brush"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "brush", "GPencilBrush", "", "The brush to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "GPencilBrush"); @@ -3609,8 +3609,8 @@ static void rna_def_freestyle_modules(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a style module from scene render layer Freestyle settings"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "module", "FreestyleModuleSettings", "", "Style module to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop) @@ -3642,7 +3642,7 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a line set to scene render layer Freestyle settings"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_SELF_ID); parm = RNA_def_string(func, "name", "LineSet", 0, "", "New name for the line set (not unique)"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "lineset", "FreestyleLineSet", "", "Newly created line set"); RNA_def_function_return(func, parm); @@ -3650,8 +3650,8 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a line set from scene render layer Freestyle settings"); RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "lineset", "FreestyleLineSet", "", "Line set to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_freestyle_settings(BlenderRNA *brna) @@ -4979,7 +4979,7 @@ static void rna_def_render_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a render layer to scene"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_string(func, "name", "RenderLayer", 0, "", "New name for the render layer (not unique)"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "result", "SceneRenderLayer", "", "Newly created render layer"); RNA_def_function_return(func, parm); @@ -4987,8 +4987,8 @@ static void rna_def_render_layers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a render layer"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS | FUNC_USE_SELF_ID); parm = RNA_def_pointer(func, "layer", "SceneRenderLayer", "", "Render layer to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } /* Render Views - MultiView */ @@ -5058,7 +5058,7 @@ static void rna_def_render_views(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Add a render view to scene"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_string(func, "name", "RenderView", 0, "", "New name for the marker (not unique)"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "result", "SceneRenderView", "", "Newly created render view"); RNA_def_function_return(func, parm); @@ -5066,8 +5066,8 @@ static void rna_def_render_views(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a render view"); RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS | FUNC_USE_SELF_ID); parm = RNA_def_pointer(func, "view", "SceneRenderView", "", "Render view to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_image_format_stereo3d_format(BlenderRNA *brna) @@ -6635,7 +6635,7 @@ static void rna_def_scene_objects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Link object to scene, run scene.update() after"); RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "object", "Object", "", "Object to add to scene"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "base", "ObjectBase", "", "The newly created base"); RNA_def_function_return(func, parm); @@ -6643,7 +6643,7 @@ static void rna_def_scene_objects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Unlink object from scene"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove from scene"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "Object"); @@ -6694,7 +6694,7 @@ static void rna_def_timeline_markers(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_TimeLine_add"); RNA_def_function_ui_description(func, "Add a keyframe to the curve"); parm = RNA_def_string(func, "name", "Marker", 0, "", "New name for the marker (not unique)"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "frame", 1, -MAXFRAME, MAXFRAME, "", "The frame for the new marker", -MAXFRAME, MAXFRAME); parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Newly created timeline marker"); RNA_def_function_return(func, parm); @@ -6704,8 +6704,8 @@ static void rna_def_timeline_markers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove a timeline marker"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "marker", "TimelineMarker", "", "Timeline marker to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_TimeLine_clear"); RNA_def_function_ui_description(func, "Remove all timeline markers"); @@ -6732,7 +6732,6 @@ static void rna_def_scene_keying_sets(BlenderRNA *brna, PropertyRNA *cprop) /* name */ RNA_def_string(func, "idname", "KeyingSet", 64, "IDName", "Internal identifier of Keying Set"); RNA_def_string(func, "name", "KeyingSet", 64, "Name", "User visible name of Keying Set"); - /* returns the new KeyingSet */ parm = RNA_def_pointer(func, "keyingset", "KeyingSet", "", "Newly created Keying Set"); RNA_def_function_return(func, parm); @@ -7216,8 +7215,8 @@ void RNA_def_scene(BlenderRNA *brna) /* Statistics */ func = RNA_def_function(srna, "statistics", "ED_info_stats_string"); - prop = RNA_def_string(func, "statistics", NULL, 0, "Statistics", ""); - RNA_def_function_return(func, prop); + parm = RNA_def_string(func, "statistics", NULL, 0, "Statistics", ""); + RNA_def_function_return(func, parm); /* Grease Pencil */ prop = RNA_def_property(srna, "grease_pencil", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index 85c0b01334f..fe781a309a4 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -305,7 +305,7 @@ void RNA_api_scene(StructRNA *srna) func = RNA_def_function(srna, "frame_set", "rna_Scene_frame_set"); RNA_def_function_ui_description(func, "Set scene frame updating all objects immediately"); parm = RNA_def_int(func, "frame", 0, MINAFRAME, MAXFRAME, "", "Frame number to set", MINAFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_float(func, "subframe", 0.0, 0.0, 1.0, "", "Sub-frame time, between 0.0 and 1.0", 0.0, 1.0); func = RNA_def_function(srna, "update", "rna_Scene_update_tagged"); @@ -315,34 +315,31 @@ void RNA_api_scene(StructRNA *srna) func = RNA_def_function(srna, "uvedit_aspect", "rna_Scene_uvedit_aspect"); RNA_def_function_ui_description(func, "Get uv aspect for current object"); parm = RNA_def_pointer(func, "object", "Object", "", "Object"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); - + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_float_vector(func, "result", 2, NULL, 0.0f, FLT_MAX, "", "aspect", 0.0f, FLT_MAX); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); /* Ray Cast */ func = RNA_def_function(srna, "ray_cast", "rna_Scene_ray_cast"); RNA_def_function_ui_description(func, "Cast a ray onto in object space"); - /* ray start and end */ parm = RNA_def_float_vector(func, "origin", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float_vector(func, "direction", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_float(func, "distance", BVH_RAYCAST_DIST_MAX, 0.0, BVH_RAYCAST_DIST_MAX, "", "Maximum distance", 0.0, BVH_RAYCAST_DIST_MAX); - /* return location and normal */ parm = RNA_def_boolean(func, "result", 0, "", ""); RNA_def_function_output(func, parm); parm = RNA_def_float_vector(func, "location", 3, NULL, -FLT_MAX, FLT_MAX, "Location", "The hit location of this ray cast", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); parm = RNA_def_float_vector(func, "normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal", "The face normal at the ray cast hit location", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); parm = RNA_def_int(func, "index", 0, 0, 0, "", "The face index, -1 when original data isn't available", 0, 0); RNA_def_function_output(func, parm); @@ -355,29 +352,29 @@ void RNA_api_scene(StructRNA *srna) /* don't remove this, as COLLADA exporting cannot be done through operators in render() callback. */ func = RNA_def_function(srna, "collada_export", "rna_Scene_collada_export"); parm = RNA_def_string(func, "filepath", NULL, FILE_MAX, "File Path", "File path to write Collada file"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */ - parm = RNA_def_boolean(func, "apply_modifiers", 0, "Apply Modifiers", "Apply modifiers"); - parm = RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX, + RNA_def_boolean(func, "apply_modifiers", 0, "Apply Modifiers", "Apply modifiers"); + RNA_def_int(func, "export_mesh_type", 0, INT_MIN, INT_MAX, "Resolution", "Modifier resolution for export", INT_MIN, INT_MAX); - parm = RNA_def_boolean(func, "selected", 0, "Selection Only", "Export only selected elements"); - parm = RNA_def_boolean(func, "include_children", 0, "Include Children", "Export all children of selected objects (even if not selected)"); - parm = RNA_def_boolean(func, "include_armatures", 0, "Include Armatures", "Export related armatures (even if not selected)"); - parm = RNA_def_boolean(func, "include_shapekeys", 0, "Include Shape Keys", "Export all Shape Keys from Mesh Objects"); - parm = RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only", "Only export deforming bones with armatures"); + RNA_def_boolean(func, "selected", 0, "Selection Only", "Export only selected elements"); + RNA_def_boolean(func, "include_children", 0, "Include Children", "Export all children of selected objects (even if not selected)"); + RNA_def_boolean(func, "include_armatures", 0, "Include Armatures", "Export related armatures (even if not selected)"); + RNA_def_boolean(func, "include_shapekeys", 0, "Include Shape Keys", "Export all Shape Keys from Mesh Objects"); + RNA_def_boolean(func, "deform_bones_only", 0, "Deform Bones only", "Only export deforming bones with armatures"); - parm = RNA_def_boolean(func, "active_uv_only", 0, "Active UV Layer only", "Export only the active UV Layer"); - parm = RNA_def_boolean(func, "include_uv_textures", 0, "Include UV Textures", "Export textures assigned to the object UV maps"); - parm = RNA_def_boolean(func, "include_material_textures", 0, "Include Material Textures", "Export textures assigned to the object Materials"); - parm = RNA_def_boolean(func, "use_texture_copies", 0, "copy", "Copy textures to same folder where the .dae file is exported"); + RNA_def_boolean(func, "active_uv_only", 0, "Active UV Layer only", "Export only the active UV Layer"); + RNA_def_boolean(func, "include_uv_textures", 0, "Include UV Textures", "Export textures assigned to the object UV maps"); + RNA_def_boolean(func, "include_material_textures", 0, "Include Material Textures", "Export textures assigned to the object Materials"); + RNA_def_boolean(func, "use_texture_copies", 0, "copy", "Copy textures to same folder where the .dae file is exported"); - parm = RNA_def_boolean(func, "use_ngons", 1, "Use NGons", "Keep NGons in Export"); - parm = RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", "Instantiate multiple Objects from same Data"); - parm = RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile", "Export additional Blender specific information (for material, shaders, bones, etc.)"); - parm = RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name"); - parm = RNA_def_boolean(func, "open_sim", 0, "Export for SL/OpenSim", "Compatibility mode for SL, OpenSim and similar online worlds"); + RNA_def_boolean(func, "use_ngons", 1, "Use NGons", "Keep NGons in Export"); + RNA_def_boolean(func, "use_object_instantiation", 1, "Use Object Instances", "Instantiate multiple Objects from same Data"); + RNA_def_boolean(func, "use_blender_profile", 1, "Use Blender Profile", "Export additional Blender specific information (for material, shaders, bones, etc.)"); + RNA_def_boolean(func, "sort_by_name", 0, "Sort by Object name", "Sort exported data by Object name"); + RNA_def_boolean(func, "open_sim", 0, "Export for SL/OpenSim", "Compatibility mode for SL, OpenSim and similar online worlds"); - parm = RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX, + RNA_def_int(func, "export_transformation_type", 0, INT_MIN, INT_MAX, "Transformation", "Transformation type for translation, scale and rotation", INT_MIN, INT_MAX); RNA_def_function_ui_description(func, "Export to collada file"); @@ -388,7 +385,7 @@ void RNA_api_scene(StructRNA *srna) RNA_def_function_ui_description(func, "Export to Alembic file"); parm = RNA_def_string(func, "filepath", NULL, FILE_MAX, "File Path", "File path to write Alembic file"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_subtype(parm, PROP_FILEPATH); /* allow non utf8 */ RNA_def_int(func, "frame_start", 1, INT_MIN, INT_MAX, "Start", "Start Frame", INT_MIN, INT_MAX); @@ -428,13 +425,12 @@ void RNA_api_scene_render(StructRNA *srna) RNA_def_function_ui_description(func, "Return the absolute path to the filename to be written for a given frame"); RNA_def_int(func, "frame", INT_MIN, INT_MIN, INT_MAX, "", "Frame number to use, if unset the current frame will be used", MINAFRAME, MAXFRAME); - parm = RNA_def_boolean(func, "preview", 0, "Preview", "Use preview range"); - parm = RNA_def_string_file_path(func, "view", NULL, FILE_MAX, "View", + RNA_def_boolean(func, "preview", 0, "Preview", "Use preview range"); + RNA_def_string_file_path(func, "view", NULL, FILE_MAX, "View", "The name of the view to use to replace the \"%\" chars"); - parm = RNA_def_string_file_path(func, "filepath", NULL, FILE_MAX, "File Path", "The resulting filepath from the scenes render settings"); - RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */ + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */ RNA_def_function_output(func, parm); } diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 43d5cda17ae..b44e404c364 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -285,22 +285,22 @@ static void rna_def_view2d_api(StructRNA *srna) func = RNA_def_function(srna, "region_to_view", "rna_View2D_region_to_view"); RNA_def_function_ui_description(func, "Transform region coordinates to 2D view"); parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "x", "Region x coordinate", -10000, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "y", "Region y coordinate", -10000, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float_array(func, "result", 2, view_default, -FLT_MAX, FLT_MAX, "Result", "View coordinates", -10000.0f, 10000.0f); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); func = RNA_def_function(srna, "view_to_region", "rna_View2D_view_to_region"); RNA_def_function_ui_description(func, "Transform 2D view coordinates to region"); parm = RNA_def_float(func, "x", 0.0f, -FLT_MAX, FLT_MAX, "x", "2D View x coordinate", -10000.0f, 10000.0f); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float(func, "y", 0.0f, -FLT_MAX, FLT_MAX, "y", "2D View y coordinate", -10000.0f, 10000.0f); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "clip", 1, "Clip", "Clip coordinates to the visible region"); parm = RNA_def_int_array(func, "result", 2, region_default, INT_MIN, INT_MAX, "Result", "Region coordinates", -10000, 10000); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); } diff --git a/source/blender/makesrna/intern/rna_sensor_api.c b/source/blender/makesrna/intern/rna_sensor_api.c index 476f0589bc9..b0c4109b1df 100644 --- a/source/blender/makesrna/intern/rna_sensor_api.c +++ b/source/blender/makesrna/intern/rna_sensor_api.c @@ -65,13 +65,13 @@ void RNA_api_sensor(StructRNA *srna) func = RNA_def_function(srna, "link", "rna_Sensor_link"); RNA_def_function_ui_description(func, "Link the sensor to a controller"); parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to link to"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_update(parm, NC_LOGIC, NULL); func = RNA_def_function(srna, "unlink", "rna_Sensor_unlink"); RNA_def_function_ui_description(func, "Unlink the sensor from a controller"); parm = RNA_def_pointer(func, "controller", "Controller", "", "Controller to unlink from"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_update(parm, NC_LOGIC, NULL); } diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index bb9c2a6c2fd..ae444acc432 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1357,10 +1357,10 @@ static void rna_def_sequence_modifiers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Add a new modifier"); parm = RNA_def_string(func, "name", "Name", 0, "", "New name for the modifier"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* modifier to add */ parm = RNA_def_enum(func, "type", rna_enum_sequence_modifier_type_items, seqModifierType_ColorBalance, "", "Modifier type to add"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "modifier", "SequenceModifier", "", "Newly created modifier"); RNA_def_function_return(func, parm); @@ -1371,8 +1371,8 @@ static void rna_def_sequence_modifiers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove an existing modifier from the sequence"); /* modifier to remove */ parm = RNA_def_pointer(func, "modifier", "SequenceModifier", "", "Modifier to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); /* clear all modifiers */ func = RNA_def_function(srna, "clear", "rna_Sequence_modifier_clear"); diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c index 13fda02c7c8..76f5a4934cf 100644 --- a/source/blender/makesrna/intern/rna_sequencer_api.c +++ b/source/blender/makesrna/intern/rna_sequencer_api.c @@ -414,14 +414,14 @@ void RNA_api_sequence_strip(StructRNA *srna) RNA_def_function_ui_description(func, "Return the strip element from a given frame or None"); parm = RNA_def_int(func, "frame", 0, -MAXFRAME, MAXFRAME, "Frame", "The frame to get the strip element from", -MAXFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_function_return(func, RNA_def_pointer(func, "elem", "SequenceElement", "", "strip element of the current frame")); func = RNA_def_function(srna, "swap", "rna_Sequence_swap_internal"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "other", "Sequence", "Other", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); } void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop) @@ -439,7 +439,7 @@ void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Push an image from ImageSequence.directory"); parm = RNA_def_string(func, "filename", "File", 0, "", "Filepath to image"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "elem", "SequenceElement", "", "New SequenceElement"); RNA_def_function_return(func, parm); @@ -448,7 +448,7 @@ void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Pop an image off the collection"); parm = RNA_def_int(func, "index", -1, INT_MIN, INT_MAX, "", "Index of image to remove", INT_MIN, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) @@ -487,15 +487,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Add a new movie clip sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to add"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel", "The channel for the new sequence", 1, MAXSEQ); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "", "The start frame for the new sequence", -MAXFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); @@ -504,15 +504,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Add a new mask sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to add"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel", "The channel for the new sequence", 1, MAXSEQ); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "", "The start frame for the new sequence", -MAXFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); @@ -521,15 +521,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Add a new scene sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to add"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel", "The channel for the new sequence", 1, MAXSEQ); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "", "The start frame for the new sequence", -MAXFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); @@ -538,15 +538,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Add a new image sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "filepath", "File", 0, "", "Filepath to image"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel", "The channel for the new sequence", 1, MAXSEQ); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "", "The start frame for the new sequence", -MAXFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); @@ -555,15 +555,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Add a new movie sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "filepath", "File", 0, "", "Filepath to movie"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel", "The channel for the new sequence", 1, MAXSEQ); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "", "The start frame for the new sequence", -MAXFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); @@ -572,15 +572,15 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID | FUNC_USE_MAIN); RNA_def_function_ui_description(func, "Add a new sound sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "filepath", "File", 0, "", "Filepath to movie"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel", "The channel for the new sequence", 1, MAXSEQ); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "frame_start", 0, -MAXFRAME, MAXFRAME, "", "The start frame for the new sequence", -MAXFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return type */ parm = RNA_def_pointer(func, "sequence", "Sequence", "", "New Sequence"); RNA_def_function_return(func, parm); @@ -589,17 +589,17 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); RNA_def_function_ui_description(func, "Add a new effect sequence"); parm = RNA_def_string(func, "name", "Name", 0, "", "Name for the new sequence"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", seq_effect_items, 0, "Type", "type for the new sequence"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "channel", 0, 1, MAXSEQ, "Channel", "The channel for the new sequence", 1, MAXSEQ); /* don't use MAXFRAME since it makes importer scripts fail */ - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "frame_start", 0, INT_MIN, INT_MAX, "", "The start frame for the new sequence", INT_MIN, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_int(func, "frame_end", 0, INT_MIN, INT_MAX, "", "The end frame for the new sequence", INT_MIN, INT_MAX); RNA_def_pointer(func, "seq1", "Sequence", "", "Sequence 1 for effect"); @@ -614,8 +614,8 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a Sequence"); parm = RNA_def_pointer(func, "sequence", "Sequence", "", "Sequence to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index b262e6412e3..1feae9e0bca 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2320,8 +2320,8 @@ static void rna_def_backgroundImages(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Remove background image"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "image", "BackgroundImage", "", "Image displayed as viewport background"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "clear", "rna_BackgroundImage_clear"); RNA_def_function_ui_description(func, "Remove all background images"); @@ -4253,15 +4253,15 @@ static void rna_def_space_node_path_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Set the root node tree"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); func = RNA_def_function(srna, "append", "rna_SpaceNodeEditor_path_append"); RNA_def_function_ui_description(func, "Append a node group tree to the path"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "node_tree", "NodeTree", "Node Tree", "Node tree to append to the node editor path"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_pointer(func, "node", "Node", "Node", "Group node linking to this node tree"); - RNA_def_property_flag(parm, PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_RNAPTR); func = RNA_def_function(srna, "pop", "rna_SpaceNodeEditor_path_pop"); RNA_def_function_ui_description(func, "Remove the last node tree from the path"); diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index 3cfbd798ad6..c72d6d9e581 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -84,9 +84,9 @@ void RNA_api_space_node(StructRNA *srna) RNA_def_function_ui_description(func, "Set the cursor location using region coordinates"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "x", "Region x coordinate", -10000, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "y", "Region y coordinate", -10000, 10000); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } void RNA_api_space_text(StructRNA *srna) @@ -98,9 +98,9 @@ void RNA_api_space_text(StructRNA *srna) RNA_def_function_ui_description(func, "Retrieve the region position from the given line and character position"); RNA_def_function_flag(func, FUNC_USE_SELF_ID); parm = RNA_def_int(func, "line", 0, INT_MIN, INT_MAX, "Line", "Line index", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "column", 0, INT_MIN, INT_MAX, "Column", "Column index", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int_array(func, "result", 2, NULL, -1, INT_MAX, "", "Region coordinates", -1, INT_MAX); RNA_def_function_output(func, parm); } diff --git a/source/blender/makesrna/intern/rna_text_api.c b/source/blender/makesrna/intern/rna_text_api.c index 2478ad0fe1a..0287f74587b 100644 --- a/source/blender/makesrna/intern/rna_text_api.c +++ b/source/blender/makesrna/intern/rna_text_api.c @@ -55,15 +55,15 @@ static void rna_Text_write(Text *text, const char *str) void RNA_api_text(StructRNA *srna) { FunctionRNA *func; - PropertyRNA *prop; + PropertyRNA *parm; func = RNA_def_function(srna, "clear", "rna_Text_clear"); RNA_def_function_ui_description(func, "clear the text block"); func = RNA_def_function(srna, "write", "rna_Text_write"); RNA_def_function_ui_description(func, "write text at the cursor location and advance to the end of the text block"); - prop = RNA_def_string(func, "text", "Text", 0, "", "New text for this data-block"); - RNA_def_property_flag(prop, PROP_REQUIRED); + parm = RNA_def_string(func, "text", "Text", 0, "", "New text for this data-block"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } #endif diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c index ef1ef5e1469..a8fcf0ca3b6 100644 --- a/source/blender/makesrna/intern/rna_texture_api.c +++ b/source/blender/makesrna/intern/rna_texture_api.c @@ -93,11 +93,11 @@ void RNA_api_texture(StructRNA *srna) RNA_def_function_ui_description(func, "Evaluate the texture at the coordinates given"); parm = RNA_def_float_vector(func, "value", 3, NULL, -FLT_MAX, FLT_MAX, "", "", -1e4, 1e4); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* return location and normal */ parm = RNA_def_float_vector(func, "result", 4, NULL, -FLT_MAX, FLT_MAX, "Result", NULL, -1e4, 1e4); - RNA_def_property_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); RNA_def_function_output(func, parm); } @@ -119,7 +119,7 @@ void RNA_api_environment_map(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS); parm = RNA_def_string_file_name(func, "filepath", NULL, FILE_MAX, "File path", "Location of the output file"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_pointer(func, "scene", "Scene", "", "Overrides the scene from which image parameters are taken"); diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index 2340345c1c6..7a01e3a4f6b 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -1289,7 +1289,7 @@ static void rna_def_trackingMarkers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Get marker for specified frame"); parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to find marker for", MINFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "exact", true, "Exact", "Get marker at exact frame number rather than get estimated marker"); parm = RNA_def_pointer(func, "marker", "MovieTrackingMarker", "", "Marker for specified frame"); @@ -1299,11 +1299,11 @@ static void rna_def_trackingMarkers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Insert a new marker at the specified frame"); parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to insert marker to", MINFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_float_vector(func, "co", 2, NULL, -1.0, 1.0, "Coordinate", "Place new marker at the given frame using specified in normalized space coordinates", -1.0, 1.0); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "marker", "MovieTrackingMarker", "", "Newly created marker"); RNA_def_function_return(func, parm); @@ -1311,7 +1311,7 @@ static void rna_def_trackingMarkers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Delete marker at specified frame"); parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to delete marker from", MINFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } static void rna_def_trackingTrack(BlenderRNA *brna) @@ -1593,7 +1593,7 @@ static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Get plane marker for specified frame"); parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to find marker for", MINFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "exact", true, "Exact", "Get plane marker at exact frame number rather than get estimated marker"); parm = RNA_def_pointer(func, "plane_marker", "MovieTrackingPlaneMarker", "", "Plane marker for specified frame"); @@ -1603,7 +1603,7 @@ static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Insert a new plane marker at the specified frame"); parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to insert marker to", MINFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "plane_marker", "MovieTrackingPlaneMarker", "", "Newly created plane marker"); RNA_def_function_return(func, parm); @@ -1611,7 +1611,7 @@ static void rna_def_trackingPlaneMarkers(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_ui_description(func, "Delete plane marker at specified frame"); parm = RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to delete plane marker from", MINFRAME, MAXFRAME); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } static void rna_def_trackingPlaneTrack(BlenderRNA *brna) @@ -1886,7 +1886,7 @@ static void rna_def_trackingReconstructedCameras(BlenderRNA *brna) RNA_def_int(func, "frame", 1, MINFRAME, MAXFRAME, "Frame", "Frame number to find camera for", MINFRAME, MAXFRAME); parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, -FLT_MAX, FLT_MAX, "Matrix", "Interpolated camera matrix for a given frame", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_THICK_WRAP); /* needed for string return value */ + RNA_def_parameter_flags(parm, PROP_THICK_WRAP, 0); /* needed for string return value */ RNA_def_function_output(func, parm); } @@ -2099,7 +2099,7 @@ static void rna_def_trackingObjects(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_trackingObject_new"); RNA_def_function_ui_description(func, "Add tracking object to this movie clip"); parm = RNA_def_string(func, "name", NULL, 0, "", "Name of new object"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "object", "MovieTrackingObject", "", "New motion tracking object"); RNA_def_function_return(func, parm); @@ -2107,8 +2107,8 @@ static void rna_def_trackingObjects(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove tracking object from this movie clip"); parm = RNA_def_pointer(func, "object", "MovieTrackingObject", "", "Motion tracking object to be removed"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); /* active object */ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index 5f11dd51282..7a3c862f04c 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -944,20 +944,20 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", "")); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* draw */ func = RNA_def_function(srna, "draw", NULL); RNA_def_function_ui_description(func, "Draw UI elements into the panel UI layout"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); func = RNA_def_function(srna, "draw_header", NULL); RNA_def_function_ui_description(func, "Draw UI elements into the panel's header UI layout"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "UILayout"); @@ -1084,35 +1084,35 @@ static void rna_def_uilist(BlenderRNA *brna) "function, you may want to check given 'item' is of the right type...)"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take Collection property"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_pointer(func, "item", "AnyType", "", "Item of the collection property"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_int(func, "icon", 0, 0, INT_MAX, "", "Icon of the item in the collection", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "active_data", "AnyType", "", "Data from which to take property for the active element"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "active_property", NULL, 0, "", "Identifier of property in active_data, for the active element"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_int(func, "index", 0, 0, INT_MAX, "", "Index of the item in the collection", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_PYFUNC_OPTIONAL); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_PYFUNC_OPTIONAL); prop = RNA_def_property(func, "flt_flag", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(prop, "", "The filter-flag result for this item"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_PYFUNC_OPTIONAL); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_PYFUNC_OPTIONAL); /* draw_filter */ func = RNA_def_function(srna, "draw_filter", NULL); RNA_def_function_ui_description(func, "Draw filtering options"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "layout", "UILayout", "", "Layout to draw the item"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* filter */ func = RNA_def_function(srna, "filter_items", NULL); @@ -1120,19 +1120,19 @@ static void rna_def_uilist(BlenderRNA *brna) "filter_flags, and reorder results in filter_neworder arrays)"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take Collection property"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data, for the collection"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); prop = RNA_def_property(func, "filter_flags", PROP_INT, PROP_UNSIGNED); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_DYNAMIC); + RNA_def_property_flag(prop, PARM_REQUIRED | PROP_DYNAMIC); RNA_def_property_array(prop, 1); /* XXX Dummy value, default 0 does not work */ RNA_def_property_ui_text(prop, "", "An array of filter flags, one for each item in the collection (NOTE: " "FILTER_ITEM bit is reserved, it defines whether the item is shown or not)"); RNA_def_function_output(func, prop); prop = RNA_def_property(func, "filter_neworder", PROP_INT, PROP_UNSIGNED); - RNA_def_property_flag(prop, PROP_REQUIRED | PROP_DYNAMIC); + RNA_def_property_flag(prop, PARM_REQUIRED | PROP_DYNAMIC); RNA_def_property_array(prop, 1); /* XXX Dummy value, default 0 does not work */ RNA_def_property_ui_text(prop, "", "An array of indices, one for each item in the collection, mapping the org " "index to the new one"); @@ -1166,7 +1166,7 @@ static void rna_def_header(BlenderRNA *brna) RNA_def_function_ui_description(func, "Draw UI elements into the header UI layout"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_define_verify_sdna(0); /* not in sdna */ @@ -1214,14 +1214,14 @@ static void rna_def_menu(BlenderRNA *brna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", "")); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* draw */ func = RNA_def_function(srna, "draw", NULL); RNA_def_function_ui_description(func, "Draw UI elements into the menu UI layout"); RNA_def_function_flag(func, FUNC_REGISTER); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_define_verify_sdna(false); /* not in sdna */ diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index 9d55115a14c..46775af21db 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -397,7 +397,7 @@ static void api_ui_item_op(FunctionRNA *func) { PropertyRNA *parm; parm = RNA_def_string(func, "operator", NULL, 0, "", "Identifier of the operator"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } static void api_ui_item_op_common(FunctionRNA *func) @@ -411,9 +411,9 @@ static void api_ui_item_rna_common(FunctionRNA *func) PropertyRNA *parm; parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } void RNA_api_ui_layout(StructRNA *srna) @@ -481,7 +481,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_return(func, parm); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take the icon"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_function_ui_description(func, "Return the custom icon for this data, " "use it e.g. to get materials or texture icons"); @@ -492,7 +492,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); api_ui_item_rna_common(func); parm = RNA_def_string(func, "identifier", NULL, 0, "", "Identifier of the enum item"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_function_ui_description(func, "Return the UI name for this enum item"); func = RNA_def_function(srna, "enum_item_description", "rna_ui_get_enum_description"); @@ -501,7 +501,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); api_ui_item_rna_common(func); parm = RNA_def_string(func, "identifier", NULL, 0, "", "Identifier of the enum item"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_function_ui_description(func, "Return the UI description for this enum item"); func = RNA_def_function(srna, "enum_item_icon", "rna_ui_get_enum_icon"); @@ -510,7 +510,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); api_ui_item_rna_common(func); parm = RNA_def_string(func, "identifier", NULL, 0, "", "Identifier of the enum item"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_function_ui_description(func, "Return the icon for this enum item"); /* items */ @@ -541,15 +541,15 @@ void RNA_api_ui_layout(StructRNA *srna) func = RNA_def_function(srna, "prop_enum", "rna_uiItemEnumR_string"); api_ui_item_rna_common(func); parm = RNA_def_string(func, "value", NULL, 0, "", "Enum property value"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); api_ui_item_common(func); func = RNA_def_function(srna, "prop_search", "rna_uiItemPointerR"); api_ui_item_rna_common(func); parm = RNA_def_pointer(func, "search_data", "AnyType", "", "Data from which to take collection to search in"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "search_property", NULL, 0, "", "Identifier of search collection property"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); api_ui_item_common(func); func = RNA_def_function(srna, "operator", "rna_uiItemO"); @@ -559,21 +559,21 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item"); parm = RNA_def_pointer(func, "properties", "OperatorProperties", "", "Operator properties to fill in, return when 'properties' is set to true"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); RNA_def_function_return(func, parm); RNA_def_function_ui_description(func, "Item. Places a button into the layout to call an Operator"); func = RNA_def_function(srna, "operator_enum", "uiItemsEnumO"); parm = RNA_def_string(func, "operator", NULL, 0, "", "Identifier of the operator"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "operator_menu_enum", "rna_uiItemMenuEnumO"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); api_ui_item_op(func); /* cant use api_ui_item_op_common because property must come right after */ parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); api_ui_item_common(func); /* useful in C but not in python */ @@ -582,39 +582,39 @@ void RNA_api_ui_layout(StructRNA *srna) func = RNA_def_function(srna, "operator_enum_single", "uiItemEnumO_string"); api_ui_item_op_common(func); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "value", NULL, 0, "", "Enum property value"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "operator_boolean", "uiItemBooleanO"); api_ui_item_op_common(func); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_boolean(func, "value", false, "", "Value of the property to call the operator with"); - RNA_def_property_flag(parm, PROP_REQUIRED); */ + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); */ func = RNA_def_function(srna, "operator_int", "uiItemIntO"); api_ui_item_op_common(func); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "value", 0, INT_MIN, INT_MAX, "", "Value of the property to call the operator with", INT_MIN, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); */ + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); */ func = RNA_def_function(srna, "operator_float", "uiItemFloatO"); api_ui_item_op_common(func); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_float(func, "value", 0, -FLT_MAX, FLT_MAX, "", "Value of the property to call the operator with", -FLT_MAX, FLT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); */ + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); */ func = RNA_def_function(srna, "operator_string", "uiItemStringO"); api_ui_item_op_common(func); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in operator"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "value", NULL, 0, "", "Value of the property to call the operator with"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); #endif func = RNA_def_function(srna, "label", "rna_uiItemL"); @@ -627,7 +627,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_string(func, "menu", NULL, 0, "", "Identifier of the menu"); api_ui_item_common(func); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_property(func, "icon_value", PROP_INT, PROP_UNSIGNED); RNA_def_property_ui_text(parm, "Icon Value", "Override automatic icon of the item"); @@ -637,9 +637,9 @@ void RNA_api_ui_layout(StructRNA *srna) /* context */ func = RNA_def_function(srna, "context_pointer_set", "uiLayoutSetContextPointer"); parm = RNA_def_string(func, "name", NULL, 0, "Name", "Name of entry in the context"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "data", "AnyType", "", "Pointer to put in context"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); /* templates */ func = RNA_def_function(srna, "template_header", "uiTemplateHeader"); @@ -664,35 +664,35 @@ void RNA_api_ui_layout(StructRNA *srna) func = RNA_def_function(srna, "template_any_ID", "rna_uiTemplateAnyID"); parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "type_property", NULL, 0, "", "Identifier of property in data giving the type of the ID-blocks to use"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); api_ui_item_common_text(func); func = RNA_def_function(srna, "template_path_builder", "rna_uiTemplatePathBuilder"); parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "root", "ID", "", "ID-block from which path is evaluated from"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); api_ui_item_common_text(func); func = RNA_def_function(srna, "template_modifier", "uiTemplateModifier"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); RNA_def_function_ui_description(func, "Generates the UI layout for modifiers"); parm = RNA_def_pointer(func, "data", "Modifier", "", "Modifier data"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "template_constraint", "uiTemplateConstraint"); RNA_def_function_ui_description(func, "Generates the UI layout for constraints"); parm = RNA_def_pointer(func, "data", "Constraint", "", "Constraint data"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in"); RNA_def_function_return(func, parm); @@ -700,7 +700,7 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description(func, "Item. A preview window for materials, textures, lamps or worlds"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "id", "ID", "", "ID data-block"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "show_buttons", true, "", "Show preview buttons?"); RNA_def_pointer(func, "parent", "ID", "", "ID data-block"); RNA_def_pointer(func, "slot", "TextureSlot", "", "Texture slot"); @@ -742,11 +742,11 @@ void RNA_api_ui_layout(StructRNA *srna) func = RNA_def_function(srna, "template_layers", "uiTemplateLayers"); api_ui_item_rna_common(func); parm = RNA_def_pointer(func, "used_layers_data", "AnyType", "", "Data from which to take property"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "used_layers_property", NULL, 0, "", "Identifier of property in data"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "active_layer", 0, 0, INT_MAX, "Active Layer", "", 0, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "template_color_picker", "uiTemplateColorPicker"); RNA_def_function_ui_description(func, "Item. A color wheel widget to pick colors"); @@ -764,34 +764,34 @@ void RNA_api_ui_layout(StructRNA *srna) func = RNA_def_function(srna, "template_image_layers", "uiTemplateImageLayers"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "image", "Image", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "image_user", "ImageUser", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "template_image", "uiTemplateImage"); RNA_def_function_ui_description(func, "Item(s). User interface for selecting images and their source paths"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); api_ui_item_rna_common(func); parm = RNA_def_pointer(func, "image_user", "ImageUser", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_boolean(func, "compact", false, "", "Use more compact layout"); RNA_def_boolean(func, "multiview", false, "", "Expose Multi-View options"); func = RNA_def_function(srna, "template_image_settings", "uiTemplateImageSettings"); RNA_def_function_ui_description(func, "User interface for setting image format options"); parm = RNA_def_pointer(func, "image_settings", "ImageFormatSettings", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_boolean(func, "color_management", false, "", "Show color management settings"); func = RNA_def_function(srna, "template_image_stereo_3d", "uiTemplateImageStereo3d"); RNA_def_function_ui_description(func, "User interface for setting image stereo 3d options"); parm = RNA_def_pointer(func, "stereo_3d_format", "Stereo3dFormat", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); func = RNA_def_function(srna, "template_image_views", "uiTemplateImageViews"); RNA_def_function_ui_description(func, "User interface for setting image views output options"); parm = RNA_def_pointer(func, "image_settings", "ImageFormatSettings", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); func = RNA_def_function(srna, "template_movieclip", "uiTemplateMovieClip"); RNA_def_function_ui_description(func, "Item(s). User interface for selecting movie clips and their source paths"); @@ -807,22 +807,22 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_ui_description(func, "Item. A widget to control single marker settings."); api_ui_item_rna_common(func); parm = RNA_def_pointer(func, "clip_user", "MovieClipUser", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_pointer(func, "track", "MovieTrackingTrack", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); RNA_def_boolean(func, "compact", false, "", "Use more compact layout"); func = RNA_def_function(srna, "template_movieclip_information", "uiTemplateMovieclipInformation"); RNA_def_function_ui_description(func, "Item. Movie clip information data."); api_ui_item_rna_common(func); parm = RNA_def_pointer(func, "clip_user", "MovieClipUser", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); func = RNA_def_function(srna, "template_list", "uiTemplateList"); RNA_def_function_ui_description(func, "Item. A list widget to display data, e.g. vertexgroups."); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_string(func, "listtype_name", NULL, 0, "", "Identifier of the list type to use"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "list_id", NULL, 0, "", "Identifier of this list widget (mandatory when using default \"" UI_UL_DEFAULT_CLASS_NAME "\" class). " @@ -831,15 +831,15 @@ void RNA_api_ui_layout(StructRNA *srna) "class name is \"OBJECT_UL_vgroups\", and list_id is not set by the " "script, then bl_idname = \"OBJECT_UL_vgroups\")"); parm = RNA_def_pointer(func, "dataptr", "AnyType", "", "Data from which to take the Collection property"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "propname", NULL, 0, "", "Identifier of the Collection property in data"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "active_dataptr", "AnyType", "", "Data from which to take the integer property, index of the active item"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "active_propname", NULL, 0, "", "Identifier of the integer property in active_data, index of the active item"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_string(func, "item_dyntip_propname", NULL, 0, "", "Identifier of a string property in items, to use as tooltip content"); RNA_def_int(func, "rows", 5, 0, INT_MAX, "", "Default and minimum number of rows to display", 0, INT_MAX); @@ -866,34 +866,34 @@ void RNA_api_ui_layout(StructRNA *srna) func = RNA_def_function(srna, "template_node_link", "uiTemplateNodeLink"); parm = RNA_def_pointer(func, "ntree", "NodeTree", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "node", "Node", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "socket", "NodeSocket", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "template_node_view", "uiTemplateNodeView"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "ntree", "NodeTree", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "node", "Node", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "socket", "NodeSocket", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "template_texture_user", "uiTemplateTextureUser"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); func = RNA_def_function(srna, "template_keymap_item_properties", "uiTemplateKeymapItemProperties"); parm = RNA_def_pointer(func, "item", "KeyMapItem", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); func = RNA_def_function(srna, "template_component_menu", "uiTemplateComponentMenu"); RNA_def_function_ui_description(func, "Item. Display expanded property in a popup menu"); parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR); parm = RNA_def_string(func, "property", NULL, 0, "", "Identifier of property in data"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_string(func, "name", NULL, 0, "", ""); func = RNA_def_function(srna, "introspect", "uiLayoutIntrospect"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index ffdc5bb0592..beb1d890ba9 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -4612,8 +4612,8 @@ static void rna_def_userdef_addon_collection(BlenderRNA *brna, PropertyRNA *cpro RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove add-on"); parm = RNA_def_pointer(func, "addon", "Addon", "", "Add-on to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_userdef_autoexec_path_collection(BlenderRNA *brna, PropertyRNA *cprop) @@ -4638,8 +4638,8 @@ static void rna_def_userdef_autoexec_path_collection(BlenderRNA *brna, PropertyR RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove path"); parm = RNA_def_pointer(func, "pathcmp", "PathCompare", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } void RNA_def_userdef(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index 8d0b704a402..1f23ab938fb 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -340,11 +340,11 @@ static void rna_generic_op_invoke(FunctionRNA *func, int flag) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "operator", "Operator", "", "Operator to call"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); if (flag & WM_GEN_INVOKE_EVENT) { parm = RNA_def_pointer(func, "event", "Event", "", "Event"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); } if (flag & WM_GEN_INVOKE_SIZE) { @@ -365,21 +365,21 @@ void RNA_api_window(StructRNA *srna) func = RNA_def_function(srna, "cursor_warp", "WM_cursor_warp"); parm = RNA_def_int(func, "x", 0, INT_MIN, INT_MAX, "", "", INT_MIN, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_int(func, "y", 0, INT_MIN, INT_MAX, "", "", INT_MIN, INT_MAX); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_function_ui_description(func, "Set the cursor position"); func = RNA_def_function(srna, "cursor_set", "WM_cursor_set"); parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(parm, rna_enum_window_cursor_items); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_function_ui_description(func, "Set the cursor"); func = RNA_def_function(srna, "cursor_modal_set", "WM_cursor_modal_set"); parm = RNA_def_property(func, "cursor", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(parm, rna_enum_window_cursor_items); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_function_ui_description(func, "Set the cursor, so the previous cursor can be restored"); RNA_def_function(srna, "cursor_modal_restore", "WM_cursor_modal_restore"); @@ -402,14 +402,14 @@ void RNA_api_wm(StructRNA *srna) "(called by invoke() with self, just before returning {'RUNNING_MODAL'})"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "operator", "Operator", "", "Operator to call"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_function_return(func, RNA_def_boolean(func, "handle", 1, "", "Whether adding the handler was successful")); func = RNA_def_function(srna, "event_timer_add", "rna_event_timer_add"); RNA_def_function_ui_description(func, "Add a timer to the given window, to generate periodic 'TIMER' events"); parm = RNA_def_property(func, "time_step", PROP_FLOAT, PROP_NONE); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_range(parm, 0.0, FLT_MAX); RNA_def_property_ui_text(parm, "Time Step", "Interval in seconds between timer events"); RNA_def_pointer(func, "window", "Window", "", "Window to attach the timer to, or None"); @@ -419,22 +419,22 @@ void RNA_api_wm(StructRNA *srna) func = RNA_def_function(srna, "event_timer_remove", "rna_event_timer_remove"); parm = RNA_def_pointer(func, "timer", "Timer", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* Progress bar interface */ func = RNA_def_function(srna, "progress_begin", "rna_progress_begin"); RNA_def_function_ui_description(func, "Start progress report"); parm = RNA_def_property(func, "min", PROP_FLOAT, PROP_NONE); RNA_def_property_ui_text(parm, "min", "any value in range [0,9999]"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_property(func, "max", PROP_FLOAT, PROP_NONE); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_ui_text(parm, "max", "any value in range [min+1,9998]"); func = RNA_def_function(srna, "progress_update", "rna_progress_update"); RNA_def_function_ui_description(func, "Update the progress feedback"); parm = RNA_def_property(func, "value", PROP_FLOAT, PROP_NONE); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_ui_text(parm, "value", "Any value between min and max as set in progress_begin()"); func = RNA_def_function(srna, "progress_end", "rna_progress_end"); @@ -474,39 +474,39 @@ void RNA_api_wm(StructRNA *srna) func = RNA_def_function(srna, "pupmenu_begin__internal", "rna_PupMenuBegin"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); parm = RNA_def_string(func, "title", NULL, 0, "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(parm, rna_enum_icon_items); /* return */ parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", ""); - RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR); RNA_def_function_return(func, parm); /* wrap UI_popup_menu_end */ func = RNA_def_function(srna, "pupmenu_end__internal", "rna_PupMenuEnd"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", ""); - RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR); /* wrap uiPieMenuBegin */ func = RNA_def_function(srna, "piemenu_begin__internal", "rna_PieMenuBegin"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); parm = RNA_def_string(func, "title", NULL, 0, "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(parm, rna_enum_icon_items); parm = RNA_def_pointer(func, "event", "Event", "", ""); - RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR); /* return */ parm = RNA_def_pointer(func, "menu_pie", "UIPieMenu", "", ""); - RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR); RNA_def_function_return(func, parm); /* wrap uiPieMenuEnd */ func = RNA_def_function(srna, "piemenu_end__internal", "rna_PieMenuEnd"); RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "menu", "UIPieMenu", "", ""); - RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_RNAPTR); } void RNA_api_operator(StructRNA *srna) @@ -517,9 +517,9 @@ void RNA_api_operator(StructRNA *srna) /* utility, not for registering */ func = RNA_def_function(srna, "report", "rna_Operator_report"); parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "message", NULL, 0, "Report Message", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* Registration */ @@ -530,14 +530,14 @@ void RNA_api_operator(StructRNA *srna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", "")); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* exec */ func = RNA_def_function(srna, "execute", NULL); RNA_def_function_ui_description(func, "Execute the operator"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* better name? */ parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", ""); @@ -548,7 +548,7 @@ void RNA_api_operator(StructRNA *srna) RNA_def_function_ui_description(func, "Check the operator settings, return True to signal a change to redraw"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_boolean(func, "result", 0, "result", ""); /* better name? */ RNA_def_function_return(func, parm); @@ -558,9 +558,9 @@ void RNA_api_operator(StructRNA *srna) RNA_def_function_ui_description(func, "Invoke the operator"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "event", "Event", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* better name? */ parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", ""); @@ -570,9 +570,9 @@ void RNA_api_operator(StructRNA *srna) RNA_def_function_ui_description(func, "Modal operator function"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_pointer(func, "event", "Event", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* better name? */ parm = RNA_def_enum_flag(func, "result", rna_enum_operator_return_items, OPERATOR_CANCELLED, "result", ""); @@ -583,14 +583,14 @@ void RNA_api_operator(StructRNA *srna) RNA_def_function_ui_description(func, "Draw function for the operator"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* cancel */ func = RNA_def_function(srna, "cancel", NULL); RNA_def_function_ui_description(func, "Called when the operator is canceled"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL | FUNC_ALLOW_WRITE); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); } void RNA_api_macro(StructRNA *srna) @@ -601,9 +601,9 @@ void RNA_api_macro(StructRNA *srna) /* utility, not for registering */ func = RNA_def_function(srna, "report", "rna_Operator_report"); parm = RNA_def_enum_flag(func, "type", rna_enum_wm_report_items, 0, "Type", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_string(func, "message", NULL, 0, "Report Message", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); /* Registration */ @@ -614,14 +614,14 @@ void RNA_api_macro(StructRNA *srna) RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_REGISTER_OPTIONAL); RNA_def_function_return(func, RNA_def_boolean(func, "visible", 1, "", "")); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); /* draw */ func = RNA_def_function(srna, "draw", NULL); RNA_def_function_ui_description(func, "Draw function for the operator"); RNA_def_function_flag(func, FUNC_REGISTER_OPTIONAL); parm = RNA_def_pointer(func, "context", "Context", "", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); } void RNA_api_keyconfig(StructRNA *UNUSED(srna)) @@ -646,7 +646,7 @@ void RNA_api_keymap(StructRNA *srna) func = RNA_def_function(srna, "restore_item_to_default", "rna_keymap_restore_item_to_default"); RNA_def_function_flag(func, FUNC_USE_CONTEXT); parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); } void RNA_api_keymapitem(StructRNA *srna) @@ -656,7 +656,7 @@ void RNA_api_keymapitem(StructRNA *srna) func = RNA_def_function(srna, "compare", "WM_keymap_item_compare"); parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_boolean(func, "result", 0, "Comparison result", ""); RNA_def_function_return(func, parm); } @@ -669,11 +669,11 @@ void RNA_api_keymapitems(StructRNA *srna) func = RNA_def_function(srna, "new", "rna_KeyMap_item_new"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "idname", NULL, 0, "Operator Identifier", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", rna_enum_event_type_items, 0, "Type", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "value", rna_enum_event_value_items, 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "any", 0, "Any", ""); RNA_def_boolean(func, "shift", 0, "Shift", ""); RNA_def_boolean(func, "ctrl", 0, "Ctrl", ""); @@ -689,11 +689,11 @@ void RNA_api_keymapitems(StructRNA *srna) func = RNA_def_function(srna, "new_modal", "rna_KeyMap_item_new_modal"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_string(func, "propvalue", NULL, 0, "Property Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "type", rna_enum_event_type_items, 0, "Type", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_enum(func, "value", rna_enum_event_value_items, 0, "Value", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_boolean(func, "any", 0, "Any", ""); RNA_def_boolean(func, "shift", 0, "Shift", ""); RNA_def_boolean(func, "ctrl", 0, "Ctrl", ""); @@ -706,12 +706,12 @@ void RNA_api_keymapitems(StructRNA *srna) func = RNA_def_function(srna, "remove", "rna_KeyMap_item_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "from_id", "WM_keymap_item_find_id"); parm = RNA_def_property(func, "id", PROP_INT, PROP_NONE); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_property_ui_text(parm, "id", "ID of the item"); parm = RNA_def_pointer(func, "item", "KeyMapItem", "Item", ""); RNA_def_function_return(func, parm); @@ -724,7 +724,7 @@ void RNA_api_keymaps(StructRNA *srna) func = RNA_def_function(srna, "new", "rna_keymap_new"); /* add_keymap */ parm = RNA_def_string(func, "name", NULL, 0, "Name", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", ""); RNA_def_enum(func, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", ""); RNA_def_boolean(func, "modal", 0, "Modal", ""); @@ -734,12 +734,12 @@ void RNA_api_keymaps(StructRNA *srna) func = RNA_def_function(srna, "remove", "rna_KeyMap_remove"); /* remove_keymap */ RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Removed key map"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); func = RNA_def_function(srna, "find", "rna_keymap_find"); /* find_keymap */ parm = RNA_def_string(func, "name", NULL, 0, "Name", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", ""); RNA_def_enum(func, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", ""); parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map"); @@ -747,7 +747,7 @@ void RNA_api_keymaps(StructRNA *srna) func = RNA_def_function(srna, "find_modal", "rna_keymap_find_modal"); /* find_keymap_modal */ parm = RNA_def_string(func, "name", NULL, 0, "Operator Name", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "keymap", "KeyMap", "Key Map", "Corresponding key map"); RNA_def_function_return(func, parm); } @@ -759,15 +759,15 @@ void RNA_api_keyconfigs(StructRNA *srna) func = RNA_def_function(srna, "new", "WM_keyconfig_new_user"); /* add_keyconfig */ parm = RNA_def_string(func, "name", NULL, 0, "Name", ""); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); parm = RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Added key configuration"); RNA_def_function_return(func, parm); func = RNA_def_function(srna, "remove", "rna_KeyConfig_remove"); /* remove_keyconfig */ RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "keyconfig", "KeyConfig", "Key Configuration", "Removed key configuration"); - RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); - RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } #endif diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index ab523e03f4d..2fd46ab94f0 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -1636,7 +1636,7 @@ static int pyrna_py_to_prop( /* prefer not to have an exception here * however so many poll functions return None or a valid Object. * its a hassle to convert these into a bool before returning, */ - if (RNA_property_flag(prop) & PROP_OUTPUT) { + if (RNA_parameter_flag(prop) & PARM_OUTPUT) { param = PyObject_IsTrue(value); } else { @@ -1824,6 +1824,7 @@ static int pyrna_py_to_prop( StructRNA *ptr_type = RNA_property_pointer_type(ptr, prop); int flag = RNA_property_flag(prop); + int flag_parameter = RNA_parameter_flag(prop); /* this is really nasty!, so we can fake the operator having direct properties eg: * layout.prop(self, "filepath") @@ -1900,7 +1901,7 @@ static int pyrna_py_to_prop( bool raise_error = false; if (data) { - if (flag & PROP_RNAPTR) { + if (flag_parameter & PARM_RNAPTR) { if (flag & PROP_THICK_WRAP) { if (value == Py_None) memset(data, 0, sizeof(PointerRNA)); @@ -5116,6 +5117,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat PyObject *ret; const int type = RNA_property_type(prop); const int flag = RNA_property_flag(prop); + const int flag_parameter = RNA_parameter_flag(prop); if (RNA_property_array_check(prop)) { int a, len; @@ -5233,7 +5235,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat PointerRNA newptr; StructRNA *ptype = RNA_property_pointer_type(ptr, prop); - if (flag & PROP_RNAPTR) { + if (flag_parameter & PARM_RNAPTR) { /* in this case we get the full ptr */ newptr = *(PointerRNA *)data; } @@ -5315,7 +5317,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject ParameterIterator iter; PropertyRNA *parm; PyObject *ret, *item; - int i, pyargs_len, pykw_len, parms_len, ret_len, flag, err = 0, kw_tot = 0; + int i, pyargs_len, pykw_len, parms_len, ret_len, flag_parameter, err = 0, kw_tot = 0; bool kw_arg; PropertyRNA *pret_single = NULL; @@ -5380,10 +5382,10 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject /* parse function parameters */ for (i = 0; iter.valid && err == 0; RNA_parameter_list_next(&iter)) { parm = iter.parm; - flag = RNA_property_flag(parm); + flag_parameter = RNA_parameter_flag(parm); /* only useful for single argument returns, we'll need another list loop for multiple */ - if (flag & PROP_OUTPUT) { + if (flag_parameter & PARM_OUTPUT) { ret_len++; if (pret_single == NULL) { pret_single = parm; @@ -5414,7 +5416,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject i++; /* current argument */ if (item == NULL) { - if (flag & PROP_REQUIRED) { + if (flag_parameter & PARM_REQUIRED) { PyErr_Format(PyExc_TypeError, "%.200s.%.200s(): required parameter \"%.200s\" not specified", RNA_struct_identifier(self_ptr->type), @@ -5514,7 +5516,7 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject RNA_parameter_list_begin(&parms, &iter); for (; iter.valid; RNA_parameter_list_next(&iter)) { parm = iter.parm; - if (RNA_property_flag(parm) & PROP_OUTPUT) + if (RNA_parameter_flag(parm) & PARM_OUTPUT) continue; BLI_dynstr_appendf(good_args, first ? "%s" : ", %s", RNA_property_identifier(parm)); @@ -5561,9 +5563,8 @@ static PyObject *pyrna_func_call(BPy_FunctionRNA *self, PyObject *args, PyObject for (; iter.valid; RNA_parameter_list_next(&iter)) { parm = iter.parm; - flag = RNA_property_flag(parm); - if (flag & PROP_OUTPUT) + if (RNA_parameter_flag(parm) & PARM_OUTPUT) PyTuple_SET_ITEM(ret, i++, pyrna_param_to_py(&funcptr, parm, iter.data)); } @@ -7216,8 +7217,8 @@ static int rna_function_arg_count(FunctionRNA *func, int *min_count) for (link = lb->first; link; link = link->next) { parm = (PropertyRNA *)link; - if (!(RNA_property_flag(parm) & PROP_OUTPUT)) { - if (!done_min_count && (RNA_property_flag(parm) & PROP_PYFUNC_OPTIONAL)) { + if (!(RNA_parameter_flag(parm) & PARM_OUTPUT)) { + if (!done_min_count && (RNA_parameter_flag(parm) & PARM_PYFUNC_OPTIONAL)) { /* From now on, following parameters are optional in py func */ if (min_count) *min_count = count; @@ -7575,10 +7576,9 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param /* parse function parameters */ for (; iter.valid; RNA_parameter_list_next(&iter)) { parm = iter.parm; - flag = RNA_property_flag(parm); /* only useful for single argument returns, we'll need another list loop for multiple */ - if (flag & PROP_OUTPUT) { + if (RNA_parameter_flag(parm) & PARM_OUTPUT) { ret_len++; if (pret_single == NULL) { pret_single = parm; @@ -7678,10 +7678,9 @@ static int bpy_class_call(bContext *C, PointerRNA *ptr, FunctionRNA *func, Param /* parse function parameters */ for (i = 0; iter.valid; RNA_parameter_list_next(&iter)) { parm = iter.parm; - flag = RNA_property_flag(parm); /* only useful for single argument returns, we'll need another list loop for multiple */ - if (flag & PROP_OUTPUT) { + if (RNA_parameter_flag(parm) & PARM_OUTPUT) { err = pyrna_py_to_prop(&funcptr, parm, iter.data, PyTuple_GET_ITEM(ret, i++), "calling class function:"); @@ -7967,7 +7966,7 @@ static int pyrna_srna_contains_pointer_prop_srna( for (link = lb->first; link; link = link->next) { prop = (PropertyRNA *)link; - if (RNA_property_type(prop) == PROP_POINTER && !(RNA_property_flag(prop) & PROP_BUILTIN)) { + if (RNA_property_type(prop) == PROP_POINTER && !RNA_property_builtin(prop)) { PointerRNA tptr; RNA_pointer_create(NULL, &RNA_Struct, srna_props, &tptr); From 7415b9ffa310d8f55e38861b84d2f275f4d36370 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 12 Dec 2016 15:54:16 +0100 Subject: [PATCH 382/590] Fix (unreported) some RNA func definitions setting flags of other func parameters! Both found cases where luckily harmless, though... --- source/blender/makesrna/intern/rna_depsgraph.c | 3 +-- source/blender/makesrna/intern/rna_render.c | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c index b0e02a4eeb0..2748bd8b877 100644 --- a/source/blender/makesrna/intern/rna_depsgraph.c +++ b/source/blender/makesrna/intern/rna_depsgraph.c @@ -97,8 +97,7 @@ static void rna_def_depsgraph(BlenderRNA *brna) func = RNA_def_function(srna, "debug_rebuild", "rna_Depsgraph_debug_rebuild"); RNA_def_function_flag(func, FUNC_USE_MAIN); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); - + func = RNA_def_function(srna, "debug_stats", "rna_Depsgraph_debug_stats"); RNA_def_function_ui_description(func, "Report the number of elements in the Dependency Graph"); RNA_def_function_flag(func, FUNC_USE_REPORTS); diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 946b20c916d..d69ae2b78bb 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -575,7 +575,6 @@ static void rna_def_render_engine(BlenderRNA *brna) RNA_def_function_ui_description(func, "Update memory usage statistics"); RNA_def_float(func, "memory_used", 0, 0.0f, FLT_MAX, "", "Current memory usage in megabytes", 0.0f, FLT_MAX); RNA_def_float(func, "memory_peak", 0, 0.0f, FLT_MAX, "", "Peak memory usage in megabytes", 0.0f, FLT_MAX); - RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); func = RNA_def_function(srna, "report", "RE_engine_report"); RNA_def_function_ui_description(func, "Report info, warning or error messages"); From 5f852a4324212221500d11b2c7594f5e0ca894c6 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 12 Dec 2016 15:56:00 +0100 Subject: [PATCH 383/590] Cleanup: bad (harmless) usage of PARM_PYFUNC_OPTIONAL in new ID.make_local RNA definition. PARM_PYFUNC_OPTIONAL is only useful in definition of callbacks for registrable types... --- source/blender/makesrna/intern/rna_ID.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index ee43a619f41..671902c5cc7 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -1023,7 +1023,6 @@ static void rna_def_ID(BlenderRNA *brna) parm = RNA_def_boolean(func, "clear_proxy", true, "", "Whether to clear proxies (the default behavior, " "note that if object has to be duplicated to be made local, proxies are always cleared)"); - RNA_def_property_flag(parm, PARM_PYFUNC_OPTIONAL); parm = RNA_def_pointer(func, "id", "ID", "", "This ID, or the new ID if it was copied"); RNA_def_function_return(func, parm); From 356dacea9095daa491d5deaa17772e7890e1a285 Mon Sep 17 00:00:00 2001 From: Karsten Weiss <> Date: Tue, 13 Dec 2016 10:15:40 +0100 Subject: [PATCH 384/590] Libmv: Fix copy-paste mistake in camera intrinsic parameters --- intern/libmv/intern/camera_intrinsics.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc index 24a34ae40bb..c9aea30b893 100644 --- a/intern/libmv/intern/camera_intrinsics.cc +++ b/intern/libmv/intern/camera_intrinsics.cc @@ -179,7 +179,7 @@ void libmv_cameraIntrinsicsExtractOptions( camera_intrinsics_options->polynomial_k2 = polynomial_intrinsics->k2(); camera_intrinsics_options->polynomial_k3 = polynomial_intrinsics->k3(); camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p1(); - camera_intrinsics_options->polynomial_p1 = polynomial_intrinsics->p2(); + camera_intrinsics_options->polynomial_p2 = polynomial_intrinsics->p2(); break; } From 9446b6809af4a55ddd2f822fefe3c3fd8e82f40a Mon Sep 17 00:00:00 2001 From: Karsten Weiss <> Date: Tue, 13 Dec 2016 10:16:20 +0100 Subject: [PATCH 385/590] Libmv: Fix typo in assert message --- intern/libmv/intern/camera_intrinsics.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/libmv/intern/camera_intrinsics.cc b/intern/libmv/intern/camera_intrinsics.cc index c9aea30b893..3b4cd1545df 100644 --- a/intern/libmv/intern/camera_intrinsics.cc +++ b/intern/libmv/intern/camera_intrinsics.cc @@ -195,7 +195,7 @@ void libmv_cameraIntrinsicsExtractOptions( } default: - assert(!"Uknown distortion model"); + assert(!"Unknown distortion model"); } } From 8bae72d04a77ba3ed8ea43735aa0d021122766f7 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 13 Dec 2016 10:18:02 +0100 Subject: [PATCH 386/590] Fix strict compiler error when building without bullet --- source/blender/blenkernel/intern/rigidbody.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 747f5775aff..b5f34a29ebb 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -1624,7 +1624,6 @@ void BKE_rigidbody_do_simulation(Scene *scene, float ctime) struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; } struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; } -void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) {} void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) {} void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { if (r_vol) *r_vol = 0.0f; } void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_center[3]) { zero_v3(r_center); } From ec2fd74f4728f9051d0621fb56cae6bc67cce596 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 13 Dec 2016 16:46:04 +0100 Subject: [PATCH 387/590] Fix strict warnings on Windows --- extern/curve_fit_nd/curve_fit_nd.h | 2 +- source/blender/editors/mesh/editmesh_undo.c | 4 +++- source/blender/makesdna/intern/dna_genfile.c | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/extern/curve_fit_nd/curve_fit_nd.h b/extern/curve_fit_nd/curve_fit_nd.h index cfb1881fe00..7232f802e28 100644 --- a/extern/curve_fit_nd/curve_fit_nd.h +++ b/extern/curve_fit_nd/curve_fit_nd.h @@ -137,7 +137,7 @@ int curve_fit_cubic_to_points_refit_db( const double error_threshold, const unsigned int calc_flag, const unsigned int *corners, - unsigned int corners_len, + const unsigned int corners_len, const double corner_angle, double **r_cubic_array, unsigned int *r_cubic_array_len, diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index c9814d189a4..534ca22178e 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -369,7 +369,9 @@ struct UMArrayData { UndoMesh *um; const UndoMesh *um_ref; /* can be NULL */ }; -static void um_arraystore_compact_cb(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid)) +static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool), + void *taskdata, + int UNUSED(threadid)) { struct UMArrayData *um_data = taskdata; um_arraystore_compact_with_info(um_data->um, um_data->um_ref); diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index 96085a79eff..181d01e04fc 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -169,7 +169,7 @@ void DNA_sdna_free(SDNA *sdna) } MEM_freeN((void *)sdna->names); - MEM_freeN(sdna->types); + MEM_freeN((void *)sdna->types); MEM_freeN(sdna->structs); #ifdef WITH_DNA_GHASH From c1267bb8008bd903ab819ca8c56de6fdbf902003 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 13 Dec 2016 16:45:07 +0100 Subject: [PATCH 388/590] UI: Externally open file and path from context menu Adds two buttons to context (RMB) menu of path buttons: * "Open File Externally" to open a file in an external app (only visible if path contains a filename) * "Open Location Externally" to open a path in an external file browser The functionallity for this was already there, just hidden behind Shift/Alt click of file_browse button (folder icon next to path button). --- .../editors/interface/interface_handlers.c | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 33f1d5e93cb..8c9f4ff422a 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -50,6 +50,7 @@ #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_linklist.h" +#include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_string_utf8.h" #include "BLI_string_cursor_utf8.h" @@ -6703,6 +6704,35 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa) UI_popup_menu_end(C, pup); } +static void ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop) +{ + const PropertySubType subtype = RNA_property_subtype(prop); + wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true); + char filepath[FILE_MAX]; + char dir[FILE_MAXDIR]; + char file[FILE_MAXFILE]; + PointerRNA props_ptr; + + BLI_assert(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)); + + RNA_property_string_get(ptr, prop, filepath); + BLI_split_dirfile(filepath, dir, file, sizeof(dir), sizeof(file)); + + if (file[0]) { + BLI_assert(subtype == PROP_FILEPATH); + + props_ptr = uiItemFullO_ptr( + layout, ot, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open File Externally"), + ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_string_set(&props_ptr, "filepath", filepath); + } + + props_ptr = uiItemFullO_ptr( + layout, ot, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Open Location Externally"), + ICON_NONE, NULL, WM_OP_INVOKE_DEFAULT, UI_ITEM_O_RETURN_PROPS); + RNA_string_set(&props_ptr, "filepath", dir); +} + static bool ui_but_menu(bContext *C, uiBut *but) { uiPopupMenu *pup; @@ -6731,6 +6761,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) if (but->rnapoin.data && but->rnaprop) { PointerRNA *ptr = &but->rnapoin; PropertyRNA *prop = but->rnaprop; + const PropertyType type = RNA_property_type(prop); + const PropertySubType subtype = RNA_property_subtype(prop); bool is_anim = RNA_property_animateable(ptr, prop); bool is_editable = RNA_property_editable(ptr, prop); /*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */ @@ -6901,6 +6933,11 @@ static bool ui_but_menu(bContext *C, uiBut *but) ICON_NONE, "UI_OT_copy_data_path_button"); uiItemS(layout); + + if (type == PROP_STRING && ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)) { + ui_but_menu_add_path_operators(layout, ptr, prop); + uiItemS(layout); + } } /* Operator buttons */ From c21a5139e1f263c0c7acd80ec49d5e3ecbff8456 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Tue, 13 Dec 2016 20:15:53 +0100 Subject: [PATCH 389/590] Small cleanup: Remove unused code This code has not been used for a long time if not ever. Most of the code was removed in rB1d3609262704f88c9e30b2cebdb236110b25cdc9 however, this was forgoten. --- release/scripts/startup/bl_operators/wm.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 68a25acc2db..f5460d58d44 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -656,11 +656,6 @@ doc_id = StringProperty( options={'HIDDEN'}, ) -doc_new = StringProperty( - name="Edit Description", - maxlen=1024, - ) - data_path_iter = StringProperty( description="The data path relative to the context, must point to an iterable") From fbcd51aef86a69fb99ae5cba51da6401f6c3dca4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 14 Dec 2016 10:44:57 +0100 Subject: [PATCH 390/590] Fix T50243: libmv_panography_test is broken There was fully wrong logic in comparison: was actually accessing memory past the array boundary. Run test manually and the figure seems correct to me now. Spotted by @LazyDodo, thanks! --- intern/libmv/libmv/multiview/panography_test.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/libmv/libmv/multiview/panography_test.cc b/intern/libmv/libmv/multiview/panography_test.cc index f6faf0f6022..96d52acfc3c 100644 --- a/intern/libmv/libmv/multiview/panography_test.cc +++ b/intern/libmv/libmv/multiview/panography_test.cc @@ -48,7 +48,7 @@ TEST(Panography, PrintSomeSharedFocalEstimationValues) { // Assert we found a valid solution. EXPECT_EQ(1, fs.size()); - EXPECT_NEAR(1.01667, fs[1], 1e-3); + EXPECT_NEAR(3.47194, fs[0], 1e-3); } TEST(Panography, GetR_FixedCameraCenterWithIdentity) { From d210755f85f8539add759680aa5c407f5748ceae Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 14 Dec 2016 10:36:43 +0100 Subject: [PATCH 391/590] Usual UI messages/i18n fixes/tweaks. --- release/scripts/modules/bl_i18n_utils/utils_spell_check.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py index f749cf82bb9..949678b2fc0 100644 --- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py +++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py @@ -248,6 +248,7 @@ class SpellChecker: "amb", "anim", "app", + "bbox", "bboxes", "bool", "calc", "config", "configs", @@ -443,6 +444,7 @@ class SpellChecker: "gpencil", "idcol", "keyframe", "keyframes", "keyframing", "keyframed", + "mathvis", "metaball", "metaballs", "mball", "metaelement", "metaelements", "metastrip", "metastrips", @@ -470,6 +472,7 @@ class SpellChecker: "timeline", "timelines", "tosphere", "uilist", + "userpref", "vcol", "vcols", "vgroup", "vgroups", "vinterlace", From 72d18c195eea7aa6be43afbda7dab584893c1882 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 7 Dec 2016 10:53:07 +0100 Subject: [PATCH 392/590] Cycles: Tweak curve segment (un)pack to handle more curve segments There was 16 bits reserved for primitive type, while we only need 4. Reviewers: brecht Reviewed By: brecht Differential Revision: https://developer.blender.org/D2401 --- intern/cycles/kernel/kernel_types.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index fd961836ec9..2563f1491b1 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -550,27 +550,29 @@ typedef ccl_addr_space struct Intersection { /* Primitives */ typedef enum PrimitiveType { - PRIMITIVE_NONE = 0, - PRIMITIVE_TRIANGLE = 1, - PRIMITIVE_MOTION_TRIANGLE = 2, - PRIMITIVE_CURVE = 4, - PRIMITIVE_MOTION_CURVE = 8, - /* Lamp primitive is not included below on purpose, since it is no real traceable primitive */ - PRIMITIVE_LAMP = 16, + PRIMITIVE_NONE = 0, + PRIMITIVE_TRIANGLE = (1 << 0), + PRIMITIVE_MOTION_TRIANGLE = (1 << 1), + PRIMITIVE_CURVE = (1 << 2), + PRIMITIVE_MOTION_CURVE = (1 << 3), + /* Lamp primitive is not included below on purpose, + * since it is no real traceable primitive. + */ + PRIMITIVE_LAMP = (1 << 4), PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE|PRIMITIVE_MOTION_TRIANGLE), PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE|PRIMITIVE_MOTION_CURVE), PRIMITIVE_ALL_MOTION = (PRIMITIVE_MOTION_TRIANGLE|PRIMITIVE_MOTION_CURVE), PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE|PRIMITIVE_ALL_CURVE), - /* Total number of different primitives. + /* Total number of different traceable primitives. * NOTE: This is an actual value, not a bitflag. */ PRIMITIVE_NUM_TOTAL = 4, } PrimitiveType; -#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << 16) | type) -#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> 16) +#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM_TOTAL) | (type)) +#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM_TOTAL) /* Attributes */ From c4d6fd3ec04a93376d08e7baa89846732c01ec04 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 6 Dec 2016 15:57:16 +0100 Subject: [PATCH 393/590] Cycles: Consider GGX/Beckmann/Ashikhmin of 0 roughness a singular ray This matches behavior of Multiscatter GGX and could become handy later on when/if we decide it would be beneficial to replace on closure with another. Reviewers: lukasstockner97, brecht Reviewed By: brecht Differential Revision: https://developer.blender.org/D2413 --- .../kernel/closure/bsdf_ashikhmin_shirley.h | 4 +++- intern/cycles/kernel/closure/bsdf_microfacet.h | 16 ++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h index 1cd8246aa71..b6c896c754b 100644 --- a/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h +++ b/intern/cycles/kernel/closure/bsdf_ashikhmin_shirley.h @@ -143,6 +143,7 @@ ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng, { const MicrofacetBsdf *bsdf = (const MicrofacetBsdf*)sc; float3 N = bsdf->N; + int label = LABEL_REFLECT | LABEL_GLOSSY; float NdotI = dot(N, I); if(NdotI > 0.0f) { @@ -211,6 +212,7 @@ ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng, /* Some high number for MIS. */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); + label = LABEL_REFLECT | LABEL_SINGULAR; } else { /* leave the rest to eval_reflect */ @@ -224,7 +226,7 @@ ccl_device int bsdf_ashikhmin_shirley_sample(const ShaderClosure *sc, float3 Ng, #endif } - return LABEL_REFLECT|LABEL_GLOSSY; + return label; } diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 0a8d14a00c2..72fffe6ff69 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -452,6 +452,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure float alpha_y = bsdf->alpha_y; bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; float3 N = bsdf->N; + int label; float cosNO = dot(N, I); if(cosNO > 0) { @@ -477,6 +478,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure /* reflection or refraction? */ if(!m_refractive) { float cosMO = dot(m, I); + label = LABEL_REFLECT | LABEL_GLOSSY; if(cosMO > 0) { /* eq. 39 - compute actual reflected direction */ @@ -487,6 +489,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); + label = LABEL_REFLECT | LABEL_SINGULAR; } else { /* microfacet normal is visible to this ray */ @@ -549,6 +552,8 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure } } else { + label = LABEL_TRANSMIT | LABEL_GLOSSY; + /* CAUTION: the i and o variables are inverted relative to the paper * eq. 39 - compute actual refractive direction */ float3 R, T; @@ -576,6 +581,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); + label = LABEL_TRANSMIT | LABEL_SINGULAR; } else { /* eq. 33 */ @@ -607,7 +613,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure } } } - return (m_refractive) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; + return label; } /* Beckmann microfacet with Smith shadow-masking from: @@ -815,6 +821,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl float alpha_y = bsdf->alpha_y; bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; float3 N = bsdf->N; + int label; float cosNO = dot(N, I); if(cosNO > 0) { @@ -839,6 +846,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl /* reflection or refraction? */ if(!m_refractive) { + label = LABEL_REFLECT | LABEL_GLOSSY; float cosMO = dot(m, I); if(cosMO > 0) { @@ -850,6 +858,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); + label = LABEL_REFLECT | LABEL_SINGULAR; } else { /* microfacet normal is visible to this ray @@ -904,6 +913,8 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl } } else { + label = LABEL_TRANSMIT | LABEL_GLOSSY; + /* CAUTION: the i and o variables are inverted relative to the paper * eq. 39 - compute actual refractive direction */ float3 R, T; @@ -931,6 +942,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); + label = LABEL_TRANSMIT | LABEL_SINGULAR; } else { /* eq. 33 */ @@ -963,7 +975,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl } } } - return (m_refractive) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; + return label; } CCL_NAMESPACE_END From 696721648558aef94e8488dbef13eff758abdf08 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 14 Dec 2016 12:47:28 +0100 Subject: [PATCH 394/590] Cycles: Fix indendation --- intern/cycles/blender/blender_object.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 681a22e1f07..22cc4e6f030 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -148,8 +148,8 @@ public: BL::Array boundbox = b_ob.bound_box(); for(int i = 0; i < 8; ++i) { float3 p = make_float3(boundbox[3 * i + 0], - boundbox[3 * i + 1], - boundbox[3 * i + 2]); + boundbox[3 * i + 1], + boundbox[3 * i + 2]); bb[i] = transform_point(&tfm, p); } @@ -203,7 +203,7 @@ private: { float3 camera_position = transform_get_column(&scene->camera->matrix, 3); float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), - bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); /* Find min & max points for x & y & z on bounding box */ for(int i = 0; i < 8; ++i) { From 91bbffd37942f3c71b065b3c1365c771e1939f45 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 14 Dec 2016 13:01:33 +0100 Subject: [PATCH 395/590] Cycles: Move object culling helper to own files This is a stand-alone logic, which becomes quite comprehensive now. --- intern/cycles/blender/CMakeLists.txt | 2 + intern/cycles/blender/blender_object.cpp | 138 +--------------- intern/cycles/blender/blender_object_cull.cpp | 149 ++++++++++++++++++ intern/cycles/blender/blender_object_cull.h | 49 ++++++ 4 files changed, 201 insertions(+), 137 deletions(-) create mode 100644 intern/cycles/blender/blender_object_cull.cpp create mode 100644 intern/cycles/blender/blender_object_cull.h diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index a79deca53e1..b57502b3b14 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -25,6 +25,7 @@ set(SRC blender_camera.cpp blender_mesh.cpp blender_object.cpp + blender_object_cull.cpp blender_particles.cpp blender_curves.cpp blender_logging.cpp @@ -35,6 +36,7 @@ set(SRC blender_texture.cpp CCL_api.h + blender_object_cull.h blender_sync.h blender_session.h blender_texture.h diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 22cc4e6f030..637cf7abda8 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -25,6 +25,7 @@ #include "particles.h" #include "shader.h" +#include "blender_object_cull.h" #include "blender_sync.h" #include "blender_util.h" @@ -88,143 +89,6 @@ static uint object_ray_visibility(BL::Object& b_ob) return flag; } -/* Culling */ - -class BlenderObjectCulling -{ -public: - BlenderObjectCulling(Scene *scene, BL::Scene& b_scene) - : use_scene_camera_cull(false), - use_camera_cull(false), - camera_cull_margin(0.0f), - use_scene_distance_cull(false), - use_distance_cull(false), - distance_cull_margin(0.0f) - { - if(b_scene.render().use_simplify()) { - PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); - - use_scene_camera_cull = scene->camera->type != CAMERA_PANORAMA && - !b_scene.render().use_multiview() && - get_boolean(cscene, "use_camera_cull"); - use_scene_distance_cull = scene->camera->type != CAMERA_PANORAMA && - !b_scene.render().use_multiview() && - get_boolean(cscene, "use_distance_cull"); - - camera_cull_margin = get_float(cscene, "camera_cull_margin"); - distance_cull_margin = get_float(cscene, "distance_cull_margin"); - - if (distance_cull_margin == 0.0f) { - use_scene_distance_cull = false; - } - } - } - - void init_object(Scene *scene, BL::Object& b_ob) - { - if(!use_scene_camera_cull && !use_scene_distance_cull) { - return; - } - - PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); - - use_camera_cull = use_scene_camera_cull && get_boolean(cobject, "use_camera_cull"); - use_distance_cull = use_scene_distance_cull && get_boolean(cobject, "use_distance_cull"); - - if(use_camera_cull || use_distance_cull) { - /* Need to have proper projection matrix. */ - scene->camera->update(); - } - } - - bool test(Scene *scene, BL::Object& b_ob, Transform& tfm) - { - if(!use_camera_cull && !use_distance_cull) { - return false; - } - - /* Compute world space bounding box corners. */ - float3 bb[8]; - BL::Array boundbox = b_ob.bound_box(); - for(int i = 0; i < 8; ++i) { - float3 p = make_float3(boundbox[3 * i + 0], - boundbox[3 * i + 1], - boundbox[3 * i + 2]); - bb[i] = transform_point(&tfm, p); - } - - bool camera_culled = use_camera_cull && test_camera(scene, bb); - bool distance_culled = use_distance_cull && test_distance(scene, bb); - - return ((camera_culled && distance_culled) || - (camera_culled && !use_distance_cull) || - (distance_culled && !use_camera_cull)); - } - -private: - /* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order - * to reduce number of objects which are wrongly considered visible. - */ - bool test_camera(Scene *scene, float3 bb[8]) - { - Camera *cam = scene->camera; - Transform& worldtondc = cam->worldtondc; - float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), - bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - bool all_behind = true; - for(int i = 0; i < 8; ++i) { - float3 p = bb[i]; - float4 b = make_float4(p.x, p.y, p.z, 1.0f); - float4 c = make_float4(dot(worldtondc.x, b), - dot(worldtondc.y, b), - dot(worldtondc.z, b), - dot(worldtondc.w, b)); - p = float4_to_float3(c / c.w); - if(c.z < 0.0f) { - p.x = 1.0f - p.x; - p.y = 1.0f - p.y; - } - if(c.z >= -camera_cull_margin) { - all_behind = false; - } - bb_min = min(bb_min, p); - bb_max = max(bb_max, p); - } - if(all_behind) { - return true; - } - return (bb_min.x >= 1.0f + camera_cull_margin || - bb_min.y >= 1.0f + camera_cull_margin || - bb_max.x <= -camera_cull_margin || - bb_max.y <= -camera_cull_margin); - } - - bool test_distance(Scene *scene, float3 bb[8]) - { - float3 camera_position = transform_get_column(&scene->camera->matrix, 3); - float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), - bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); - - /* Find min & max points for x & y & z on bounding box */ - for(int i = 0; i < 8; ++i) { - float3 p = bb[i]; - bb_min = min(bb_min, p); - bb_max = max(bb_max, p); - } - - float3 closest_point = max(min(bb_max,camera_position),bb_min); - return (len_squared(camera_position - closest_point) > - distance_cull_margin * distance_cull_margin); - } - - bool use_scene_camera_cull; - bool use_camera_cull; - float camera_cull_margin; - bool use_scene_distance_cull; - bool use_distance_cull; - float distance_cull_margin; -}; - /* Light */ void BlenderSync::sync_light(BL::Object& b_parent, diff --git a/intern/cycles/blender/blender_object_cull.cpp b/intern/cycles/blender/blender_object_cull.cpp new file mode 100644 index 00000000000..b8582df0f93 --- /dev/null +++ b/intern/cycles/blender/blender_object_cull.cpp @@ -0,0 +1,149 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "camera.h" + +#include "blender_object_cull.h" + +CCL_NAMESPACE_BEGIN + +BlenderObjectCulling::BlenderObjectCulling(Scene *scene, BL::Scene& b_scene) + : use_scene_camera_cull_(false), + use_camera_cull_(false), + camera_cull_margin_(0.0f), + use_scene_distance_cull_(false), + use_distance_cull_(false), + distance_cull_margin_(0.0f) +{ + if(b_scene.render().use_simplify()) { + PointerRNA cscene = RNA_pointer_get(&b_scene.ptr, "cycles"); + + use_scene_camera_cull_ = scene->camera->type != CAMERA_PANORAMA && + !b_scene.render().use_multiview() && + get_boolean(cscene, "use_camera_cull"); + use_scene_distance_cull_ = scene->camera->type != CAMERA_PANORAMA && + !b_scene.render().use_multiview() && + get_boolean(cscene, "use_distance_cull"); + + camera_cull_margin_ = get_float(cscene, "camera_cull_margin"); + distance_cull_margin_ = get_float(cscene, "distance_cull_margin"); + + if (distance_cull_margin_ == 0.0f) { + use_scene_distance_cull_ = false; + } + } +} + +void BlenderObjectCulling::init_object(Scene *scene, BL::Object& b_ob) +{ + if(!use_scene_camera_cull_ && !use_scene_distance_cull_) { + return; + } + + PointerRNA cobject = RNA_pointer_get(&b_ob.ptr, "cycles"); + + use_camera_cull_ = use_scene_camera_cull_ && get_boolean(cobject, "use_camera_cull"); + use_distance_cull_ = use_scene_distance_cull_ && get_boolean(cobject, "use_distance_cull"); + + if(use_camera_cull_ || use_distance_cull_) { + /* Need to have proper projection matrix. */ + scene->camera->update(); + } +} + +bool BlenderObjectCulling::test(Scene *scene, BL::Object& b_ob, Transform& tfm) +{ + if(!use_camera_cull_ && !use_distance_cull_) { + return false; + } + + /* Compute world space bounding box corners. */ + float3 bb[8]; + BL::Array boundbox = b_ob.bound_box(); + for(int i = 0; i < 8; ++i) { + float3 p = make_float3(boundbox[3 * i + 0], + boundbox[3 * i + 1], + boundbox[3 * i + 2]); + bb[i] = transform_point(&tfm, p); + } + + bool camera_culled = use_camera_cull_ && test_camera(scene, bb); + bool distance_culled = use_distance_cull_ && test_distance(scene, bb); + + return ((camera_culled && distance_culled) || + (camera_culled && !use_distance_cull_) || + (distance_culled && !use_camera_cull_)); +} + +/* TODO(sergey): Not really optimal, consider approaches based on k-DOP in order + * to reduce number of objects which are wrongly considered visible. + */ +bool BlenderObjectCulling::test_camera(Scene *scene, float3 bb[8]) +{ + Camera *cam = scene->camera; + Transform& worldtondc = cam->worldtondc; + float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), + bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + bool all_behind = true; + for(int i = 0; i < 8; ++i) { + float3 p = bb[i]; + float4 b = make_float4(p.x, p.y, p.z, 1.0f); + float4 c = make_float4(dot(worldtondc.x, b), + dot(worldtondc.y, b), + dot(worldtondc.z, b), + dot(worldtondc.w, b)); + p = float4_to_float3(c / c.w); + if(c.z < 0.0f) { + p.x = 1.0f - p.x; + p.y = 1.0f - p.y; + } + if(c.z >= -camera_cull_margin_) { + all_behind = false; + } + bb_min = min(bb_min, p); + bb_max = max(bb_max, p); + } + if(all_behind) { + return true; + } + return (bb_min.x >= 1.0f + camera_cull_margin_ || + bb_min.y >= 1.0f + camera_cull_margin_ || + bb_max.x <= -camera_cull_margin_ || + bb_max.y <= -camera_cull_margin_); +} + +bool BlenderObjectCulling::test_distance(Scene *scene, float3 bb[8]) +{ + float3 camera_position = transform_get_column(&scene->camera->matrix, 3); + float3 bb_min = make_float3(FLT_MAX, FLT_MAX, FLT_MAX), + bb_max = make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX); + + /* Find min & max points for x & y & z on bounding box */ + for(int i = 0; i < 8; ++i) { + float3 p = bb[i]; + bb_min = min(bb_min, p); + bb_max = max(bb_max, p); + } + + float3 closest_point = max(min(bb_max,camera_position),bb_min); + return (len_squared(camera_position - closest_point) > + distance_cull_margin_ * distance_cull_margin_); +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/blender/blender_object_cull.h b/intern/cycles/blender/blender_object_cull.h new file mode 100644 index 00000000000..b6f0ca5cd31 --- /dev/null +++ b/intern/cycles/blender/blender_object_cull.h @@ -0,0 +1,49 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __BLENDER_OBJECT_CULL_H__ +#define __BLENDER_OBJECT_CULL_H__ + +#include "blender_sync.h" +#include "util_types.h" + +CCL_NAMESPACE_BEGIN + +class Scene; + +class BlenderObjectCulling +{ +public: + BlenderObjectCulling(Scene *scene, BL::Scene& b_scene); + + void init_object(Scene *scene, BL::Object& b_ob); + bool test(Scene *scene, BL::Object& b_ob, Transform& tfm); + +private: + bool test_camera(Scene *scene, float3 bb[8]); + bool test_distance(Scene *scene, float3 bb[8]); + + bool use_scene_camera_cull_; + bool use_camera_cull_; + float camera_cull_margin_; + bool use_scene_distance_cull_; + bool use_distance_cull_; + float distance_cull_margin_; +}; + +CCL_NAMESPACE_END + +#endif /* __BLENDER_OBJECT_CULL_H__ */ From 4f03d3290c74ace448e7e6e09a87dd1a5c159899 Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Wed, 14 Dec 2016 18:02:38 +0300 Subject: [PATCH 396/590] Fresnel node support for Blender Internal Render --- release/scripts/startup/nodeitems_builtins.py | 1 + .../nodes/shader/nodes/node_shader_fresnel.c | 31 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 83e396b0997..69358302782 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -144,6 +144,7 @@ shader_node_categories = [ ShaderOldNodeCategory("SH_INPUT", "Input", items=[ NodeItem("ShaderNodeMaterial"), NodeItem("ShaderNodeCameraData"), + NodeItem("ShaderNodeFresnel"), NodeItem("ShaderNodeLampData"), NodeItem("ShaderNodeValue"), NodeItem("ShaderNodeRGB"), diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c index ef2ce99c924..ea19a2560ce 100644 --- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c +++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c @@ -51,17 +51,46 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *UNUSED(node), bNodeE return GPU_stack_link(mat, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION)); } +float fresnel_dielectric(float incoming[3], float normal[3], float eta) +{ + /* compute fresnel reflectance without explicitly computing + * the refracted direction */ + float c = fabs(dot_v3v3(incoming, normal)); + float g = eta * eta - 1.0 + c * c; + float result; + + if (g > 0.0) { + g = sqrtf(g); + float A = (g - c) / (g + c); + float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0); + result = 0.5 * A * A * (1.0 + B * B); + } + else { + result = 1.0; /* TIR (no refracted component) */ + } + + return result; +} + +static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) +{ + ShadeInput *shi = ((ShaderCallData *)data)->shi; + float eta = max_ff(in[0]->vec[0], 0.00001); + out[0]->vec[0] = fresnel_dielectric(shi->view, shi->vn, shi->flippednor ? 1/eta : eta); +} + /* node type definition */ void register_node_type_sh_fresnel(void) { static bNodeType ntype; sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT, 0); - node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING); node_type_socket_templates(&ntype, sh_node_fresnel_in, sh_node_fresnel_out); node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_fresnel); + node_type_exec(&ntype, NULL, NULL, node_shader_exec_fresnel); nodeRegisterType(&ntype); } From 525673b37b1718bf9973eecf1ec467d538a99607 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 14 Dec 2016 17:30:50 +0100 Subject: [PATCH 397/590] Cycles: Fix uninitialized variable issue after recent changes --- intern/cycles/kernel/closure/bsdf_microfacet.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 72fffe6ff69..4a1316fd2a9 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -613,6 +613,9 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure } } } + else { + label = (m_refractive) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; + } return label; } @@ -975,6 +978,9 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl } } } + else { + label = (m_refractive) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY; + } return label; } From 84a283d18c60b56d0586c46f4cd8baf81b551fc3 Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Wed, 14 Dec 2016 19:48:01 +0300 Subject: [PATCH 398/590] Fix World Space Shading option influence on Fresnel node for BI + cleanup --- .../nodes/shader/nodes/node_shader_fresnel.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c index ea19a2560ce..917a06b3536 100644 --- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c +++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c @@ -51,7 +51,7 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *UNUSED(node), bNodeE return GPU_stack_link(mat, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION)); } -float fresnel_dielectric(float incoming[3], float normal[3], float eta) +static float fresnel_dielectric(float incoming[3], float normal[3], float eta) { /* compute fresnel reflectance without explicitly computing * the refracted direction */ @@ -72,11 +72,23 @@ float fresnel_dielectric(float incoming[3], float normal[3], float eta) return result; } -static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *node, bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) +static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { ShadeInput *shi = ((ShaderCallData *)data)->shi; float eta = max_ff(in[0]->vec[0], 0.00001); - out[0]->vec[0] = fresnel_dielectric(shi->view, shi->vn, shi->flippednor ? 1/eta : eta); + + float n[3]; + if (in[1]->hasinput) { + copy_v3_v3(n, in[1]->vec); + } + else { + copy_v3_v3(n, shi->vn); + } + + if(shi->use_world_space_shading) + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n); + + out[0]->vec[0] = fresnel_dielectric(shi->view, n, shi->flippednor ? 1/eta : eta); } /* node type definition */ From 741c4082d822baa0b3b3b948460de39cee607089 Mon Sep 17 00:00:00 2001 From: Thomas Szepe Date: Wed, 14 Dec 2016 20:07:51 +0100 Subject: [PATCH 399/590] BGE: Fix T50098: Crash when useding ImageMirror The crash was caused by a missing m_sync initialisation in the second ImageRender constructor. --- source/gameengine/VideoTexture/ImageRender.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp index 9991bf42a9f..7e8c534d7d5 100644 --- a/source/gameengine/VideoTexture/ImageRender.cpp +++ b/source/gameengine/VideoTexture/ImageRender.cpp @@ -734,6 +734,7 @@ ImageRender::ImageRender (KX_Scene *scene, KX_GameObject *observer, KX_GameObjec m_done(false), m_scene(scene), m_offscreen(NULL), + m_sync(NULL), m_observer(observer), m_mirror(mirror), m_clip(100.f) From 820709c14d3917db86c6c392df75a32d52c53ca2 Mon Sep 17 00:00:00 2001 From: Karsten Weiss <> Date: Thu, 15 Dec 2016 12:56:48 +1100 Subject: [PATCH 400/590] Fix STR_String Capitalize on non Win32 Harmless since its not used, but good to fix. --- intern/string/intern/STR_String.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/string/intern/STR_String.cpp b/intern/string/intern/STR_String.cpp index 4ea451311e4..4612c91b6a6 100644 --- a/intern/string/intern/STR_String.cpp +++ b/intern/string/intern/STR_String.cpp @@ -545,9 +545,9 @@ STR_String& STR_String::Capitalize() if (this->m_len > 1) _strlwr(this->m_data + 1); #else if (this->m_len > 0) - this->m_data[0] = (this->m_data[0] >= 'A' && this->m_data[0] <= 'A') ? this->m_data[0] + 'a' - 'A' : this->m_data[0]; + this->m_data[0] = (this->m_data[0] >= 'a' && this->m_data[0] <= 'z') ? this->m_data[0] + 'A' - 'a' : this->m_data[0]; for (int i = 1; i < this->m_len; i++) - this->m_data[i] = (this->m_data[i] >= 'a' && this->m_data[i] <= 'z') ? this->m_data[i] + 'A' - 'a' : this->m_data[i]; + this->m_data[i] = (this->m_data[i] >= 'A' && this->m_data[i] <= 'Z') ? this->m_data[i] + 'a' - 'A' : this->m_data[i]; #endif return *this; } From 743165eb48870f1d68c8df48cc5907dea857b017 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 15 Dec 2016 11:49:44 +0100 Subject: [PATCH 401/590] Cleanup: Remove unused variable --- source/blender/editors/interface/interface_handlers.c | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 8c9f4ff422a..a7a09c8fd62 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -6706,7 +6706,6 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa) static void ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop) { - const PropertySubType subtype = RNA_property_subtype(prop); wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true); char filepath[FILE_MAX]; char dir[FILE_MAXDIR]; From 14d17cd27a47c5831edcb5224025edf8d4637756 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 15 Dec 2016 11:50:25 +0100 Subject: [PATCH 402/590] Revert "Cleanup: Remove unused variable" This reverts commit 743165eb48870f1d68c8df48cc5907dea857b017. Didn't see it is used in debug mode, sorry --- source/blender/editors/interface/interface_handlers.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a7a09c8fd62..8c9f4ff422a 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -6706,6 +6706,7 @@ void ui_panel_menu(bContext *C, ARegion *ar, Panel *pa) static void ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop) { + const PropertySubType subtype = RNA_property_subtype(prop); wmOperatorType *ot = WM_operatortype_find("WM_OT_path_open", true); char filepath[FILE_MAX]; char dir[FILE_MAXDIR]; From 665110a4140307b2ae4c96f682e09c7e846101c4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 15 Dec 2016 11:51:53 +0100 Subject: [PATCH 403/590] Proper fix for strict compiler warning --- source/blender/editors/interface/interface_handlers.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 8c9f4ff422a..a761bcfdf5e 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -6714,6 +6714,7 @@ static void ui_but_menu_add_path_operators(uiLayout *layout, PointerRNA *ptr, Pr PointerRNA props_ptr; BLI_assert(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH)); + UNUSED_VARS_NDEBUG(subtype); RNA_property_string_get(ptr, prop, filepath); BLI_split_dirfile(filepath, dir, file, sizeof(dir), sizeof(file)); From 12e1732f72bba6905da834a565885d4e8ecf9dc9 Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Thu, 15 Dec 2016 15:03:28 +0300 Subject: [PATCH 404/590] Layer Weight node support for Blender Internal Render --- .../nodes/shader/nodes/node_shader_fresnel.c | 23 +------------ .../shader/nodes/node_shader_layer_weight.c | 34 +++++++++++++++++-- .../render/extern/include/RE_shader_ext.h | 2 ++ .../blender/render/intern/include/shading.h | 2 +- .../render/intern/source/shadeoutput.c | 21 ++++++++++++ 5 files changed, 57 insertions(+), 25 deletions(-) diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.c index 917a06b3536..d5e11795fc0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c +++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.c @@ -51,27 +51,6 @@ static int node_shader_gpu_fresnel(GPUMaterial *mat, bNode *UNUSED(node), bNodeE return GPU_stack_link(mat, "node_fresnel", in, out, GPU_builtin(GPU_VIEW_POSITION)); } -static float fresnel_dielectric(float incoming[3], float normal[3], float eta) -{ - /* compute fresnel reflectance without explicitly computing - * the refracted direction */ - float c = fabs(dot_v3v3(incoming, normal)); - float g = eta * eta - 1.0 + c * c; - float result; - - if (g > 0.0) { - g = sqrtf(g); - float A = (g - c) / (g + c); - float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0); - result = 0.5 * A * A * (1.0 + B * B); - } - else { - result = 1.0; /* TIR (no refracted component) */ - } - - return result; -} - static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) { ShadeInput *shi = ((ShaderCallData *)data)->shi; @@ -88,7 +67,7 @@ static void node_shader_exec_fresnel(void *data, int UNUSED(thread), bNode *UNUS if(shi->use_world_space_shading) mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n); - out[0]->vec[0] = fresnel_dielectric(shi->view, n, shi->flippednor ? 1/eta : eta); + out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, shi->flippednor ? 1/eta : eta); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c index 8cbc587e339..90e2625b961 100644 --- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c +++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.c @@ -45,23 +45,53 @@ static int node_shader_gpu_layer_weight(GPUMaterial *mat, bNode *UNUSED(node), b { if (!in[1].link) in[1].link = GPU_builtin(GPU_VIEW_NORMAL); - else + else if (GPU_material_use_world_space_shading(mat)) { GPU_link(mat, "direction_transform_m4v3", in[1].link, GPU_builtin(GPU_VIEW_MATRIX), &in[1].link); + } return GPU_stack_link(mat, "node_layer_weight", in, out, GPU_builtin(GPU_VIEW_POSITION)); } +static void node_shader_exec_layer_weight(void *data, int UNUSED(thread), bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **out) +{ + ShadeInput *shi = ((ShaderCallData *)data)->shi; + float blend = in[0]->vec[0]; + float eta = max_ff(1 - blend, 0.00001); + + float n[3]; + if (in[1]->hasinput) { + copy_v3_v3(n, in[1]->vec); + } + else { + copy_v3_v3(n, shi->vn); + } + + if (shi->use_world_space_shading) + mul_mat3_m4_v3((float (*)[4])RE_render_current_get_matrix(RE_VIEW_MATRIX), n); + + out[0]->vec[0] = RE_fresnel_dielectric(shi->view, n, shi->flippednor ? eta : 1/eta); + + float facing = fabs(dot_v3v3(shi->view, n)); + if (blend != 0.5) { + CLAMP(blend, 0.0, 0.99999); + blend = (blend < 0.5) ? 2.0 * blend : 0.5 / (1.0 - blend); + facing = pow(facing, blend); + } + out[1]->vec[0] = 1.0 - facing; +} + /* node type definition */ void register_node_type_sh_layer_weight(void) { static bNodeType ntype; sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT, 0); - node_type_compatibility(&ntype, NODE_NEW_SHADING); + node_type_compatibility(&ntype, NODE_NEW_SHADING | NODE_OLD_SHADING); node_type_socket_templates(&ntype, sh_node_layer_weight_in, sh_node_layer_weight_out); node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_layer_weight); + node_type_exec(&ntype, NULL, NULL, node_shader_exec_layer_weight); nodeRegisterType(&ntype); } diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h index 73867de6b2e..ae389fdfd2e 100644 --- a/source/blender/render/extern/include/RE_shader_ext.h +++ b/source/blender/render/extern/include/RE_shader_ext.h @@ -218,6 +218,8 @@ int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]); void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]); +float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta); + /* shaded view and bake */ struct Render; struct Image; diff --git a/source/blender/render/intern/include/shading.h b/source/blender/render/intern/include/shading.h index 27867eadbb4..13f16ce0bd7 100644 --- a/source/blender/render/intern/include/shading.h +++ b/source/blender/render/intern/include/shading.h @@ -99,7 +99,7 @@ ListBase *get_lights(struct ShadeInput *shi); float lamp_get_visibility(struct LampRen *lar, const float co[3], float lv[3], float *dist); void lamp_get_shadow(struct LampRen *lar, ShadeInput *shi, float inp, float shadfac[4], int do_real); -float fresnel_fac(const float view[3], const float vn[3], float fresnel, float fac); +float fresnel_fac(const float view[3], const float vn[3], float fresnel, float fac); /* rayshade.c */ extern void shade_ray(struct Isect *is, struct ShadeInput *shi, struct ShadeResult *shr); diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c index 3d6462e09a0..c4de95e863e 100644 --- a/source/blender/render/intern/source/shadeoutput.c +++ b/source/blender/render/intern/source/shadeoutput.c @@ -2151,3 +2151,24 @@ const float (*RE_render_current_get_matrix(int matrix_id))[4] } return NULL; } + +float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) +{ + /* compute fresnel reflectance without explicitly computing + * the refracted direction */ + float c = fabs(dot_v3v3(incoming, normal)); + float g = eta * eta - 1.0 + c * c; + float result; + + if (g > 0.0) { + g = sqrtf(g); + float A = (g - c) / (g + c); + float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0); + result = 0.5 * A * A * (1.0 + B * B); + } + else { + result = 1.0; /* TIR (no refracted component) */ + } + + return result; +} \ No newline at end of file From 26bb0ee4641ff605e2ea397149762515fdf593a4 Mon Sep 17 00:00:00 2001 From: Jens Verwiebe Date: Thu, 15 Dec 2016 15:47:00 +0100 Subject: [PATCH 405/590] Fix Playerstubs tm --- source/blenderplayer/bad_level_call_stubs/stubs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 6040dfff644..5cda94dc22b 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -673,6 +673,7 @@ void RE_point_density_sample(struct Scene *scene, struct PointDensity *pd, int r void RE_point_density_free(struct PointDensity *pd) RET_NONE; void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) RET_NONE void RE_FreeAllPersistentData(void) RET_NONE +float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) RET_NONE /* python */ struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) RET_NULL From bd3de93557ce1e3af1ec33530add1f7831f09db6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 15 Dec 2016 17:53:27 +0100 Subject: [PATCH 406/590] Gtest: Fix/workaround MSVC complains about use of struct with alignment --- extern/gtest/include/gtest/internal/gtest-internal.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/extern/gtest/include/gtest/internal/gtest-internal.h b/extern/gtest/include/gtest/internal/gtest-internal.h index ebd1cf615de..ca15a2f3a78 100644 --- a/extern/gtest/include/gtest/internal/gtest-internal.h +++ b/extern/gtest/include/gtest/internal/gtest-internal.h @@ -60,6 +60,10 @@ #include #include +#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) +# include +#endif + #include "gtest/gtest-message.h" #include "gtest/internal/gtest-string.h" #include "gtest/internal/gtest-filepath.h" @@ -854,6 +858,7 @@ struct AddReference { typedef T& type; }; // NOLINT template class ImplicitlyConvertible { private: +#if !((__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)) // We need the following helper functions only for their types. // They have no implementations. @@ -874,6 +879,7 @@ class ImplicitlyConvertible { // implicitly converted to type To. static char Helper(To); static char (&Helper(...))[2]; // NOLINT +#endif // We have to put the 'public' section after the 'private' section, // or MSVC refuses to compile the code. @@ -883,6 +889,8 @@ class ImplicitlyConvertible { // instantiation. The simplest workaround is to use its C++0x type traits // functions (C++Builder 2009 and above only). static const bool value = __is_convertible(From, To); +#elif (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800) + static const bool value = std::is_convertible::value; #else // MSVC warns about implicitly converting from double to int for // possible loss of data, so we need to temporarily disable the From e2d7efc9503720770b9652284e25006eecbec8d4 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Thu, 15 Dec 2016 22:12:29 +0100 Subject: [PATCH 407/590] Remove double menu entries These were already present in the "Select" menu. --- release/scripts/startup/bl_ui/space_view3d.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 5e936076d0e..55fa2c28011 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2528,14 +2528,7 @@ class VIEW3D_MT_edit_mesh_edges(Menu): layout.operator("mesh.bevel").vertex_only = False layout.operator("mesh.edge_split") layout.operator("mesh.bridge_edge_loops") - - layout.separator() - layout.operator("transform.edge_slide") - layout.operator("mesh.loop_multi_select", text="Edge Loops").ring = False - layout.operator("mesh.loop_multi_select", text="Edge Rings").ring = True - layout.operator("mesh.loop_to_region") - layout.operator("mesh.region_to_loop") class VIEW3D_MT_edit_mesh_faces(Menu): From 524ab96245211bb722b82e197ac75bba6bd10e69 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 15 Dec 2016 22:22:54 +0100 Subject: [PATCH 408/590] Fix drawing enum property with icon only flag Enum properties with icon only flag should use minimum/fixed width in expanded layouts (alignment=UI_LAYOUT_ALIGN_EXPAND). Differential Revision: https://developer.blender.org/D2415 by @raa (only made some really minor corrections) --- source/blender/editors/interface/interface_layout.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 342c7182453..80d091c0fdb 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1235,8 +1235,15 @@ static void ui_item_rna_size( } } - if (!w) - w = ui_text_icon_width(layout, name, icon, 0); + if (!w) { + if (type == PROP_ENUM && icon_only) { + w = ui_text_icon_width(layout, "", ICON_BLANK1, 0); + w += 0.6f * UI_UNIT_X; + } + else { + w = ui_text_icon_width(layout, name, icon, 0); + } + } h = UI_UNIT_Y; /* increase height for arrays */ @@ -1254,7 +1261,7 @@ static void ui_item_rna_size( else if (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X) { if (type == PROP_BOOLEAN && name[0]) w += UI_UNIT_X / 5; - else if (type == PROP_ENUM) + else if (type == PROP_ENUM && !icon_only) w += UI_UNIT_X / 4; else if (type == PROP_FLOAT || type == PROP_INT) w += UI_UNIT_X * 3; From 4df75e536a0847cf5e5f567f92f1391f1f72c211 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Fri, 16 Dec 2016 02:35:36 +0100 Subject: [PATCH 409/590] Make Shift+LMB on transform manipulator configurable It's now possible to change the shortcut that enables planar transformation with the transform manipulators (shift+LMB on axis). This actually fixes the workaround added in rB20681f49801fd. Thing is that we needed to allow using the manipulators, even if a modifier key is held so things like snapping work right away. That's why normal LMB behavior uses KM_ANY. However, event handling would always execute the KM_ANY keymap handler because it's iterated over first. Simply solved this by registering the KM_SHIFT keymap item first, so it has priority over the KM_ANY one. --- source/blender/editors/physics/physics_ops.c | 8 +++++++- source/blender/editors/space_view3d/view3d_edit.c | 8 ++++---- source/blender/editors/space_view3d/view3d_ops.c | 14 ++++++++------ .../editors/transform/transform_manipulator.c | 14 +++++++------- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index 7ba4b2be43b..0c907f19753 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -137,8 +137,14 @@ static void keymap_particle(wmKeyConfig *keyconf) kmi = WM_keymap_add_item(keymap, "PARTICLE_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "unselected", true); - kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0); + /* Shift+LMB behavior first, so it has priority over KM_ANY item below. */ + kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "release_confirm", true); + RNA_boolean_set(kmi->ptr, "use_planar_constraint", true); + /* Using KM_ANY here to allow holding modifiers before starting to transform. */ + kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0); + RNA_boolean_set(kmi->ptr, "release_confirm", true); + RNA_boolean_set(kmi->ptr, "use_planar_constraint", false); WM_keymap_add_item(keymap, "PARTICLE_OT_brush_edit", LEFTMOUSE, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "PARTICLE_OT_brush_edit", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 080f205b530..eb4d1b3819b 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4782,13 +4782,10 @@ static int manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return OPERATOR_PASS_THROUGH; if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return OPERATOR_PASS_THROUGH; - /* only no modifier or shift */ - if (event->keymodifier != 0 && event->keymodifier != KM_SHIFT) return OPERATOR_PASS_THROUGH; - /* note; otherwise opengl won't work */ view3d_operator_needs_opengl(C); - if (0 == BIF_do_manipulator(C, event, op)) + if (BIF_do_manipulator(C, event, op) == 0) return OPERATOR_PASS_THROUGH; return OPERATOR_FINISHED; @@ -4809,6 +4806,9 @@ void VIEW3D_OT_manipulator(wmOperatorType *ot) /* properties to pass to transform */ Transform_Properties(ot, P_CONSTRAINT); + + RNA_def_boolean(ot->srna, "use_planar_constraint", false, "Planar Constraint", "Limit the transformation to the " + "two axes that have not been clicked (translate/scale only)"); } static int enable_manipulator_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index cfeb8af280e..0fa6841fe27 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -240,13 +240,15 @@ void view3d_keymap(wmKeyConfig *keyconf) /* only for region 3D window */ keymap = WM_keymap_find(keyconf, "3D View", SPACE_VIEW3D, 0); - kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0); + /* Shift+LMB behavior first, so it has priority over KM_ANY item below. */ + kmi = WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "release_confirm", true); - /* - * Doesn't work with KM_SHIFT, have to use KM_ANY and filter in invoke - * */ - // WM_keymap_verify_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0); - + RNA_boolean_set(kmi->ptr, "use_planar_constraint", true); + /* Using KM_ANY here to allow holding modifiers before starting to transform. */ + kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_manipulator", LEFTMOUSE, KM_PRESS, KM_ANY, 0); + RNA_boolean_set(kmi->ptr, "release_confirm", true); + RNA_boolean_set(kmi->ptr, "use_planar_constraint", false); + WM_keymap_verify_item(keymap, "VIEW3D_OT_cursor3d", ACTIONMOUSE, KM_PRESS, 0, 0); WM_keymap_verify_item(keymap, "VIEW3D_OT_rotate", MIDDLEMOUSE, KM_PRESS, 0, 0); diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 075f311db72..e141724f2df 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -1835,7 +1835,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) ARegion *ar = CTX_wm_region(C); int constraint_axis[3] = {0, 0, 0}; int val; - int shift = event->shift; + const bool use_planar = RNA_boolean_get(op->ptr, "use_planar_constraint"); if (!(v3d->twflag & V3D_USE_MANIPULATOR)) return 0; if (!(v3d->twflag & V3D_DRAW_MANIPULATOR)) return 0; @@ -1856,7 +1856,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) case MAN_TRANS_C: break; case MAN_TRANS_X: - if (shift) { + if (use_planar) { constraint_axis[1] = 1; constraint_axis[2] = 1; } @@ -1864,7 +1864,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) constraint_axis[0] = 1; break; case MAN_TRANS_Y: - if (shift) { + if (use_planar) { constraint_axis[0] = 1; constraint_axis[2] = 1; } @@ -1872,7 +1872,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) constraint_axis[1] = 1; break; case MAN_TRANS_Z: - if (shift) { + if (use_planar) { constraint_axis[0] = 1; constraint_axis[1] = 1; } @@ -1886,7 +1886,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) else if (drawflags & MAN_SCALE_C) { switch (drawflags) { case MAN_SCALE_X: - if (shift) { + if (use_planar) { constraint_axis[1] = 1; constraint_axis[2] = 1; } @@ -1894,7 +1894,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) constraint_axis[0] = 1; break; case MAN_SCALE_Y: - if (shift) { + if (use_planar) { constraint_axis[0] = 1; constraint_axis[2] = 1; } @@ -1902,7 +1902,7 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op) constraint_axis[1] = 1; break; case MAN_SCALE_Z: - if (shift) { + if (use_planar) { constraint_axis[0] = 1; constraint_axis[1] = 1; } From 535298eea5fd50a19d04ddffb05060313e32826c Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Fri, 16 Dec 2016 22:56:43 +0100 Subject: [PATCH 410/590] Fix T50264: Stroke is not painted when append Grease Pencil block When append a datablock the default brushes were not created and only were created when draw new strokes. Now the default brushes are created when draw strokes if necessary. --- source/blender/editors/gpencil/drawgpencil.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 48786e08f85..9da3c3ee088 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -1554,7 +1554,17 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i int cfra, int dflag, const char spacetype) { bGPdata *gpd_source = NULL; - + ToolSettings *ts; + bGPDbrush *brush; + if (scene) { + ts = scene->toolsettings; + brush = BKE_gpencil_brush_getactive(ts); + /* if no brushes, create default set */ + if (brush == NULL) { + BKE_gpencil_brush_init_presets(ts); + brush = BKE_gpencil_brush_getactive(ts); + } + } if (scene) { if (spacetype == SPACE_VIEW3D) { gpd_source = (scene->gpd ? scene->gpd : NULL); @@ -1565,8 +1575,6 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i } if (gpd_source) { - ToolSettings *ts = scene->toolsettings; - bGPDbrush *brush = BKE_gpencil_brush_getactive(ts); if (brush != NULL) { gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source, offsx, offsy, winx, winy, cfra, dflag); @@ -1578,8 +1586,6 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i /* scene/clip data has already been drawn, only object/track data is drawn here * if gpd_source == gpd, we don't have any object/track data and we can skip */ if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) { - ToolSettings *ts = scene->toolsettings; - bGPDbrush *brush = BKE_gpencil_brush_getactive(ts); if (brush != NULL) { gp_draw_data(brush, ts->gp_sculpt.alpha, gpd, offsx, offsy, winx, winy, cfra, dflag); From 2e15618f498c5a64c012f559bbb95273e729999a Mon Sep 17 00:00:00 2001 From: Luca Rood Date: Sun, 11 Dec 2016 20:10:01 -0200 Subject: [PATCH 411/590] Fix T50216: Missing checks caused data transfer segfault Data transfer was not checking if the required geometry existed, thus causing a segfault when it didn't. This adds the required checks, and reports errors if geometry is missing. This also replaces instances of the words "polygon" and "loop" in error messages with "face" and "corner" respectively, to be consistent with the rest of the existing UI. Reviewed By: mont29 Differential Revision: http://developer.blender.org/D2410 --- .../blender/blenkernel/intern/data_transfer.c | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c index 839673c192b..3bc09c0173b 100644 --- a/source/blender/blenkernel/intern/data_transfer.c +++ b/source/blender/blenkernel/intern/data_transfer.c @@ -1205,6 +1205,18 @@ bool BKE_object_data_transfer_dm( "'Topology' mapping cannot be used in this case"); continue; } + if ((map_vert_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) { + BKE_report(reports, RPT_ERROR, + "Source mesh doesn't have any edges, " + "None of the 'Edge' mappings can be used in this case"); + continue; + } + if ((map_vert_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) { + BKE_report(reports, RPT_ERROR, + "Source mesh doesn't have any faces, " + "None of the 'Face' mappings can be used in this case"); + continue; + } if (ELEM(0, num_verts_dst, num_verts_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any vertices, cannot transfer vertex data"); @@ -1253,6 +1265,12 @@ bool BKE_object_data_transfer_dm( "'Topology' mapping cannot be used in this case"); continue; } + if ((map_edge_mode & MREMAP_USE_POLY) && (dm_src->getNumPolys(dm_src) == 0)) { + BKE_report(reports, RPT_ERROR, + "Source mesh doesn't have any faces, " + "None of the 'Face' mappings can be used in this case"); + continue; + } if (ELEM(0, num_edges_dst, num_edges_src)) { BKE_report(reports, RPT_ERROR, "Source or destination meshes do not have any edges, cannot transfer edge data"); @@ -1312,9 +1330,15 @@ bool BKE_object_data_transfer_dm( "'Topology' mapping cannot be used in this case"); continue; } + if ((map_loop_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) { + BKE_report(reports, RPT_ERROR, + "Source mesh doesn't have any edges, " + "None of the 'Edge' mappings can be used in this case"); + continue; + } if (ELEM(0, num_loops_dst, num_loops_src)) { BKE_report(reports, RPT_ERROR, - "Source or destination meshes do not have any polygons, cannot transfer loop data"); + "Source or destination meshes do not have any faces, cannot transfer corner data"); continue; } @@ -1370,9 +1394,15 @@ bool BKE_object_data_transfer_dm( "'Topology' mapping cannot be used in this case"); continue; } + if ((map_poly_mode & MREMAP_USE_EDGE) && (dm_src->getNumEdges(dm_src) == 0)) { + BKE_report(reports, RPT_ERROR, + "Source mesh doesn't have any edges, " + "None of the 'Edge' mappings can be used in this case"); + continue; + } if (ELEM(0, num_polys_dst, num_polys_src)) { BKE_report(reports, RPT_ERROR, - "Source or destination meshes do not have any polygons, cannot transfer poly data"); + "Source or destination meshes do not have any faces, cannot transfer face data"); continue; } From 6c3d8fbeb399c394831137b511c02df642fade92 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 17 Dec 2016 19:12:07 +1100 Subject: [PATCH 412/590] Cleanup: trackball logic Used SQRT2 and SQRT1_2 to calculate the same value, harmless but a little confusing, set once and check instead. --- source/blender/editors/space_view3d/view3d_edit.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index eb4d1b3819b..620bbf03f32 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -566,22 +566,20 @@ typedef struct ViewOpsData { static void calctrackballvec(const rcti *rect, int mx, int my, float vec[3]) { - float x, y, radius, d, z, t; - - radius = TRACKBALLSIZE; + const float radius = TRACKBALLSIZE; + const float t = radius / (float)M_SQRT2; + float x, y, z, d; /* normalize x and y */ x = BLI_rcti_cent_x(rect) - mx; x /= (float)(BLI_rcti_size_x(rect) / 4); y = BLI_rcti_cent_y(rect) - my; y /= (float)(BLI_rcti_size_y(rect) / 2); - d = sqrtf(x * x + y * y); - if (d < radius * (float)M_SQRT1_2) { /* Inside sphere */ + if (d < t) { /* Inside sphere */ z = sqrtf(radius * radius - d * d); } else { /* On hyperbola */ - t = radius / (float)M_SQRT2; z = t * t / d; } From e30d94bb3bdb333a514f0771e63ff2543c0a1969 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Mon, 19 Dec 2016 12:28:51 +0100 Subject: [PATCH 413/590] Cleanup: rename paramenter to right name --- source/blender/blenkernel/BKE_gpencil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index ab8b83f8271..3378f4acc60 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -104,7 +104,7 @@ void BKE_gpencil_layer_delete(struct bGPdata *gpd, struct bGPDlayer *gpl); struct bGPDbrush *BKE_gpencil_brush_getactive(struct ToolSettings *ts); void BKE_gpencil_brush_setactive(struct ToolSettings *ts, struct bGPDbrush *active); -void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *palette); +void BKE_gpencil_brush_delete(struct ToolSettings *ts, struct bGPDbrush *brush); struct bGPDpalette *BKE_gpencil_palette_getactive(struct bGPdata *gpd); void BKE_gpencil_palette_setactive(struct bGPdata *gpd, struct bGPDpalette *active); From bd42987399f1e2decf259cce21a91e39c7a0a50d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 19 Dec 2016 16:28:41 +0100 Subject: [PATCH 414/590] Fix (unreported) linked datablocks going through do_versions several times. When linking data-blocks from same library in several steps, the already linked data-blocks of same lib would go again through versionning code... Note: only fixed for libraries, I can't imagine how this could happen with local data... --- source/blender/blenloader/intern/readfile.c | 50 ++++++++++++++++++--- source/blender/makesdna/DNA_ID.h | 3 +- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 03c5d083456..a154d283f07 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -8112,7 +8112,10 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short if (bhead->code == ID_ID) { return blo_nextbhead(fd, bhead); } - + + /* That way, we know which datablock needs do_versions (required currently for linking). */ + id->tag |= LIB_TAG_NEW; + /* need a name for the mallocN, just for debugging and sane prints on leaks */ allocname = dataname(GS(id->name)); @@ -8578,7 +8581,10 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) blo_join_main(&mainlist); lib_link_all(fd, bfd->main); + //do_versions_after_linking(fd, NULL, bfd->main); // XXX: not here (or even in this function at all)! this causes crashes on many files - Aligorith (July 04, 2010) + BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false); + lib_verify_nodetree(bfd->main, true); fix_relpaths_library(fd->relabase, bfd->main); /* make all relative paths, relative to the open blend file */ @@ -10142,6 +10148,9 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene mainl = NULL; /* blo_join_main free's mainl, cant use anymore */ lib_link_all(*fd, mainvar); + + BKE_main_id_tag_all(mainvar, LIB_TAG_NEW, false); + lib_verify_nodetree(mainvar, false); fix_relpaths_library(G.main->name, mainvar); /* make all relative paths, relative to the open blend file */ @@ -10212,6 +10221,32 @@ static int mainvar_id_tag_any_check(Main *mainvar, const short tag) return false; } +static void split_main_newid(Main *mainptr, Main *main_newid) +{ + /* We only copy the necessary subset of data in this temp main. */ + main_newid->versionfile = mainptr->versionfile; + main_newid->subversionfile = mainptr->subversionfile; + BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name)); + main_newid->curlib = mainptr->curlib; + + ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray_newid[MAX_LIBARRAY]; + int i = set_listbasepointers(mainptr, lbarray); + set_listbasepointers(main_newid, lbarray_newid); + while (i--) { + BLI_listbase_clear(lbarray_newid[i]); + + for (ID *id = lbarray[i]->first, *idnext; id; id = idnext) { + idnext = id->next; + + if (id->tag & LIB_TAG_NEW) { + BLI_remlink(lbarray[i], id); + BLI_addtail(lbarray_newid[i], id); + } + } + } +} + static void read_libraries(FileData *basefd, ListBase *mainlist) { Main *mainl = mainlist->first; @@ -10381,14 +10416,19 @@ static void read_libraries(FileData *basefd, ListBase *mainlist) } /* do versions, link, and free */ + Main main_newid = {0}; for (mainptr = mainl->next; mainptr; mainptr = mainptr->next) { - /* some mains still have to be read, then - * versionfile is still zero! */ + /* some mains still have to be read, then versionfile is still zero! */ if (mainptr->versionfile) { + /* We need to split out IDs already existing, or they will go again through do_versions - bad, very bad! */ + split_main_newid(mainptr, &main_newid); + if (mainptr->curlib->filedata) // can be zero... with shift+f1 append - do_versions(mainptr->curlib->filedata, mainptr->curlib, mainptr); + do_versions(mainptr->curlib->filedata, mainptr->curlib, &main_newid); else - do_versions(basefd, NULL, mainptr); + do_versions(basefd, NULL, &main_newid); + + add_main_to_main(mainptr, &main_newid); } if (mainptr->curlib->filedata) diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 59fd0c7832c..9a8f3da3396 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -336,7 +336,8 @@ enum { /* tag datablock has having actually increased usercount for the extra virtual user. */ LIB_TAG_EXTRAUSER_SET = 1 << 7, - /* RESET_AFTER_USE tag newly duplicated/copied IDs. */ + /* RESET_AFTER_USE tag newly duplicated/copied IDs. + * Also used internally in readfile.c to mark datablocks needing do_versions. */ LIB_TAG_NEW = 1 << 8, /* RESET_BEFORE_USE free test flag. * TODO make it a RESET_AFTER_USE too. */ From 4d5cd638ffba6854bfcee2ee7eb836f446b087ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 20 Dec 2016 11:01:08 +0100 Subject: [PATCH 415/590] String drawing function for the "simdebug" utilities. Simple string drawing API for debug drawing, in addition to basic primitives. --- source/blender/blenkernel/BKE_effect.h | 16 ++++++++++----- source/blender/blenkernel/intern/effect.c | 16 ++++++++++++--- .../editors/space_view3d/drawsimdebug.c | 20 +++++++++++++++++-- 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h index b934ec7166d..aa45132cbe9 100644 --- a/source/blender/blenkernel/BKE_effect.h +++ b/source/blender/blenkernel/BKE_effect.h @@ -172,6 +172,7 @@ typedef struct SimDebugElement { float color[3]; float v1[3], v2[3]; + char str[64]; } SimDebugElement; typedef enum eSimDebugElement_Type { @@ -179,6 +180,7 @@ typedef enum eSimDebugElement_Type { SIM_DEBUG_ELEM_CIRCLE, SIM_DEBUG_ELEM_LINE, SIM_DEBUG_ELEM_VECTOR, + SIM_DEBUG_ELEM_STRING, } eSimDebugElement_Type; typedef struct SimDebugData { @@ -191,26 +193,30 @@ void BKE_sim_debug_data_set_enabled(bool enable); bool BKE_sim_debug_data_get_enabled(void); void BKE_sim_debug_data_free(void); -void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], +void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], const char *str, float r, float g, float b, const char *category, unsigned int hash); void BKE_sim_debug_data_remove_element(unsigned int hash); #define BKE_sim_debug_data_add_dot(p, r, g, b, category, ...) { \ const float v2[3] = { 0.0f, 0.0f, 0.0f }; \ - BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_DOT, p, v2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \ + BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_DOT, p, v2, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \ } #define BKE_sim_debug_data_add_circle(p, radius, r, g, b, category, ...) { \ const float v2[3] = { radius, 0.0f, 0.0f }; \ - BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_CIRCLE, p, v2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \ + BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_CIRCLE, p, v2, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \ } #define BKE_sim_debug_data_add_line(p1, p2, r, g, b, category, ...) { \ - BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_LINE, p1, p2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \ + BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_LINE, p1, p2, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \ } #define BKE_sim_debug_data_add_vector(p, d, r, g, b, category, ...) { \ - BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_VECTOR, p, d, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \ + BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_VECTOR, p, d, NULL, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \ +} + +#define BKE_sim_debug_data_add_string(p, str, r, g, b, category, ...) { \ + BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_STRING, p, NULL, str, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \ } #define BKE_sim_debug_data_remove(...) \ diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index 3e85b0d4a15..fe8f5ebdca6 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -1130,7 +1130,7 @@ static void debug_data_insert(SimDebugData *debug_data, SimDebugElement *elem) BLI_ghash_insert(debug_data->gh, elem, elem); } -void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], float r, float g, float b, const char *category, unsigned int hash) +void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], const char *str, float r, float g, float b, const char *category, unsigned int hash) { unsigned int category_hash = BLI_ghashutil_strhash_p(category); SimDebugElement *elem; @@ -1149,8 +1149,18 @@ void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[ elem->color[0] = r; elem->color[1] = g; elem->color[2] = b; - copy_v3_v3(elem->v1, v1); - copy_v3_v3(elem->v2, v2); + if (v1) + copy_v3_v3(elem->v1, v1); + else + zero_v3(elem->v1); + if (v2) + copy_v3_v3(elem->v2, v2); + else + zero_v3(elem->v2); + if (str) + BLI_strncpy(elem->str, str, sizeof(elem->str)); + else + elem->str[0] = '\0'; debug_data_insert(_sim_debug_data, elem); } diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c index 91adc905816..9414d39467d 100644 --- a/source/blender/editors/space_view3d/drawsimdebug.c +++ b/source/blender/editors/space_view3d/drawsimdebug.c @@ -136,9 +136,23 @@ static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4]) glVertex3f(t[0], t[1], t[2]); } glEnd(); + + /**** strings ****/ + + for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { + SimDebugElement *elem = BLI_ghashIterator_getValue(&iter); + if (elem->type != SIM_DEBUG_ELEM_STRING) + continue; + + unsigned char col[4]; + rgb_float_to_uchar(col, elem->color); + col[3] = 255; + view3d_cached_text_draw_add(elem->v1, elem->str, strlen(elem->str), + 0, V3D_CACHE_TEXT_GLOBALSPACE, col); + } } -void draw_sim_debug_data(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar) +void draw_sim_debug_data(Scene *UNUSED(scene), View3D *v3d, ARegion *ar) { RegionView3D *rv3d = ar->regiondata; /*Object *ob = base->object;*/ @@ -153,9 +167,11 @@ void draw_sim_debug_data(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar) // glEnable(GL_BLEND); glPushMatrix(); - glLoadMatrixf(rv3d->viewmat); + + view3d_cached_text_draw_begin(); draw_sim_debug_elements(_sim_debug_data, imat); + view3d_cached_text_draw_end(v3d, ar, false, NULL); glPopMatrix(); From 1c34a7f4ebc746236f9689c9bc1e6961ad9949e0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 20 Dec 2016 10:22:54 +0100 Subject: [PATCH 416/590] Libmv: Fix missing virtual destructor in frame access sub-class This is undefined behavior in C++ and Clang was complaining a lot about this. --- intern/libmv/intern/frame_accessor.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/intern/libmv/intern/frame_accessor.cc b/intern/libmv/intern/frame_accessor.cc index 9213cc311b3..5d274d7ccca 100644 --- a/intern/libmv/intern/frame_accessor.cc +++ b/intern/libmv/intern/frame_accessor.cc @@ -45,6 +45,9 @@ struct LibmvFrameAccessor : public FrameAccessor { get_image_callback_(get_image_callback), release_image_callback_(release_image_callback) { } + virtual ~LibmvFrameAccessor() { + } + libmv_InputMode get_libmv_input_mode(InputMode input_mode) { switch (input_mode) { #define CHECK_INPUT_MODE(mode) \ From 544f6113f85fe9dd962b5985878677a3d9c202da Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 20 Dec 2016 10:23:36 +0100 Subject: [PATCH 417/590] OpensSubdiv: Cleanup, unused argument --- intern/opensubdiv/opensubdiv_evaluator_capi.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.cc b/intern/opensubdiv/opensubdiv_evaluator_capi.cc index 0da6b9daba8..c4a128213dd 100644 --- a/intern/opensubdiv/opensubdiv_evaluator_capi.cc +++ b/intern/opensubdiv/opensubdiv_evaluator_capi.cc @@ -117,12 +117,12 @@ protected: * is small enough and better to be allocated in stack rather * than in heap. * - * TODO(sergey): Check if bare arrays could be sued by CPU evalautor. + * TODO(sergey): Check if bare arrays could be used by CPU evalautor. */ template class StackAllocatedBuffer { public: - static PatchCoordBuffer *Create(int size) + static PatchCoordBuffer *Create(int /*size*/) { StackAllocatedBuffer *buffer = new StackAllocatedBuffer(); From 5fb85ef2c2465a4192e60c8c671904c143ecc6c9 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 20 Dec 2016 10:23:55 +0100 Subject: [PATCH 418/590] Fix strict compiler warning in generated C++ RNA --- source/blender/makesrna/intern/makesrna.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index d5576978e23..4552c773097 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3765,7 +3765,7 @@ static const char *cpp_classes = "" "\n" "private:\n" " const CollectionIterator& operator = " -"(const CollectionIterator& copy) {}\n" +"(const CollectionIterator& /*copy*/) {}\n" "" " CollectionPropertyIterator iter;\n" " T t;\n" From 5e31e0723017ae93490778b1dd8b9b265b2df100 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 22 Dec 2016 02:35:34 +0100 Subject: [PATCH 419/590] Fix wrong return type in blenderplayer stubs --- source/blenderplayer/bad_level_call_stubs/stubs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 5cda94dc22b..a297dac0f55 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -673,7 +673,7 @@ void RE_point_density_sample(struct Scene *scene, struct PointDensity *pd, int r void RE_point_density_free(struct PointDensity *pd) RET_NONE; void RE_instance_get_particle_info(struct ObjectInstanceRen *obi, float *index, float *age, float *lifetime, float co[3], float *size, float vel[3], float angvel[3]) RET_NONE void RE_FreeAllPersistentData(void) RET_NONE -float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) RET_NONE +float RE_fresnel_dielectric(float incoming[3], float normal[3], float eta) RET_ZERO /* python */ struct wmOperatorType *WM_operatortype_find(const char *idname, bool quiet) RET_NULL From 8db2f72997cc72259157d7fc42b54fa5a292f424 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 22 Dec 2016 21:58:57 +0100 Subject: [PATCH 420/590] Fix (unreported) `--threads` option no more respected by main task scheduler. Main scheduler would be created way before `-t` argument would be parsed, since it was on forth pass! Moved it to first pass of argparse, that kind of stuff should be initialized asap on startup. --- source/creator/creator_args.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 9f845d29c18..4eb72fb1619 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -1886,7 +1886,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle) BLI_argsAdd(ba, 4, "-E", "--engine", CB(arg_handle_engine_set), C); BLI_argsAdd(ba, 4, "-F", "--render-format", CB(arg_handle_image_type_set), C); - BLI_argsAdd(ba, 4, "-t", "--threads", CB(arg_handle_threads_set), NULL); + BLI_argsAdd(ba, 1, "-t", "--threads", CB(arg_handle_threads_set), NULL); BLI_argsAdd(ba, 4, "-x", "--use-extension", CB(arg_handle_extension_set), C); #undef CB From d0335796a8f1acb8b1a1c2336b382da82e2370ee Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 23 Dec 2016 12:54:51 +0100 Subject: [PATCH 421/590] Readfile: Resurrect do_versions_after_liblink. Basic idea is to store fileversion in Library datablock, and split again Main by libraries after lib linking, do_versions_after_liblink on those separated Mains, and merge again. This allows to still have correct versions for each data-block in that second do_versions step. Note that this is not used currently in master (might be soon, though), but is needed for 2.8 work. --- source/blender/blenloader/intern/readfile.c | 96 +++++++++++++-------- source/blender/makesdna/DNA_ID.h | 3 +- 2 files changed, 64 insertions(+), 35 deletions(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a154d283f07..f568a741a30 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -531,6 +531,8 @@ void blo_split_main(ListBase *mainlist, Main *main) for (Library *lib = main->library.first; lib; lib = lib->id.next, i++) { Main *libmain = BKE_main_new(); libmain->curlib = lib; + libmain->versionfile = lib->versionfile; + libmain->subversionfile = lib->subversionfile; BLI_addtail(mainlist, libmain); lib->temp_index = i; lib_main_array[i] = libmain; @@ -562,6 +564,10 @@ static void read_file_version(FileData *fd, Main *main) break; } } + if (main->curlib) { + main->curlib->versionfile = main->versionfile; + main->curlib->subversionfile = main->subversionfile; + } } #ifdef USE_GHASH_BHEAD @@ -8373,14 +8379,11 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* don't forget to set version number in BKE_blender_version.h! */ } -#if 0 // XXX: disabled for now... we still don't have this in the right place in the loading code for it to work -static void do_versions_after_linking(FileData *fd, Library *lib, Main *main) +static void do_versions_after_linking(Main *main) { - /* old Animation System (using IPO's) needs to be converted to the new Animato system */ - if (main->versionfile < 250) - do_versions_ipos_to_animato(main); +// printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name, +// main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile); } -#endif static void lib_link_all(FileData *fd, Main *main) { @@ -8582,7 +8585,17 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) lib_link_all(fd, bfd->main); - //do_versions_after_linking(fd, NULL, bfd->main); // XXX: not here (or even in this function at all)! this causes crashes on many files - Aligorith (July 04, 2010) + /* Skip in undo case. */ + if (fd->memfile == NULL) { + /* Yep, second splitting... but this is a very cheap operation, so no big deal. */ + blo_split_main(&mainlist, bfd->main); + for (Main *mainvar = mainlist.first; mainvar; mainvar = mainvar->next) { + BLI_assert(mainvar->versionfile != 0); + do_versions_after_linking(mainvar); + } + blo_join_main(&mainlist); + } + BKE_main_id_tag_all(bfd->main, LIB_TAG_NEW, false); lib_verify_nodetree(bfd->main, true); @@ -10116,6 +10129,32 @@ Main *BLO_library_link_begin(Main *mainvar, BlendHandle **bh, const char *filepa return library_link_begin(mainvar, &fd, filepath); } +static void split_main_newid(Main *mainptr, Main *main_newid) +{ + /* We only copy the necessary subset of data in this temp main. */ + main_newid->versionfile = mainptr->versionfile; + main_newid->subversionfile = mainptr->subversionfile; + BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name)); + main_newid->curlib = mainptr->curlib; + + ListBase *lbarray[MAX_LIBARRAY]; + ListBase *lbarray_newid[MAX_LIBARRAY]; + int i = set_listbasepointers(mainptr, lbarray); + set_listbasepointers(main_newid, lbarray_newid); + while (i--) { + BLI_listbase_clear(lbarray_newid[i]); + + for (ID *id = lbarray[i]->first, *idnext; id; id = idnext) { + idnext = id->next; + + if (id->tag & LIB_TAG_NEW) { + BLI_remlink(lbarray[i], id); + BLI_addtail(lbarray_newid[i], id); + } + } + } +} + /* scene and v3d may be NULL. */ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene *scene, View3D *v3d) { @@ -10144,11 +10183,26 @@ static void library_link_end(Main *mainl, FileData **fd, const short flag, Scene blo_join_main((*fd)->mainlist); mainvar = (*fd)->mainlist->first; - MEM_freeN((*fd)->mainlist); mainl = NULL; /* blo_join_main free's mainl, cant use anymore */ lib_link_all(*fd, mainvar); + /* Yep, second splitting... but this is a very cheap operation, so no big deal. */ + blo_split_main((*fd)->mainlist, mainvar); + Main main_newid = {0}; + for (mainvar = ((Main *)(*fd)->mainlist->first)->next; mainvar; mainvar = mainvar->next) { + BLI_assert(mainvar->versionfile != 0); + /* We need to split out IDs already existing, or they will go again through do_versions - bad, very bad! */ + split_main_newid(mainvar, &main_newid); + + do_versions_after_linking(&main_newid); + + add_main_to_main(mainvar, &main_newid); + } + blo_join_main((*fd)->mainlist); + mainvar = (*fd)->mainlist->first; + MEM_freeN((*fd)->mainlist); + BKE_main_id_tag_all(mainvar, LIB_TAG_NEW, false); lib_verify_nodetree(mainvar, false); @@ -10221,32 +10275,6 @@ static int mainvar_id_tag_any_check(Main *mainvar, const short tag) return false; } -static void split_main_newid(Main *mainptr, Main *main_newid) -{ - /* We only copy the necessary subset of data in this temp main. */ - main_newid->versionfile = mainptr->versionfile; - main_newid->subversionfile = mainptr->subversionfile; - BLI_strncpy(main_newid->name, mainptr->name, sizeof(main_newid->name)); - main_newid->curlib = mainptr->curlib; - - ListBase *lbarray[MAX_LIBARRAY]; - ListBase *lbarray_newid[MAX_LIBARRAY]; - int i = set_listbasepointers(mainptr, lbarray); - set_listbasepointers(main_newid, lbarray_newid); - while (i--) { - BLI_listbase_clear(lbarray_newid[i]); - - for (ID *id = lbarray[i]->first, *idnext; id; id = idnext) { - idnext = id->next; - - if (id->tag & LIB_TAG_NEW) { - BLI_remlink(lbarray[i], id); - BLI_addtail(lbarray_newid[i], id); - } - } - } -} - static void read_libraries(FileData *basefd, ListBase *mainlist) { Main *mainl = mainlist->first; diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 9a8f3da3396..ed719b66eb3 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -155,8 +155,9 @@ typedef struct Library { struct PackedFile *packedfile; + /* Temp data needed by read/write code. */ int temp_index; - int _pad; + short versionfile, subversionfile; /* see BLENDER_VERSION, BLENDER_SUBVERSION, needed for do_versions */ } Library; enum eIconSizes { From b47c912f4be877bf5511117864dfc2a5b30c0dca Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Fri, 23 Dec 2016 16:51:26 +0300 Subject: [PATCH 422/590] Fix (unreported) crash in 'Match movie length operator' in case of lost video texture file --- source/blender/editors/space_image/image_ops.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index f5da7d57010..6a1c0e7e4bf 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1475,7 +1475,10 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op)) if (!ima || !iuser || !BKE_image_has_anim(ima)) return OPERATOR_CANCELLED; - iuser->frames = IMB_anim_get_duration(((ImageAnim *) ima->anims.first)->anim, IMB_TC_RECORD_RUN); + struct ImageAnim *anim = ((ImageAnim *)ima->anims.first)->anim; + if (!anim) + return OPERATOR_CANCELLED; + iuser->frames = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN); BKE_image_user_frame_calc(iuser, scene->r.cfra, 0); return OPERATOR_FINISHED; From 3a9c490531556c1bad6e1f6e8cd7cd7f026b8437 Mon Sep 17 00:00:00 2001 From: Ulysse Martin Date: Sat, 24 Dec 2016 10:37:10 -0700 Subject: [PATCH 423/590] [MSVC] Fix test for C++11 support for vc2015/2017 based on D2432 by Ulysse Martin (youle) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8055f4fd3e9..6bb1792fef7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1573,7 +1573,7 @@ if(WITH_CXX11) if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang") # TODO(sergey): Do we want c++11 or gnu-c++11 here? set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") - elseif(MSVC12) + elseif(MSVC) # Nothing special is needed, C++11 features are available by default. else() message(FATAL_ERROR "Compiler ${CMAKE_C_COMPILER_ID} is not supported for C++11 build yet") From 41ec1adb030361df1e31d9db121f683900a464f1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 27 Dec 2016 15:27:38 +1100 Subject: [PATCH 424/590] Correct bad cast, unused var warning --- source/blender/blenloader/intern/readfile.c | 1 + source/blender/editors/space_image/image_ops.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index f568a741a30..b38d28b7d91 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -8381,6 +8381,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main) static void do_versions_after_linking(Main *main) { + UNUSED_VARS(main); // printf("%s for %s (%s), %d.%d\n", __func__, main->curlib ? main->curlib->name : main->name, // main->curlib ? "LIB" : "MAIN", main->versionfile, main->subversionfile); } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 6a1c0e7e4bf..324a3cb13b7 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1475,7 +1475,7 @@ static int image_match_len_exec(bContext *C, wmOperator *UNUSED(op)) if (!ima || !iuser || !BKE_image_has_anim(ima)) return OPERATOR_CANCELLED; - struct ImageAnim *anim = ((ImageAnim *)ima->anims.first)->anim; + struct anim *anim = ((ImageAnim *)ima->anims.first)->anim; if (!anim) return OPERATOR_CANCELLED; iuser->frames = IMB_anim_get_duration(anim, IMB_TC_RECORD_RUN); From c1e3041051f44916c896b0527b3a36937753360c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 27 Dec 2016 15:30:11 +1100 Subject: [PATCH 425/590] Comments: hints for perspective functions Note which GL functions these are equivalent to. --- source/blender/blenlib/intern/math_geom.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 38947e139ff..46d963ee268 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -3763,6 +3763,9 @@ void interp_barycentric_tri_v3(float data[3][3], float u, float v, float res[3]) /***************************** View & Projection *****************************/ +/** + * Matches `glOrtho` result. + */ void orthographic_m4(float matrix[4][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip) { @@ -3783,6 +3786,9 @@ void orthographic_m4(float matrix[4][4], const float left, const float right, co matrix[3][2] = -(farClip + nearClip) / Zdelta; } +/** + * Matches `glFrustum` result. + */ void perspective_m4(float mat[4][4], const float left, const float right, const float bottom, const float top, const float nearClip, const float farClip) { From 752a783fa431565d7d964871aceb90bfaa7c9234 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 27 Dec 2016 16:39:19 +0100 Subject: [PATCH 426/590] Fix T50305: Blender truncates a long multibyte character object's name to an invalid utf-8 string. Add logic in RNA to ensure we pass valid utf8 string to BKE ID new functions... --- source/blender/makesrna/intern/rna_main_api.c | 127 ++++++++++++++---- 1 file changed, 100 insertions(+), 27 deletions(-) diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index cecdb6bad51..c110dbff6c4 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -116,6 +116,13 @@ #endif +static void rna_idname_validate(const char *name, char *r_name) +{ + BLI_strncpy(r_name, name, MAX_ID_NAME - 2); + BLI_utf8_invalid_strip(r_name, strlen(r_name)); +} + + static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink) { ID *id = id_ptr->data; @@ -137,14 +144,20 @@ static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ static Camera *rna_Main_cameras_new(Main *bmain, const char *name) { - ID *id = BKE_camera_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + ID *id = BKE_camera_add(bmain, safe_name); id_us_min(id); return (Camera *)id; } static Scene *rna_Main_scenes_new(Main *bmain, const char *name) { - return BKE_scene_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + return BKE_scene_add(bmain, safe_name); } static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink) { @@ -180,6 +193,9 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char *name, ID *data) { + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + Object *ob; int type = OB_EMPTY; if (data) { @@ -223,7 +239,7 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char id_us_plus(data); } - ob = BKE_object_add_only_object(bmain, type, name); + ob = BKE_object_add_only_object(bmain, type, safe_name); id_us_min(&ob->id); ob->data = data; @@ -234,7 +250,10 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char static Material *rna_Main_materials_new(Main *bmain, const char *name) { - ID *id = (ID *)BKE_material_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + ID *id = (ID *)BKE_material_add(bmain, safe_name); id_us_min(id); return (Material *)id; } @@ -245,20 +264,27 @@ static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), Point } static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, int type) { + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + bNodeTreeType *typeinfo = rna_node_tree_type_from_enum(type); if (typeinfo) { - bNodeTree *ntree = ntreeAddTree(bmain, name, typeinfo->idname); + bNodeTree *ntree = ntreeAddTree(bmain, safe_name, typeinfo->idname); id_us_min(&ntree->id); return ntree; } - else + else { return NULL; + } } static Mesh *rna_Main_meshes_new(Main *bmain, const char *name) { - Mesh *me = BKE_mesh_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Mesh *me = BKE_mesh_add(bmain, safe_name); id_us_min(&me->id); return me; } @@ -286,7 +312,10 @@ Mesh *rna_Main_meshes_new_from_object( static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) { - Lamp *lamp = BKE_lamp_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Lamp *lamp = BKE_lamp_add(bmain, safe_name); lamp->type = type; id_us_min(&lamp->id); return lamp; @@ -294,8 +323,11 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d) { + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + float color[4] = {0.0, 0.0, 0.0, 1.0}; - Image *image = BKE_image_add_generated(bmain, width, height, name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d); + Image *image = BKE_image_add_generated(bmain, width, height, safe_name, alpha ? 32 : 24, float_buffer, 0, color, stereo3d); id_us_min(&image->id); return image; } @@ -322,21 +354,30 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char static Lattice *rna_Main_lattices_new(Main *bmain, const char *name) { - Lattice *lt = BKE_lattice_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Lattice *lt = BKE_lattice_add(bmain, safe_name); id_us_min(<->id); return lt; } static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type) { - Curve *cu = BKE_curve_add(bmain, name, type); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Curve *cu = BKE_curve_add(bmain, safe_name, type); id_us_min(&cu->id); return cu; } static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name) { - MetaBall *mb = BKE_mball_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + MetaBall *mb = BKE_mball_add(bmain, safe_name); id_us_min(&mb->id); return mb; } @@ -364,7 +405,10 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char * static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) { - Tex *tex = BKE_texture_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Tex *tex = BKE_texture_add(bmain, safe_name); BKE_texture_type_set(tex, type); id_us_min(&tex->id); return tex; @@ -372,26 +416,38 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) { - Brush *brush = BKE_brush_add(bmain, name, mode); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Brush *brush = BKE_brush_add(bmain, safe_name, mode); id_us_min(&brush->id); return brush; } static World *rna_Main_worlds_new(Main *bmain, const char *name) { - World *world = add_world(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + World *world = add_world(bmain, safe_name); id_us_min(&world->id); return world; } static Group *rna_Main_groups_new(Main *bmain, const char *name) { - return BKE_group_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + return BKE_group_add(bmain, safe_name); } static Speaker *rna_Main_speakers_new(Main *bmain, const char *name) { - Speaker *speaker = BKE_speaker_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Speaker *speaker = BKE_speaker_add(bmain, safe_name); id_us_min(&speaker->id); return speaker; } @@ -413,7 +469,10 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi static Text *rna_Main_texts_new(Main *bmain, const char *name) { - return BKE_text_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + return BKE_text_add(bmain, safe_name); } static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal) @@ -432,28 +491,40 @@ static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *f static bArmature *rna_Main_armatures_new(Main *bmain, const char *name) { - bArmature *arm = BKE_armature_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + bArmature *arm = BKE_armature_add(bmain, safe_name); id_us_min(&arm->id); return arm; } static bAction *rna_Main_actions_new(Main *bmain, const char *name) { - bAction *act = add_empty_action(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + bAction *act = add_empty_action(bmain, safe_name); id_fake_user_clear(&act->id); return act; } static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name) { - ParticleSettings *part = psys_new_settings(name, bmain); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + ParticleSettings *part = psys_new_settings(safe_name, bmain); id_us_min(&part->id); return part; } static Palette *rna_Main_palettes_new(Main *bmain, const char *name) { - Palette *palette = BKE_palette_add(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + Palette *palette = BKE_palette_add(bmain, safe_name); id_us_min(&palette->id); return (Palette *)palette; } @@ -481,16 +552,18 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons static Mask *rna_Main_mask_new(Main *bmain, const char *name) { - Mask *mask; + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); - mask = BKE_mask_new(bmain, name); - - return mask; + return BKE_mask_new(bmain, safe_name); } static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name) { - FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name); + char safe_name[MAX_ID_NAME - 2]; + rna_idname_validate(name, safe_name); + + FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, safe_name); id_us_min(&linestyle->id); return linestyle; } From d874b40a555790d1ca08a930597f017e59a4b698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20M=C3=BCller?= Date: Tue, 27 Dec 2016 20:47:01 +0100 Subject: [PATCH 427/590] Fix T50240: Rendering crashes when synced to JACK Transport Disabling synchronization while rendering. Using G.is_rendering as suggested by bastien. ;-) --- source/blender/blenkernel/intern/sound.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index f20885b1e8f..d5a395ffc4b 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -167,6 +167,10 @@ static const char *force_device = NULL; #ifdef WITH_JACK static void sound_sync_callback(void *data, int mode, float time) { + // Ugly: Blender doesn't like it when the animation is played back during rendering + if (G.is_rendering) + return; + struct Main *bmain = (struct Main *)data; struct Scene *scene; @@ -693,6 +697,10 @@ void BKE_sound_seek_scene(struct Main *bmain, struct Scene *scene) float BKE_sound_sync_scene(struct Scene *scene) { + // Ugly: Blender doesn't like it when the animation is played back during rendering + if (G.is_rendering) + return NAN_FLT; + if (scene->playback_handle) { if (scene->audio.flag & AUDIO_SYNC) return AUD_getSynchronizerPosition(scene->playback_handle); @@ -704,6 +712,10 @@ float BKE_sound_sync_scene(struct Scene *scene) int BKE_sound_scene_playing(struct Scene *scene) { + // Ugly: Blender doesn't like it when the animation is played back during rendering + if (G.is_rendering) + return -1; + if (scene->audio.flag & AUDIO_SYNC) return AUD_isSynchronizerPlaying(); else From d5edaac42d3b49e1a9abef1f7bcc54fb6f067ef8 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 28 Dec 2016 15:35:59 +1100 Subject: [PATCH 428/590] Comments: mul_project_m4_v3_zfac --- source/blender/blenlib/intern/math_vector_inline.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index e9fb77f6302..ee5e8651bd3 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -479,7 +479,18 @@ MINLINE void mul_v2_v2_ccw(float r[2], const float mat[2], const float vec[2]) r[1] = mat[1] * vec[0] + (+mat[0]) * vec[1]; } -/* note: could add a matrix inline */ +/** + * Convenience function to get the projected depth of a position. + * This avoids creating a temporary 4D vector and multiplying it - only for the 4th component. + * + * Matches logic for: + * + * \code{.c} + * float co_4d[4] = {co[0], co[1], co[2], 1.0}; + * mul_m4_v4(mat, co_4d); + * return co_4d[3]; + * \endcode + */ MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3]) { return (mat[0][3] * co[0]) + From 6559ab2d511b1c0c1845342133505139166da4b3 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 28 Dec 2016 17:44:36 +1100 Subject: [PATCH 429/590] 3D View roll & orbit were scaling view-quat length Over time roll and orbit would scale the quaternion which is documented as unit length. In practice any errors would be subtle, but better normalize as other operators do. --- source/blender/editors/space_view3d/view3d_edit.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 620bbf03f32..2b53eb71d99 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -4064,6 +4064,9 @@ static int vieworbit_exec(bContext *C, wmOperator *op) mul_qt_qtqt(quat_new, rv3d->viewquat, quat_mul); + /* avoid precision loss over time */ + normalize_qt(quat_new); + if (view_opposite != RV3D_VIEW_USER) { rv3d->view = view_opposite; /* avoid float in-precision, just get a new orientation */ @@ -4130,6 +4133,10 @@ static void view_roll_angle(ARegion *ar, float quat[4], const float orig_quat[4] axis_angle_normalized_to_quat(quat_mul, dvec, angle); mul_qt_qtqt(quat, orig_quat, quat_mul); + + /* avoid precision loss over time */ + normalize_qt(quat); + rv3d->view = RV3D_VIEW_USER; } From 7f262acb92e5873f3c6fd63520bcec60f8e220dc Mon Sep 17 00:00:00 2001 From: Tamito Kajiyama Date: Wed, 28 Dec 2016 18:05:28 +0900 Subject: [PATCH 430/590] Fix T49479: Freestyle inconsistent line drawing with large geometry dimension. Ray-plane intersection routine GeomUtils::intersectRayPlane() was used with an unnormalized direction vector as input. --- .../freestyle/intern/geometry/GeomUtils.cpp | 2 + .../intern/view_map/ViewMapBuilder.cpp | 40 ++++++++++--------- .../intern/view_map/ViewMapBuilder.h | 2 +- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/source/blender/freestyle/intern/geometry/GeomUtils.cpp b/source/blender/freestyle/intern/geometry/GeomUtils.cpp index 3eb92c559fe..cd7c1b83a4e 100644 --- a/source/blender/freestyle/intern/geometry/GeomUtils.cpp +++ b/source/blender/freestyle/intern/geometry/GeomUtils.cpp @@ -470,6 +470,8 @@ bool intersectRayTriangle(const Vec3r& orig, const Vec3r& dir, const Vec3r& v0, } // Intersection between plane and ray, adapted from Graphics Gems, Didier Badouel +// The plane is represented by a set of points P implicitly defined as dot(norm, P) + d = 0. +// The ray is represented as r(t) = orig + dir * t. intersection_test intersectRayPlane(const Vec3r& orig, const Vec3r& dir, const Vec3r& norm, const real d, real& t, const real epsilon) { diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp index 380bb0dd3ca..794c782bb73 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp @@ -57,7 +57,7 @@ using namespace std; template static void findOccludee(FEdge *fe, G& /*grid*/, I& occluders, real epsilon, WFace **oaWFace, - Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector& faceVertices) + Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector& faceVertices) { WFace *face = NULL; if (fe->isSmooth()) { @@ -125,7 +125,7 @@ static void findOccludee(FEdge *fe, G& /*grid*/, I& occluders, real epsilon, WFa // check whether the edge and the polygon plane are coincident: //------------------------------------------------------------- //first let us compute the plane equation. - if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, p->getNormal(), d, t, epsilon)) + if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, p->getNormal(), d, t, epsilon)) { #if LOGGING if (_global.debug & G_DEBUG_FREESTYLE) { @@ -172,10 +172,11 @@ template static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WFace **oaFace) { Vec3r A; - Vec3r edge; + Vec3r edgeDir; Vec3r origin; A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0); - edge = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D()); + edgeDir = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D()); + edgeDir.normalize(); origin = Vec3r((fe)->vertexA()->point3D()); Vec3r u; if (grid.orthographicProjection()) { @@ -199,7 +200,7 @@ static void findOccludee(FEdge *fe, G& grid, real epsilon, ViewEdge * /*ve*/, WF } I occluders(grid, A, epsilon); - findOccludee(fe, grid, occluders, epsilon, oaFace, u, A, origin, edge, faceVertices); + findOccludee(fe, grid, occluders, epsilon, oaFace, u, A, origin, edgeDir, faceVertices); } // computeVisibility takes a pointer to foundOccluders, instead of using a reference, @@ -211,11 +212,12 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, int qi = 0; Vec3r center; - Vec3r edge; + Vec3r edgeDir; Vec3r origin; center = fe->center3d(); - edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D()); + edgeDir = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D()); + edgeDir.normalize(); origin = Vec3r(fe->vertexA()->point3D()); Vec3r vp; @@ -337,7 +339,7 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, // check whether the edge and the polygon plane are coincident: //------------------------------------------------------------- //first let us compute the plane equation. - if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, p->getNormal(), d, t, epsilon)) { + if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, p->getNormal(), d, t, epsilon)) { #if LOGGING if (_global.debug & G_DEBUG_FREESTYLE) { cout << "\t\tRejecting occluder for target coincidence." << endl; @@ -391,7 +393,7 @@ static int computeVisibility(ViewMap *viewMap, FEdge *fe, G& grid, real epsilon, } // Find occludee - findOccludee(fe, grid, occluders, epsilon, oaWFace, u, center, origin, edge, faceVertices); + findOccludee(fe, grid, occluders, epsilon, oaWFace, u, center, origin, edgeDir, faceVertices); return qi; } @@ -1788,7 +1790,7 @@ void ViewMapBuilder::ComputeVeryFastRayCastingVisibility(ViewMap *ioViewMap, rea } void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp, - Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector& faceVertices) + Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector& faceVertices) { WFace *face = NULL; if (fe->isSmooth()) { @@ -1856,7 +1858,7 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3 continue; } else { - if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon)) + if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, normal, d, t, epsilon)) continue; } if ((*p)->rayIntersect(A, v, t, t_u, t_v)) { @@ -1883,10 +1885,11 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3 OccludersSet occluders; Vec3r A; - Vec3r edge; + Vec3r edgeDir; Vec3r origin; A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D()) / 2.0); - edge = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D()); + edgeDir = Vec3r((fe)->vertexB()->point3D() - (fe)->vertexA()->point3D()); + edgeDir.normalize(); origin = Vec3r((fe)->vertexA()->point3D()); Vec3r u; if (_orthographicProjection) { @@ -1910,7 +1913,7 @@ void ViewMapBuilder::FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3 if (face) face->RetrieveVertexList(faceVertices); - return FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, A, origin, edge, faceVertices); + return FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, A, origin, edgeDir, faceVertices); } int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real epsilon, set& oOccluders, @@ -1920,11 +1923,12 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps int qi = 0; Vec3r center; - Vec3r edge; + Vec3r edgeDir; Vec3r origin; center = fe->center3d(); - edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D()); + edgeDir = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D()); + edgeDir.normalize(); origin = Vec3r(fe->vertexA()->point3D()); // Is the edge outside the view frustum ? Vec3r gridOrigin(iGrid->getOrigin()); @@ -2062,7 +2066,7 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps //------------------------------------------------------------- //first let us compute the plane equation. - if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon)) { + if (GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edgeDir, normal, d, t, epsilon)) { #if LOGGING if (_global.debug & G_DEBUG_FREESTYLE) { cout << "\t\tRejecting occluder for target coincidence." << endl; @@ -2099,7 +2103,7 @@ int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid *iGrid, real eps } // Find occludee - FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, origin, edge, faceVertices); + FindOccludee(fe, iGrid, epsilon, oaPolygon, timestamp, u, center, origin, edgeDir, faceVertices); return qi; } diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h index 36497bf8d22..440ae93c7df 100644 --- a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h @@ -250,7 +250,7 @@ protected: // FIXME void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp); void FindOccludee(FEdge *fe, Grid *iGrid, real epsilon, Polygon3r **oaPolygon, unsigned timestamp, - Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector& faceVertices); + Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edgeDir, vector& faceVertices); #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:ViewMapBuilder") From c5338fd1620d387c9f5a2db9904ee3d950a0e787 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 28 Dec 2016 16:54:57 +1300 Subject: [PATCH 431/590] Fix T50184: Grease Pencil Layer synchronization between Dope Sheet and Properties panel --- source/blender/editors/animation/anim_deps.c | 26 +++++++++++++++++++ .../editors/space_action/space_action.c | 13 +++++++--- source/blender/makesrna/intern/rna_gpencil.c | 7 ++--- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index 437dd2b2de2..cc77a321a89 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -309,6 +309,28 @@ static void animchan_sync_fcurve(bAnimContext *ac, bAnimListElem *ale, FCurve ** } } +/* perform syncing updates for GPencil Layers */ +static void animchan_sync_gplayer(bAnimContext *UNUSED(ac), bAnimListElem *ale) +{ + bGPDlayer *gpl = (bGPDlayer *)ale->data; + + /* Make sure the selection flags agree with the "active" flag. + * The selection flags are used in the Dopesheet only, whereas + * the active flag is used everywhere else. Hence, we try to + * sync these here so that it all seems to be have as the user + * expects - T50184 + * + * Assume that we only really do this when the active status changes. + * (NOTE: This may prove annoying if it means selection is always lost) + */ + if (gpl->flag & GP_LAYER_ACTIVE) { + gpl->flag |= GP_LAYER_SELECT; + } + else { + gpl->flag &= ~GP_LAYER_SELECT; + } +} + /* ---------------- */ /* Main call to be exported to animation editors */ @@ -343,6 +365,10 @@ void ANIM_sync_animchannels_to_data(const bContext *C) case ANIMTYPE_FCURVE: animchan_sync_fcurve(&ac, ale, &active_fcurve); break; + + case ANIMTYPE_GPLAYER: + animchan_sync_gplayer(&ac, ale); + break; } } diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 671d6bb083e..83655a2ba9e 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -337,7 +337,7 @@ static void action_channel_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED( } break; case NC_GPENCIL: - if (wmn->action == NA_RENAME) + if (ELEM(wmn->action, NA_RENAME, NA_SELECTED)) ED_region_tag_redraw(ar); break; case NC_ID: @@ -407,10 +407,15 @@ static void action_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) /* context changes */ switch (wmn->category) { case NC_GPENCIL: - if (wmn->action == NA_EDITED) { - /* only handle this event in GPencil mode for performance considerations */ - if (saction->mode == SACTCONT_GPENCIL) + /* only handle these events in GPencil mode for performance considerations */ + if (saction->mode == SACTCONT_GPENCIL) { + if (wmn->action == NA_EDITED) { ED_area_tag_redraw(sa); + } + else if (wmn->action == NA_SELECTED) { + saction->flag |= SACTION_TEMP_NEEDCHANSYNC; + ED_area_tag_refresh(sa); + } } break; case NC_ANIMATION: diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 69ee671901a..41a73cfc528 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1276,13 +1276,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_ACTIVE); RNA_def_property_boolean_funcs(prop, NULL, "rna_GPencilLayer_active_set"); RNA_def_property_ui_text(prop, "Active", "Set active layer for editing"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); #endif prop = RNA_def_property(srna, "select", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_SELECT); RNA_def_property_ui_text(prop, "Select", "Layer is selected for editing in the Dope Sheet"); - RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, "rna_GPencil_update"); /* XXX keep this option? */ prop = RNA_def_property(srna, "show_points", PROP_BOOLEAN, PROP_NONE); @@ -1370,14 +1370,15 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_layer_get", "rna_GPencil_active_layer_set", NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Active Layer", "Active grease pencil layer"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_funcs(prop, "rna_GPencil_active_layer_index_get", "rna_GPencil_active_layer_index_set", "rna_GPencil_active_layer_index_range"); RNA_def_property_ui_text(prop, "Active Layer Index", "Index of active grease pencil layer"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); } static void rna_def_gpencil_palettecolor(BlenderRNA *brna) From 3cbe95f68312da5320cfcfd0c6f171708b27f188 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 28 Dec 2016 23:20:25 +1300 Subject: [PATCH 432/590] Fix T49816: Keyframing NLA Strip influence from Python set keyframes in the wrong place --- source/blender/python/intern/bpy_rna_anim.c | 42 ++++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 92931eb8090..893f1370637 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -223,9 +223,47 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb { return NULL; } - else { - short result; + else if (self->ptr.type == &RNA_NlaStrip) { + /* Handle special properties for NLA Strips, whose F-Curves are stored on the + * strips themselves. These are stored separately or else the properties will + * not have any effect. + */ ReportList reports; + short result = 0; + + PointerRNA ptr = self->ptr; + PropertyRNA *prop = NULL; + const char *prop_name; + + BKE_reports_init(&reports, RPT_STORE); + + /* Retrieve the property identifier from the full path, since we can't get it any other way */ + prop_name = strrchr(path_full, '.'); + if ((prop_name >= path_full) && + (prop_name + 1 < path_full + strlen(path_full))) + { + prop = RNA_struct_find_property(&ptr, prop_name + 1); + } + + if (prop) { + NlaStrip *strip = (NlaStrip *)ptr.data; + FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); + + result = insert_keyframe_direct(&reports, ptr, prop, fcu, cfra, keytype, index); + } + else { + BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full); + } + MEM_freeN((void *)path_full); + + if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) + return NULL; + + return PyBool_FromLong(result); + } + else { + ReportList reports; + short result; BKE_reports_init(&reports, RPT_STORE); From b1c6ddb107cfe5bff3e3f0da986fe14c694727bc Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 28 Dec 2016 23:27:46 +1300 Subject: [PATCH 433/590] Also apply similar fixes to .keyframe_delete() - T49816 --- source/blender/python/intern/bpy_rna_anim.c | 64 +++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 893f1370637..5fbe1ab971a 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -36,12 +36,15 @@ #include "DNA_scene_types.h" #include "DNA_anim_types.h" + #include "ED_keyframing.h" +#include "ED_keyframes_edit.h" #include "BKE_report.h" #include "BKE_context.h" #include "BKE_animsys.h" #include "BKE_fcurve.h" +#include "BKE_idcode.h" #include "RNA_access.h" #include "RNA_enum_types.h" @@ -310,6 +313,67 @@ PyObject *pyrna_struct_keyframe_delete(BPy_StructRNA *self, PyObject *args, PyOb { return NULL; } + else if (self->ptr.type == &RNA_NlaStrip) { + /* Handle special properties for NLA Strips, whose F-Curves are stored on the + * strips themselves. These are stored separately or else the properties will + * not have any effect. + */ + ReportList reports; + short result = 0; + + PointerRNA ptr = self->ptr; + PropertyRNA *prop = NULL; + const char *prop_name; + + BKE_reports_init(&reports, RPT_STORE); + + /* Retrieve the property identifier from the full path, since we can't get it any other way */ + prop_name = strrchr(path_full, '.'); + if ((prop_name >= path_full) && + (prop_name + 1 < path_full + strlen(path_full))) + { + prop = RNA_struct_find_property(&ptr, prop_name + 1); + } + + if (prop) { + ID *id = ptr.id.data; + NlaStrip *strip = (NlaStrip *)ptr.data; + FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); + + BLI_assert(fcu != NULL); /* NOTE: This should be true, or else we wouldn't be able to get here */ + + if (BKE_fcurve_is_protected(fcu)) { + BKE_reportf(&reports, RPT_WARNING, + "Not deleting keyframe for locked F-Curve for NLA Strip influence on %s - %s '%s'", + strip->name, BKE_idcode_to_name(GS(id->name)), id->name + 2); + } + else { + /* remove the keyframe directly + * NOTE: cannot use delete_keyframe_fcurve(), as that will free the curve, + * and delete_keyframe() expects the FCurve to be part of an action + */ + bool found = false; + int i; + + /* try to find index of beztriple to get rid of */ + i = binarysearch_bezt_index(fcu->bezt, cfra, fcu->totvert, &found); + if (found) { + /* delete the key at the index (will sanity check + do recalc afterwards) */ + delete_fcurve_key(fcu, i, 1); + result = true; + } + } + } + else { + BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full); + } + MEM_freeN((void *)path_full); + + if (BPy_reports_to_error(&reports, PyExc_RuntimeError, true) == -1) + return NULL; + + return PyBool_FromLong(result); + } else { short result; ReportList reports; From cabd2dcecaefc62501d95cc0f7c2163f4017588f Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 28 Dec 2016 14:09:02 +0100 Subject: [PATCH 434/590] Tweak error message when external image editor launching fails. Include idea that Blender may fail to launch it even if path is correct, in some cases (dear Windows...). Based on idea from @lijenstina and @blendify (D2349), thanks. --- release/scripts/startup/bl_operators/image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_operators/image.py b/release/scripts/startup/bl_operators/image.py index f00f5d97c5e..d3460383fe7 100644 --- a/release/scripts/startup/bl_operators/image.py +++ b/release/scripts/startup/bl_operators/image.py @@ -82,8 +82,8 @@ class EditExternally(Operator): import traceback traceback.print_exc() self.report({'ERROR'}, - "Image editor not found, " - "please specify in User Preferences > File") + "Image editor could not be launched, please ensure that " + "the path in User Preferences > File is valid, and Blender has rights to launch it") return {'CANCELLED'} From 45d0231a2426820dccfa21f6ad3ed2dbd83bbf50 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 28 Dec 2016 14:17:15 +0100 Subject: [PATCH 435/590] Minor UI message fix. Based on D2436 by @blendify, thanks. --- source/blender/makesrna/intern/rna_sequencer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index ae444acc432..3e6d8441363 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1674,7 +1674,7 @@ static void rna_def_filter_video(StructRNA *srna) prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_FILTERY); - RNA_def_property_ui_text(prop, "De-Interlace", "For video movies to remove fields"); + RNA_def_property_ui_text(prop, "Deinterlace", "Remove fields from video movies"); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update_reopen_files"); prop = RNA_def_property(srna, "alpha_mode", PROP_ENUM, PROP_NONE); From 11ae06b0b7442d63904270e8b72266e5fa3519cf Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 28 Dec 2016 14:25:06 +0100 Subject: [PATCH 436/590] Update manual links in 'add object' py template. Patch D2328 by @blendify, thanks. --- release/scripts/templates_py/addon_add_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/scripts/templates_py/addon_add_object.py b/release/scripts/templates_py/addon_add_object.py index 8e57d7ef8f8..d294838d3a2 100644 --- a/release/scripts/templates_py/addon_add_object.py +++ b/release/scripts/templates_py/addon_add_object.py @@ -69,9 +69,9 @@ def add_object_button(self, context): # This allows you to right click on a button and link to the manual def add_object_manual_map(): - url_manual_prefix = "http://wiki.blender.org/index.php/Doc:2.6/Manual/" + url_manual_prefix = "https://www.blender.org/manual/" url_manual_mapping = ( - ("bpy.ops.mesh.add_object", "Modeling/Objects"), + ("bpy.ops.mesh.add_object", "editors/3dview/object"), ) return url_manual_prefix, url_manual_mapping From a522469940375a22792356e40a4dcd7b949893d7 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 28 Dec 2016 14:37:08 +0100 Subject: [PATCH 437/590] Various UI message and API doc tweaks and fixes. Mostly from patch D2256 by Aaron Carlisle (@Blendify), thanks! --- .../rst/bge_types/bge.types.KX_GameObject.rst | 18 +++++++++--------- doc/python_api/rst/info_api_reference.rst | 2 +- .../editors/space_view3d/view3d_buttons.c | 6 +++--- .../blender/editors/uvedit/uvedit_unwrap_ops.c | 4 ++-- source/blender/makesrna/intern/rna_mesh.c | 8 ++++---- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst index d8cc5e45e83..c5729fd5b19 100644 --- a/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst +++ b/doc/python_api/rst/bge_types/bge.types.KX_GameObject.rst @@ -405,7 +405,7 @@ base class --- :class:`SCA_IObject` .. note:: - This attribute is experemental and may be removed (but probably wont be). + This attribute is experimental and may be removed (but probably wont be). .. note:: @@ -419,7 +419,7 @@ base class --- :class:`SCA_IObject` .. note:: - This attribute is experemental and may be removed (but probably wont be). + This attribute is experimental and may be removed (but probably wont be). .. note:: @@ -453,7 +453,7 @@ base class --- :class:`SCA_IObject` .. attribute:: childrenRecursive - all children of this object including childrens children, (read-only). + all children of this object including children's children, (read-only). :type: :class:`CListValue` of :class:`KX_GameObject`'s @@ -536,7 +536,7 @@ base class --- :class:`SCA_IObject` .. method:: getAxisVect(vect) - Returns the axis vector rotates by the objects worldspace orientation. + Returns the axis vector rotates by the object's worldspace orientation. This is the equivalent of multiplying the vector by the orientation matrix. :arg vect: a vector to align the axis. @@ -596,7 +596,7 @@ base class --- :class:`SCA_IObject` Gets the game object's linear velocity. - This method returns the game object's velocity through it's centre of mass, ie no angular velocity component. + This method returns the game object's velocity through it's center of mass, ie no angular velocity component. :arg local: * False: you get the "global" velocity ie: relative to world orientation. @@ -609,7 +609,7 @@ base class --- :class:`SCA_IObject` Sets the game object's linear velocity. - This method sets game object's velocity through it's centre of mass, + This method sets game object's velocity through it's center of mass, ie no angular velocity component. This requires a dynamic object. @@ -814,7 +814,7 @@ base class --- :class:`SCA_IObject` # do something pass - The face paremeter determines the orientation of the normal. + The face parameter determines the orientation of the normal. * 0 => hit normal is always oriented towards the ray origin (as if you casted the ray from outside) * 1 => hit normal is the real face normal (only for mesh object, otherwise face has no effect) @@ -911,7 +911,7 @@ base class --- :class:`SCA_IObject` .. note:: - The gameObject argument has an advantage that it can convert from a mesh with modifiers applied (such as subsurf). + The gameObject argument has an advantage that it can convert from a mesh with modifiers applied (such as the Subdivision Surface modifier). .. warning:: @@ -919,7 +919,7 @@ base class --- :class:`SCA_IObject` .. warning:: - If the object is a part of a combound object it will fail (parent or child) + If the object is a part of a compound object it will fail (parent or child) .. warning:: diff --git a/doc/python_api/rst/info_api_reference.rst b/doc/python_api/rst/info_api_reference.rst index 43469fc0cb7..5ef5866c44a 100644 --- a/doc/python_api/rst/info_api_reference.rst +++ b/doc/python_api/rst/info_api_reference.rst @@ -204,7 +204,7 @@ Lets say we want to access the texture of a brush via Python, to adjust its ``co - Start in the default scene and enable 'Sculpt' mode from the 3D-View header. - From the toolbar expand the **Texture** panel and add a new texture. - *Notice the texture button its self doesn't have very useful links (you can check the tool-tips).* + *Notice the texture button its self doesn't have very useful links (you can check the tooltips).* - The contrast setting isn't exposed in the sculpt toolbar, so view the texture in the properties panel... - In the properties button select the Texture context. diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index b9c8c98b62f..351c7ccec15 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -476,7 +476,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"), 0, yi -= buth + but_margin, 200, buth, - &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by SubSurf modifier")); + &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by the Subdivision Surface modifier")); } } /* Curve... */ @@ -491,7 +491,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float else if (totcurvedata > 1) { uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"), 0, yi -= buth + but_margin, 200, buth, - &(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for SoftBody Goal")); + &(tfp->ve_median[C_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal")); uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Radius:"), 0, yi -= buth + but_margin, 200, buth, &(tfp->ve_median[C_RADIUS]), 0.0, 100.0, 1, 3, TIP_("Radius of curve control points")); @@ -509,7 +509,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float else if (totlattdata > 1) { uiDefButF(block, UI_BTYPE_NUM, B_OBJECTPANELMEDIAN, IFACE_("Mean Weight:"), 0, yi -= buth + but_margin, 200, buth, - &(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for SoftBody Goal")); + &(tfp->ve_median[L_WEIGHT]), 0.0, 1.0, 1, 3, TIP_("Weight used for Soft Body Goal")); } UI_block_align_end(block); diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c index 8e4ba4c0afa..d8080002818 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c @@ -1222,7 +1222,7 @@ static int unwrap_exec(bContext *C, wmOperator *op) * pass operator for warning append */ modifier_unwrap_state(obedit, scene, &use_subsurf_final); if (use_subsurf != use_subsurf_final) - BKE_report(op->reports, RPT_INFO, "Subsurf modifier needs to be first to work with unwrap"); + BKE_report(op->reports, RPT_INFO, "Subdivision Surface modifier needs to be first to work with unwrap"); /* execute unwrap */ ED_unwrap_lscm(scene, obedit, true); @@ -1259,7 +1259,7 @@ void UV_OT_unwrap(wmOperatorType *ot) RNA_def_boolean(ot->srna, "correct_aspect", 1, "Correct Aspect", "Map UVs taking image aspect ratio into account"); RNA_def_boolean(ot->srna, "use_subsurf_data", 0, "Use Subsurf Modifier", - "Map UVs taking vertex position after subsurf into account"); + "Map UVs taking vertex position after Subdivision Surface modifier has been applied"); RNA_def_float_factor(ot->srna, "margin", 0.001f, 0.0f, 1.0f, "Margin", "Space between islands", 0.0f, 1.0f); } diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 3dc58442851..ad5f320625c 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -1962,7 +1962,7 @@ static void rna_def_medge(BlenderRNA *brna) prop = RNA_def_property(srna, "crease", PROP_FLOAT, PROP_NONE); RNA_def_property_float_funcs(prop, "rna_MEdge_crease_get", "rna_MEdge_crease_set", NULL); - RNA_def_property_ui_text(prop, "Crease", "Weight used by the Subsurf modifier for creasing"); + RNA_def_property_ui_text(prop, "Crease", "Weight used by the Subdivision Surface modifier for creasing"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "bevel_weight", PROP_FLOAT, PROP_NONE); @@ -1987,7 +1987,7 @@ static void rna_def_medge(BlenderRNA *brna) prop = RNA_def_property(srna, "use_edge_sharp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SHARP); - RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the EdgeSplit modifier"); + RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the Edge Split modifier"); RNA_def_property_update(prop, 0, "rna_Mesh_update_data"); prop = RNA_def_property(srna, "is_loose", PROP_BOOLEAN, PROP_NONE); @@ -3560,7 +3560,7 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "show_edge_crease", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWCREASES); - RNA_def_property_ui_text(prop, "Draw Creases", "Display creases created for subsurf weighting"); + RNA_def_property_ui_text(prop, "Draw Creases", "Display creases created for Subdivision Surface modifier"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); prop = RNA_def_property(srna, "show_edge_bevel_weight", PROP_BOOLEAN, PROP_NONE); @@ -3575,7 +3575,7 @@ static void rna_def_mesh(BlenderRNA *brna) prop = RNA_def_property(srna, "show_edge_sharp", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "drawflag", ME_DRAWSHARP); - RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the EdgeSplit modifier"); + RNA_def_property_ui_text(prop, "Draw Sharp", "Display sharp edges, used with the Edge Split modifier"); RNA_def_property_update(prop, 0, "rna_Mesh_update_draw"); prop = RNA_def_property(srna, "show_freestyle_edge_marks", PROP_BOOLEAN, PROP_NONE); From 2412e67ef860412d814d2fff505ac2f39eb80326 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 28 Dec 2016 15:07:18 +0100 Subject: [PATCH 438/590] UI: Make icon-only buttons for enum items with empty label. Patch D2420 by @raa, thanks. --- source/blender/editors/interface/interface_layout.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 80d091c0fdb..940e982d326 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1463,8 +1463,9 @@ void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *pr for (a = 0; item[a].identifier; a++) { if (item[a].value == ivalue) { const char *item_name = name ? name : CTX_IFACE_(RNA_property_translation_context(prop), item[a].name); + const int flag = item_name[0] ? 0 : UI_ITEM_R_ICON_ONLY; - uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name, icon ? icon : item[a].icon); + uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, flag, item_name, icon ? icon : item[a].icon); break; } } From 3d243eb710dd7f2ddef3c421c1fd225390115185 Mon Sep 17 00:00:00 2001 From: Howard Trickey Date: Wed, 28 Dec 2016 13:55:19 -0500 Subject: [PATCH 439/590] Fix T49848: bevel of spiral gets bigger and bigger widths. This is the same issue as was fixed with T39486: the adjustment pass that tries to equalize different widths at either end of an edge sometimes causes the widths to get bigger and bigger. The previous fix was to let "clamp_overlap" do double duty as a way to limit this behavior. But clearly this is undiscoverable, as the current bug report shows. So I put in an "auto-limiting" mode that detects when adjustments are going crazy and then acts as if clamp_overlap were set. The reason we can't always act as if clamp_overlap is set is that certain models (e.g., Bent_test in regression tests) look bad if that is enabled. --- source/blender/bmesh/tools/bmesh_bevel.c | 48 +++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 8340be81aa8..05169a2a976 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -57,6 +57,7 @@ #define BEVEL_EPSILON_ANG DEG2RADF(2.0f) #define BEVEL_SMALL_ANG DEG2RADF(10.0f) #define BEVEL_MAX_ADJUST_PCT 10.0f +#define BEVEL_MAX_AUTO_ADJUST_PCT 300.0f /* happens far too often, uncomment for development */ // #define BEVEL_ASSERT_PROJECT @@ -323,15 +324,33 @@ static bool edge_half_offset_changed(EdgeHalf *e) e->offset_r != e->offset_r_spec; } -static bool any_edge_half_offset_changed(BevVert *bv) +static float adjusted_rel_change(float val, float spec) +{ + float relchg; + + relchg = 0.0f; + if (val != spec) { + if (spec == 0) + relchg = 1000.0f; /* arbitrary large value */ + else + relchg = fabsf((val - spec) / spec); + } + return relchg; +} + +static float max_edge_half_offset_rel_change(BevVert *bv) { int i; + float max_rel_change; + EdgeHalf *e; + max_rel_change = 0.0f; for (i = 0; i < bv->edgecount; i++) { - if (edge_half_offset_changed(&bv->edges[i])) - return true; + e = &bv->edges[i]; + max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_l, e->offset_l_spec)); + max_rel_change = max_ff(max_rel_change, adjusted_rel_change(e->offset_r, e->offset_r_spec)); } - return false; + return max_rel_change; } /* Return the next EdgeHalf after from_e that is beveled. @@ -1951,6 +1970,7 @@ static void adjust_offsets(BevelParams *bp) GHashIterator giter; EdgeHalf *e, *efirst, *eother; GSQueue *q; + float max_rel_adj; BLI_assert(!bp->vertex_only); GHASH_ITER(giter, bp->vert_hash) { @@ -1966,7 +1986,7 @@ static void adjust_offsets(BevelParams *bp) searchi = -1; GHASH_ITER(giter, bp->vert_hash) { bv = BLI_ghashIterator_getValue(&giter); - if (!bv->visited && any_edge_half_offset_changed(bv)) { + if (!bv->visited && max_edge_half_offset_rel_change(bv) > 0.0f) { i = BM_elem_index_get(bv->v); if (!searchbv || i < searchi) { searchbv = bv; @@ -1996,6 +2016,24 @@ static void adjust_offsets(BevelParams *bp) } } BLI_gsqueue_free(q); + + /* Should we auto-limit the error accumulation? Typically, spirals can lead to 100x relative adjustments, + * and somewhat hacky mechanism of using bp->limit_offset to indicate "clamp the adjustments" is not + * obvious to users, who almost certainaly want clamping in this situation. + * The reason not to clamp always is that some models work better without it (e.g., Bent_test in regression + * suite, where relative adjust maximum is about .6). */ + if (!bp->limit_offset) { + max_rel_adj = 0.0f; + GHASH_ITER(giter, bp->vert_hash) { + bv = BLI_ghashIterator_getValue(&giter); + max_rel_adj = max_ff(max_rel_adj, max_edge_half_offset_rel_change(bv)); + } + if (max_rel_adj > BEVEL_MAX_AUTO_ADJUST_PCT / 100.0f) { + bp->limit_offset = true; + adjust_offsets(bp); + bp->limit_offset = false; + } + } } /* Do the edges at bv form a "pipe"? From 6bd245bb530ad48bfd7038c082bdc1870a18dd91 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Thu, 29 Dec 2016 01:09:11 -0500 Subject: [PATCH 440/590] Edits to user prefs NDOF UI Small changes: - Remove "NDOF" from each setting - Change tooltip for deadzone - Unrelated typo in cmake comment Reviewers: merwin, Severin Reviewed By: merwin, Severin Tags: #bf_blender, #user_interface Differential Revision: https://developer.blender.org/D2319 --- CMakeLists.txt | 2 +- release/scripts/startup/bl_ui/space_userpref.py | 13 ++++++++++--- source/blender/makesrna/intern/rna_userdef.c | 4 ++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bb1792fef7..8b64f7b8afd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -867,7 +867,7 @@ endif() # linux only, not cached set(WITH_BINRELOC OFF) -# MAXOSX only, set to avoid uninitialized +# MACOSX only, set to avoid uninitialized set(EXETYPE "") # C/C++ flags diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index e5b6a94c1ab..075a6f870fa 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -1180,11 +1180,18 @@ class USERPREF_PT_input(Panel): col.separator() col.label(text="NDOF Device:") sub = col.column(align=True) - sub.prop(inputs, "ndof_sensitivity", text="NDOF Sensitivity") - sub.prop(inputs, "ndof_orbit_sensitivity", text="NDOF Orbit Sensitivity") - sub.prop(inputs, "ndof_deadzone", text="NDOF Deadzone") + sub.prop(inputs, "ndof_sensitivity", text="Pan Sensitivity") + sub.prop(inputs, "ndof_orbit_sensitivity", text="Orbit Sensitivity") + sub.prop(inputs, "ndof_deadzone", text="Deadzone") + + sub.separator() + col.label(text="Navigation Style:") sub = col.column(align=True) sub.row().prop(inputs, "ndof_view_navigate_method", expand=True) + + sub.separator() + col.label(text="Rotation Style:") + sub = col.column(align=True) sub.row().prop(inputs, "ndof_view_rotate_method", expand=True) row.separator() diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index beb1d890ba9..e68e67586e9 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -3287,7 +3287,7 @@ static void rna_def_userdef_walk_navigation(BlenderRNA *brna) prop = RNA_def_property(srna, "use_mouse_reverse", PROP_BOOLEAN, PROP_BOOLEAN); RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_WALK_MOUSE_REVERSE); - RNA_def_property_ui_text(prop, "Reverse Mouse", "Reverse the mouse look"); + RNA_def_property_ui_text(prop, "Reverse Mouse", "Reverse the vertical movement of the mouse"); } static void rna_def_userdef_view(BlenderRNA *brna) @@ -4332,7 +4332,7 @@ static void rna_def_userdef_input(BlenderRNA *brna) prop = RNA_def_property(srna, "ndof_deadzone", PROP_FLOAT, PROP_FACTOR); RNA_def_property_range(prop, 0.0f, 1.0f); - RNA_def_property_ui_text(prop, "Deadzone", "Deadzone of the 3D Mouse"); + RNA_def_property_ui_text(prop, "Deadzone", "Threshold of initial movement needed from the device's rest position"); RNA_def_property_update(prop, 0, "rna_userdef_ndof_deadzone_update"); prop = RNA_def_property(srna, "ndof_pan_yz_swap_axis", PROP_BOOLEAN, PROP_NONE); From 7ba2356a5336f760d12c064c120fe83b3db659d2 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 29 Dec 2016 10:34:59 +0100 Subject: [PATCH 441/590] Freestyle: fix typo in console message. Patch D2270 by Anthony Edlin (@krash), thanks. --- .../freestyle/intern/blender_interface/FRS_freestyle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp index 2af4447e4dc..223bc607e21 100644 --- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp +++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp @@ -433,8 +433,8 @@ static void prepare(Render *re, SceneRenderLayer *srl) cout << "Crease angle : " << controller->getCreaseAngle() << endl; cout << "Sphere radius : " << controller->getSphereRadius() << endl; cout << "Face smoothness : " << (controller->getFaceSmoothness() ? "enabled" : "disabled") << endl; - cout << "Redges and valleys : " << (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") << - endl; + cout << "Ridges and valleys : " << + (controller->getComputeRidgesAndValleysFlag() ? "enabled" : "disabled") << endl; cout << "Suggestive contours : " << (controller->getComputeSuggestiveContoursFlag() ? "enabled" : "disabled") << endl; cout << "Suggestive contour Kr derivative epsilon : " << From 934b3f3682520727ee48eec8be01d46147f8927d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 29 Dec 2016 12:17:23 +0100 Subject: [PATCH 442/590] Fix T50334: Also select indirectly imported objects when linking/appending. Since we create a base and instantiate them, they become directly linked, so makes sense to also select them if requested. --- source/blender/blenloader/intern/readfile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index b38d28b7d91..a63b9ed7d19 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -9808,9 +9808,15 @@ static void give_base_to_objects(Main *mainvar, Scene *scene, View3D *v3d, Libra if (active_lay) { ob->lay = active_lay; } + if (flag & FILE_AUTOSELECT) { + /* Note that link_object_postprocess() already checks for FILE_AUTOSELECT flag, + * but it will miss objects from non-instanciated groups... */ + ob->flag |= SELECT; + /* do NOT make base active here! screws up GUI stuff, if you want it do it on src/ level */ + } - base->lay = ob->lay; base->object = ob; + base->lay = ob->lay; base->flag = ob->flag; CLAMP_MIN(ob->id.us, 0); From bf7d7bc323d5505b78688af2df1f66e1053f62e1 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 29 Dec 2016 12:38:20 +0100 Subject: [PATCH 443/590] Add new operator, ED_OT_undo_redo, to allow py tools to trigger that action. Patch D2430 by @raa, thanks. --- source/blender/editors/include/ED_util.h | 1 + source/blender/editors/screen/screen_ops.c | 1 + source/blender/editors/util/undo.c | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index a4afa958450..60c4b3593aa 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -60,6 +60,7 @@ void ED_undo_redo(struct bContext *C); void ED_OT_undo(struct wmOperatorType *ot); void ED_OT_undo_push(struct wmOperatorType *ot); void ED_OT_redo(struct wmOperatorType *ot); +void ED_OT_undo_redo(struct wmOperatorType *ot); void ED_OT_undo_history(struct wmOperatorType *ot); int ED_undo_operator_repeat(struct bContext *C, struct wmOperator *op); diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index c69e01422e0..a7a0a240259 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -4329,6 +4329,7 @@ void ED_operatortypes_screen(void) WM_operatortype_append(ED_OT_undo); WM_operatortype_append(ED_OT_undo_push); WM_operatortype_append(ED_OT_redo); + WM_operatortype_append(ED_OT_undo_redo); WM_operatortype_append(ED_OT_undo_history); WM_operatortype_append(ED_OT_flush_edits); diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index 4a9311416b3..fab5b7e821f 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -327,6 +327,13 @@ static int ed_redo_exec(bContext *C, wmOperator *UNUSED(op)) return ed_undo_step(C, -1, NULL); } +static int ed_undo_redo_exec(bContext *C, wmOperator *UNUSED(op)) +{ + wmOperator *last_op = WM_operator_last_redo(C); + const int ret = ED_undo_operator_repeat(C, last_op); + return ret ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + /* ********************** */ @@ -369,6 +376,17 @@ void ED_OT_redo(wmOperatorType *ot) ot->poll = ED_operator_screenactive; } +void ED_OT_undo_redo(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Undo and Redo"; + ot->description = "Undo and redo previous action"; + ot->idname = "ED_OT_undo_redo"; + + /* api callbacks */ + ot->exec = ed_undo_redo_exec; + ot->poll = ED_operator_screenactive; +} /* ui callbacks should call this rather than calling WM_operator_repeat() themselves */ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op) From acbb84b021a145ee2dde73ec5923990f42fc18fb Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sat, 31 Dec 2016 16:06:51 +0100 Subject: [PATCH 444/590] Add BLI_string_utf8 specific test. This test should ensure we correctly detect all invalid utf-8 sequences in a given string. DISCLAIMER: Do not run this with current code - you'll either laugh or cry, nearly *all* checks fail! Based on utf-8 decoder stress-test (https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt) by Markus Kuhn - 2015-08-28 - CC BY 4.0 --- tests/gtests/blenlib/BLI_string_utf8_test.cc | 304 +++++++++++++++++++ tests/gtests/blenlib/CMakeLists.txt | 1 + 2 files changed, 305 insertions(+) create mode 100644 tests/gtests/blenlib/BLI_string_utf8_test.cc diff --git a/tests/gtests/blenlib/BLI_string_utf8_test.cc b/tests/gtests/blenlib/BLI_string_utf8_test.cc new file mode 100644 index 00000000000..c0beb92eeec --- /dev/null +++ b/tests/gtests/blenlib/BLI_string_utf8_test.cc @@ -0,0 +1,304 @@ +/* Apache License, Version 2.0 */ + +#include "testing/testing.h" + +extern "C" { +#include "BLI_utildefines.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +} + +/* Note that 'common' utf-8 variants of string functions (like copy, etc.) are tested in BLI_string_test.cc + * However, tests below are specific utf-8 conformance ones, and since they eat quite their share of lines, + * they deserved their own file. */ + +/* -------------------------------------------------------------------- */ +/* stubs */ + +extern "C" { + +int mk_wcwidth(wchar_t ucs); +int mk_wcswidth(const wchar_t *pwcs, size_t n); + +int mk_wcwidth(wchar_t ucs) +{ + return 0; +} + +int mk_wcswidth(const wchar_t *pwcs, size_t n) +{ + return 0; +} + +} + +/* -------------------------------------------------------------------- */ +/* tests */ + +/* Each test is made of a 79 bytes (80 with NULL char) string to test, expected string result after + * stripping invalid utf8 bytes, and a single-byte string encoded with expected number of errors. + * + * Based on utf-8 decoder stress-test (https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt) + * by Markus Kuhn - 2015-08-28 - CC BY 4.0 + */ +const char *utf8_invalid_tests[][3] = { +// 1 Some correct UTF-8 text + {"You should see the Greek word 'kosme': \"\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5\" |", + "You should see the Greek word 'kosme': \"\xce\xba\xe1\xbd\xb9\xcf\x83\xce\xbc\xce\xb5\" |", "\x00"}, + +// 2 Boundary condition test cases +// Note that those will pass for us, those are not erronéous unicode code points +// (asside from \x00, which is only valid as string terminator). +// 2.1 First possible sequence of a certain length + {"2.1.1 1 byte (U-00000000): \"\x00\" |", + "2.1.1 1 byte (U-00000000): \"\" |", "\x01"}, + {"2.1.2 2 bytes (U-00000080): \"\xc2\x80\" |", + "2.1.2 2 bytes (U-00000080): \"\xc2\x80\" |", "\x00"}, + {"2.1.3 3 bytes (U-00000800): \"\xe0\xa0\x80\" |", + "2.1.3 3 bytes (U-00000800): \"\xe0\xa0\x80\" |", "\x00"}, + {"2.1.4 4 bytes (U-00010000): \"\xf0\x90\x80\x80\" |", + "2.1.4 4 bytes (U-00010000): \"\xf0\x90\x80\x80\" |", "\x00"}, + {"2.1.5 5 bytes (U-00200000): \"\xf8\x88\x80\x80\x80\" |", + "2.1.5 5 bytes (U-00200000): \"\xf8\x88\x80\x80\x80\" |", "\x00"}, + {"2.1.6 6 bytes (U-04000000): \"\xfc\x84\x80\x80\x80\x80\" |", + "2.1.6 6 bytes (U-04000000): \"\xfc\x84\x80\x80\x80\x80\" |", "\x00"}, +// 2.2 Last possible sequence of a certain length + {"2.2.1 1 byte (U-0000007F): \"\x7f\" |", + "2.2.1 1 byte (U-0000007F): \"\x7f\" |", "\x00"}, + {"2.2.2 2 bytes (U-000007FF): \"\xdf\xbf\" |", + "2.2.2 2 bytes (U-000007FF): \"\xdf\xbf\" |", "\x00"}, + {"2.2.3 3 bytes (U-0000FFFF): \"\xef\xbf\xbf\" |", + "2.2.3 3 bytes (U-0000FFFF): \"\" |", "\x03"}, /* matches one of 5.3 sequences... */ + {"2.2.4 4 bytes (U-001FFFFF): \"\xf7\xbf\xbf\xbf\" |", + "2.2.4 4 bytes (U-001FFFFF): \"\xf7\xbf\xbf\xbf\" |", "\x00"}, + {"2.2.5 5 bytes (U-03FFFFFF): \"\xfb\xbf\xbf\xbf\xbf\" |", + "2.2.5 5 bytes (U-03FFFFFF): \"\xfb\xbf\xbf\xbf\xbf\" |", "\x00"}, + {"2.2.6 6 bytes (U-7FFFFFFF): \"\xfd\xbf\xbf\xbf\xbf\xbf\" |", + "2.2.6 6 bytes (U-7FFFFFFF): \"\xfd\xbf\xbf\xbf\xbf\xbf\" |", "\x00"}, +// 2.3 Other boundary conditions + {"2.3.1 U-0000D7FF = ed 9f bf = \"\xed\x9f\xbf\" |", + "2.3.1 U-0000D7FF = ed 9f bf = \"\xed\x9f\xbf\" |", "\x00"}, + {"2.3.2 U-0000E000 = ee 80 80 = \"\xee\x80\x80\" |", + "2.3.2 U-0000E000 = ee 80 80 = \"\xee\x80\x80\" |", "\x00"}, + {"2.3.3 U-0000FFFD = ef bf bd = \"\xef\xbf\xbd\" |", + "2.3.3 U-0000FFFD = ef bf bd = \"\xef\xbf\xbd\" |", "\x00"}, + {"2.3.4 U-0010FFFF = f4 8f bf bf = \"\xf4\x8f\xbf\xbf\" |", + "2.3.4 U-0010FFFF = f4 8f bf bf = \"\xf4\x8f\xbf\xbf\" |", "\x00"}, + {"2.3.5 U-00110000 = f4 90 80 80 = \"\xf4\x90\x80\x80\" |", + "2.3.5 U-00110000 = f4 90 80 80 = \"\xf4\x90\x80\x80\" |", "\x00"}, + +// 3 Malformed sequences +// 3.1 Unexpected continuation bytes +// Each unexpected continuation byte should be separately signalled as a malformed sequence of its own. + {"3.1.1 First continuation byte 0x80: \"\x80\" |", + "3.1.1 First continuation byte 0x80: \"\" |", "\x01"}, + {"3.1.2 Last continuation byte 0xbf: \"\xbf\" |", + "3.1.2 Last continuation byte 0xbf: \"\" |", "\x01"}, + {"3.1.3 2 continuation bytes: \"\x80\xbf\" |", + "3.1.3 2 continuation bytes: \"\" |", "\x02"}, + {"3.1.4 3 continuation bytes: \"\x80\xbf\x80\" |", + "3.1.4 3 continuation bytes: \"\" |", "\x03"}, + {"3.1.5 4 continuation bytes: \"\x80\xbf\x80\xbf\" |", + "3.1.5 4 continuation bytes: \"\" |", "\x04"}, + {"3.1.6 5 continuation bytes: \"\x80\xbf\x80\xbf\x80\" |", + "3.1.6 5 continuation bytes: \"\" |", "\x05"}, + {"3.1.7 6 continuation bytes: \"\x80\xbf\x80\xbf\x80\xbf\" |", + "3.1.7 6 continuation bytes: \"\" |", "\x06"}, + {"3.1.8 7 continuation bytes: \"\x80\xbf\x80\xbf\x80\xbf\x80\" |", + "3.1.8 7 continuation bytes: \"\" |", "\x07"}, +// 3.1.9 Sequence of all 64 possible continuation bytes (0x80-0xbf): | + {"3.1.9 \"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f" + "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf" + "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\" |", + "3.1.9 \"\" |", "\x40"}, +// 3.2 Lonely start characters +// 3.2.1 All 32 first bytes of 2-byte sequences (0xc0-0xdf), each followed by a space character: + {"3.2.1 \"\xc0 \xc1 \xc2 \xc3 \xc4 \xc5 \xc6 \xc7 \xc8 \xc9 \xca \xcb \xcc \xcd \xce \xcf " + "\xd0 \xd1 \xd2 \xd3 \xd4 \xd5 \xd6 \xd7 \xd8 \xd9 \xda \xdb \xdc \xdd \xde \xdf \" |", + "3.2.1 \" \" |", "\x20"}, +// 3.2.2 All 16 first bytes of 3-byte sequences (0xe0-0xef), each followed by a space character: + {"3.2.2 \"\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef \" |", + "3.2.2 \" \" |", "\x10"}, +// 3.2.3 All 8 first bytes of 4-byte sequences (0xf0-0xf7), each followed by a space character: + {"3.2.3 \"\xf0 \xf1 \xf2 \xf3 \xf4 \xf5 \xf6 \xf7 \" |", + "3.2.3 \" \" |", "\x08"}, +// 3.2.4 All 4 first bytes of 5-byte sequences (0xf8-0xfb), each followed by a space character: + {"3.2.4 \"\xf8 \xf9 \xfa \xfb \" |", + "3.2.4 \" \" |", "\x04"}, +// 3.2.5 All 2 first bytes of 6-byte sequences (0xfc-0xfd), each followed by a space character: + {"3.2.4 \"\xfc \xfd \" |", + "3.2.4 \" \" |", "\x02"}, +// 3.3 Sequences with last continuation byte missing +// All bytes of an incomplete sequence should be signalled as a single malformed sequence, +// i.e., you should see only a single replacement character in each of the next 10 tests. +// (Characters as in section 2) + {"3.3.1 2-byte sequence with last byte missing (U+0000): \"\xc0\" |", + "3.3.1 2-byte sequence with last byte missing (U+0000): \"\" |", "\x01"}, + {"3.3.2 3-byte sequence with last byte missing (U+0000): \"\xe0\x80\" |", + "3.3.2 3-byte sequence with last byte missing (U+0000): \"\" |", "\x02"}, + {"3.3.3 4-byte sequence with last byte missing (U+0000): \"\xf0\x80\x80\" |", + "3.3.3 4-byte sequence with last byte missing (U+0000): \"\" |", "\x03"}, + {"3.3.4 5-byte sequence with last byte missing (U+0000): \"\xf8\x80\x80\x80\" |", + "3.3.4 5-byte sequence with last byte missing (U+0000): \"\" |", "\x04"}, + {"3.3.5 6-byte sequence with last byte missing (U+0000): \"\xfc\x80\x80\x80\x80\" |", + "3.3.5 6-byte sequence with last byte missing (U+0000): \"\" |", "\x05"}, + {"3.3.6 2-byte sequence with last byte missing (U-000007FF): \"\xdf\" |", + "3.3.6 2-byte sequence with last byte missing (U-000007FF): \"\" |", "\x01"}, + {"3.3.7 3-byte sequence with last byte missing (U-0000FFFF): \"\xef\xbf\" |", + "3.3.7 3-byte sequence with last byte missing (U-0000FFFF): \"\" |", "\x02"}, + {"3.3.8 4-byte sequence with last byte missing (U-001FFFFF): \"\xf7\xbf\xbf\" |", + "3.3.8 4-byte sequence with last byte missing (U-001FFFFF): \"\" |", "\x03"}, + {"3.3.9 5-byte sequence with last byte missing (U-03FFFFFF): \"\xfb\xbf\xbf\xbf\" |", + "3.3.9 5-byte sequence with last byte missing (U-03FFFFFF): \"\" |", "\x04"}, + {"3.3.10 6-byte sequence with last byte missing (U-7FFFFFFF): \"\xfd\xbf\xbf\xbf\xbf\" |", + "3.3.10 6-byte sequence with last byte missing (U-7FFFFFFF): \"\" |", "\x05"}, +// 3.4 Concatenation of incomplete sequences +// All the 10 sequences of 3.3 concatenated, you should see 10 malformed sequences being signalled: + {"3.4 \"\xc0\xe0\x80\xf0\x80\x80\xf8\x80\x80\x80\xfc\x80\x80\x80\x80" + "\xdf\xef\xbf\xf7\xbf\xbf\xfb\xbf\xbf\xbf\xfd\xbf\xbf\xbf\xbf\"" + " |", + "3.4 \"\" |", "\x1e"}, +// 3.5 Impossible bytes +// The following two bytes cannot appear in a correct UTF-8 string + {"3.5.1 fe = \"\xfe\" |", + "3.5.1 fe = \"\" |", "\x01"}, + {"3.5.2 ff = \"\xff\" |", + "3.5.2 ff = \"\" |", "\x01"}, + {"3.5.3 fe fe ff ff = \"\xfe\xfe\xff\xff\" |", + "3.5.3 fe fe ff ff = \"\" |", "\x04"}, + +// 4 Overlong sequences +// The following sequences are not malformed according to the letter of the Unicode 2.0 standard. +// However, they are longer then necessary and a correct UTF-8 encoder is not allowed to produce them. +// A "safe UTF-8 decoder" should reject them just like malformed sequences for two reasons: +// (1) It helps to debug applications if overlong sequences are not treated as valid representations +// of characters, because this helps to spot problems more quickly. (2) Overlong sequences provide +// alternative representations of characters, that could maliciously be used to bypass filters that check +// only for ASCII characters. For instance, a 2-byte encoded line feed (LF) would not be caught by a +// line counter that counts only 0x0a bytes, but it would still be processed as a line feed by an unsafe +// UTF-8 decoder later in the pipeline. From a security point of view, ASCII compatibility of UTF-8 +// sequences means also, that ASCII characters are *only* allowed to be represented by ASCII bytes +// in the range 0x00-0x7f. To ensure this aspect of ASCII compatibility, use only "safe UTF-8 decoders" +// that reject overlong UTF-8 sequences for which a shorter encoding exists. +// +// 4.1 Examples of an overlong ASCII character +// With a safe UTF-8 decoder, all of the following five overlong representations of the ASCII character +// slash ("/") should be rejected like a malformed UTF-8 sequence, for instance by substituting it with +// a replacement character. If you see a slash below, you do not have a safe UTF-8 decoder! + {"4.1.1 U+002F = c0 af = \"\xc0\xaf\" |", + "4.1.1 U+002F = c0 af = \"\" |", "\x02"}, + {"4.1.2 U+002F = e0 80 af = \"\xe0\x80\xaf\" |", + "4.1.2 U+002F = e0 80 af = \"\" |", "\x03"}, + {"4.1.3 U+002F = f0 80 80 af = \"\xf0\x80\x80\xaf\" |", + "4.1.3 U+002F = f0 80 80 af = \"\" |", "\x04"}, + {"4.1.4 U+002F = f8 80 80 80 af = \"\xf8\x80\x80\x80\xaf\" |", + "4.1.4 U+002F = f8 80 80 80 af = \"\" |", "\x05"}, + {"4.1.5 U+002F = fc 80 80 80 80 af = \"\xfc\x80\x80\x80\x80\xaf\" |", + "4.1.5 U+002F = fc 80 80 80 80 af = \"\" |", "\x06"}, +// 4.2 Maximum overlong sequences +// Below you see the highest Unicode value that is still resulting in an overlong sequence if represented +// with the given number of bytes. This is a boundary test for safe UTF-8 decoders. All five characters +// should be rejected like malformed UTF-8 sequences. + {"4.2.1 U-0000007F = c1 bf = \"\xc1\xbf\" |", + "4.2.1 U-0000007F = c1 bf = \"\" |", "\x02"}, + {"4.2.2 U-000007FF = e0 9f bf = \"\xe0\x9f\xbf\" |", + "4.2.2 U-000007FF = e0 9f bf = \"\" |", "\x03"}, + {"4.2.3 U-0000FFFF = f0 8f bf bf = \"\xf0\x8f\xbf\xbf\" |", + "4.2.3 U-0000FFFF = f0 8f bf bf = \"\" |", "\x04"}, + {"4.2.4 U-001FFFFF = f8 87 bf bf bf = \"\xf8\x87\xbf\xbf\xbf\" |", + "4.2.4 U-001FFFFF = f8 87 bf bf bf = \"\" |", "\x05"}, + {"4.2.5 U+0000 = fc 83 bf bf bf bf = \"\xfc\x83\xbf\xbf\xbf\xbf\" |", + "4.2.5 U+0000 = fc 83 bf bf bf bf = \"\" |", "\x06"}, +// 4.3 Overlong representation of the NUL character +// The following five sequences should also be rejected like malformed UTF-8 sequences and should not be +// treated like the ASCII NUL character. + {"4.3.1 U+0000 = c0 80 = \"\xc0\x80\" |", + "4.3.1 U+0000 = c0 80 = \"\" |", "\x02"}, + {"4.3.2 U+0000 = e0 80 80 = \"\xe0\x80\x80\" |", + "4.3.2 U+0000 = e0 80 80 = \"\" |", "\x03"}, + {"4.3.3 U+0000 = f0 80 80 80 = \"\xf0\x80\x80\x80\" |", + "4.3.3 U+0000 = f0 80 80 80 = \"\" |", "\x04"}, + {"4.3.4 U+0000 = f8 80 80 80 80 = \"\xf8\x80\x80\x80\x80\" |", + "4.3.4 U+0000 = f8 80 80 80 80 = \"\" |", "\x05"}, + {"4.3.5 U+0000 = fc 80 80 80 80 80 = \"\xfc\x80\x80\x80\x80\x80\" |", + "4.3.5 U+0000 = fc 80 80 80 80 80 = \"\" |", "\x06"}, + +// 5 Illegal code positions +// The following UTF-8 sequences should be rejected like malformed sequences, because they never represent +// valid ISO 10646 characters and a UTF-8 decoder that accepts them might introduce security problems +// comparable to overlong UTF-8 sequences. +// 5.1 Single UTF-16 surrogates + {"5.1.1 U+D800 = ed a0 80 = \"\xed\xa0\x80\" |", + "5.1.1 U+D800 = ed a0 80 = \"\" |", "\x03"}, + {"5.1.2 U+DB7F = ed ad bf = \"\xed\xad\xbf\" |", + "5.1.2 U+DB7F = ed ad bf = \"\" |", "\x03"}, + {"5.1.3 U+DB80 = ed ae 80 = \"\xed\xae\x80\" |", + "5.1.3 U+DB80 = ed ae 80 = \"\" |", "\x03"}, + {"5.1.4 U+DBFF = ed af bf = \"\xed\xaf\xbf\" |", + "5.1.4 U+DBFF = ed af bf = \"\" |", "\x03"}, + {"5.1.5 U+DC00 = ed b0 80 = \"\xed\xb0\x80\" |", + "5.1.5 U+DC00 = ed b0 80 = \"\" |", "\x03"}, + {"5.1.6 U+DF80 = ed be 80 = \"\xed\xbe\x80\" |", + "5.1.6 U+DF80 = ed be 80 = \"\" |", "\x03"}, + {"5.1.7 U+DFFF = ed bf bf = \"\xed\xbf\xbf\" |", + "5.1.7 U+DFFF = ed bf bf = \"\" |", "\x03"}, +// 5.2 Paired UTF-16 surrogates + {"5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 = \"\xed\xa0\x80\xed\xb0\x80\" |", + "5.2.1 U+D800 U+DC00 = ed a0 80 ed b0 80 = \"\" |", "\x06"}, + {"5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf = \"\xed\xa0\x80\xed\xbf\xbf\" |", + "5.2.2 U+D800 U+DFFF = ed a0 80 ed bf bf = \"\" |", "\x06"}, + {"5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 = \"\xed\xad\xbf\xed\xb0\x80\" |", + "5.2.3 U+DB7F U+DC00 = ed ad bf ed b0 80 = \"\" |", "\x06"}, + {"5.2.4 U+DB7F U+DFFF = ed ad bf ed bf bf = \"\xed\xad\xbf\xed\xbf\xbf\" |", + "5.2.4 U+DB7F U+DFFF = ed ad bf ed bf bf = \"\" |", "\x06"}, + {"5.2.5 U+DB80 U+DC00 = ed ae 80 ed b0 80 = \"\xed\xae\x80\xed\xb0\x80\" |", + "5.2.5 U+DB80 U+DC00 = ed ae 80 ed b0 80 = \"\" |", "\x06"}, + {"5.2.6 U+DB80 U+DFFF = ed ae 80 ed bf bf = \"\xed\xae\x80\xed\xbf\xbf\" |", + "5.2.6 U+DB80 U+DFFF = ed ae 80 ed bf bf = \"\" |", "\x06"}, + {"5.2.7 U+DBFF U+DC00 = ed af bf ed b0 80 = \"\xed\xaf\xbf\xed\xb0\x80\" |", + "5.2.7 U+DBFF U+DC00 = ed af bf ed b0 80 = \"\" |", "\x06"}, + {"5.2.8 U+DBFF U+DFFF = ed af bf ed bf bf = \"\xed\xaf\xbf\xed\xbf\xbf\" |", + "5.2.8 U+DBFF U+DFFF = ed af bf ed bf bf = \"\" |", "\x06"}, +// 5.3 Noncharacter code positions +// The following "noncharacters" are "reserved for internal use" by applications, and according to older versions +// of the Unicode Standard "should never be interchanged". Unicode Corrigendum #9 dropped the latter restriction. +// Nevertheless, their presence in incoming UTF-8 data can remain a potential security risk, depending +// on what use is made of these codes subsequently. Examples of such internal use: +// - Some file APIs with 16-bit characters may use the integer value -1 = U+FFFF to signal +// an end-of-file (EOF) or error condition. +// - In some UTF-16 receivers, code point U+FFFE might trigger a byte-swap operation +// (to convert between UTF-16LE and UTF-16BE). +// With such internal use of noncharacters, it may be desirable and safer to block those code points in +// UTF-8 decoders, as they should never occur legitimately in incoming UTF-8 data, and could trigger +// unsafe behaviour in subsequent processing. +// +// Particularly problematic noncharacters in 16-bit applications: + {"5.3.1 U+FFFE = ef bf be = \"\xef\xbf\xbe\" |", + "5.3.1 U+FFFE = ef bf be = \"\" |", "\x03"}, + {"5.3.2 U+FFFF = ef bf bf = \"\xef\xbf\xbf\" |", + "5.3.2 U+FFFF = ef bf bf = \"\" |", "\x03"}, + /* Fo now, we ignore those, they do not seem to be crucial anyway... */ +// 5.3.3 U+FDD0 .. U+FDEF +// 5.3.4 U+nFFFE U+nFFFF (for n = 1..10) + {NULL, NULL, NULL} +}; + +/* BLI_utf8_invalid_strip (and indirectly, BLI_utf8_invalid_byte). */ +TEST(string, Utf8InvalidBytes) +{ + for (int i = 0; utf8_invalid_tests[i][0] != NULL; i++) { + const char *tst = utf8_invalid_tests[i][0]; + const char *tst_stripped = utf8_invalid_tests[i][1]; + const int num_errors = (int)utf8_invalid_tests[i][2][0]; + + char buff[80]; + memcpy(buff, tst, sizeof(buff)); + + const int num_errors_found = BLI_utf8_invalid_strip(buff, sizeof(buff) - 1); + + printf("[%02d] -> [%02d] \"%s\" -> \"%s\"\n", num_errors, num_errors_found, tst, buff); + EXPECT_EQ(num_errors, num_errors_found); + EXPECT_STREQ(buff, tst_stripped); + } +} diff --git a/tests/gtests/blenlib/CMakeLists.txt b/tests/gtests/blenlib/CMakeLists.txt index 12112e7a481..a190d9cd8c5 100644 --- a/tests/gtests/blenlib/CMakeLists.txt +++ b/tests/gtests/blenlib/CMakeLists.txt @@ -42,6 +42,7 @@ BLENDER_TEST(BLI_math_color "bf_blenlib") BLENDER_TEST(BLI_math_geom "bf_blenlib;bf_intern_eigen") BLENDER_TEST(BLI_math_base "bf_blenlib") BLENDER_TEST(BLI_string "bf_blenlib") +BLENDER_TEST(BLI_string_utf8 "bf_blenlib") if(WIN32) BLENDER_TEST(BLI_path_util "bf_blenlib;bf_intern_utfconv;extern_wcwidth;${ZLIB_LIBRARIES}") else() From adadfaad880b2ad56fde72a38b13d42b512de81d Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sun, 1 Jan 2017 02:15:42 +0100 Subject: [PATCH 445/590] Fix (unreported) fully broken 'sanitize utf-8' helper. That code was a joke, letting some invalid utf8 bytes pass, returning wrong offset for some invalid sequences, not to mention length and pointer easily going out of sync, NULL final byte being 'forgotten' by memcpy, etc. etc. The miracle here is that we could survive using this for so long! Probably because we do not use utf-8 sanitizing enough in Blender, actually... :/ --- source/blender/blenlib/intern/string_utf8.c | 253 +++++++++++--------- 1 file changed, 135 insertions(+), 118 deletions(-) diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c index 96033615cf5..07437862c3e 100644 --- a/source/blender/blenlib/intern/string_utf8.c +++ b/source/blender/blenlib/intern/string_utf8.c @@ -47,124 +47,8 @@ // #define DEBUG_STRSIZE -/* from libswish3, originally called u8_isvalid(), - * modified to return the index of the bad character (byte index not utf). - * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */ - -/* based on the valid_utf8 routine from the PCRE library by Philip Hazel - * - * length is in bytes, since without knowing whether the string is valid - * it's hard to know how many characters there are! */ - -static const char trailingBytesForUTF8[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 -}; - -int BLI_utf8_invalid_byte(const char *str, int length) -{ - const unsigned char *p, *pend = (const unsigned char *)str + length; - unsigned char c; - int ab; - - for (p = (const unsigned char *)str; p < pend; p++) { - c = *p; - if (c < 128) - continue; - if ((c & 0xc0) != 0xc0) - goto utf8_error; - ab = trailingBytesForUTF8[c]; - if (length < ab) - goto utf8_error; - length -= ab; - - p++; - /* Check top bits in the second byte */ - if ((*p & 0xc0) != 0x80) - goto utf8_error; - - /* Check for overlong sequences for each different length */ - switch (ab) { - /* Check for xx00 000x */ - case 1: - if ((c & 0x3e) == 0) goto utf8_error; - continue; /* We know there aren't any more bytes to check */ - - /* Check for 1110 0000, xx0x xxxx */ - case 2: - if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error; - break; - - /* Check for 1111 0000, xx00 xxxx */ - case 3: - if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error; - break; - - /* Check for 1111 1000, xx00 0xxx */ - case 4: - if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error; - break; - - /* Check for leading 0xfe or 0xff, - * and then for 1111 1100, xx00 00xx */ - case 5: - if (c == 0xfe || c == 0xff || - (c == 0xfc && (*p & 0x3c) == 0)) goto utf8_error; - break; - } - - /* Check for valid bytes after the 2nd, if any; all must start 10 */ - while (--ab > 0) { - if ((*(p + 1) & 0xc0) != 0x80) goto utf8_error; - p++; /* do this after so we get usable offset - campbell */ - } - } - - return -1; - -utf8_error: - - return (int)((const char *)p - (const char *)str) - 1; -} - -int BLI_utf8_invalid_strip(char *str, int length) -{ - int bad_char, tot = 0; - - BLI_assert(str[length] == '\0'); - - while ((bad_char = BLI_utf8_invalid_byte(str, length)) != -1) { - str += bad_char; - length -= bad_char; - - if (length == 0) { - /* last character bad, strip it */ - *str = '\0'; - tot++; - break; - } - else { - /* strip, keep looking */ - memmove(str, str + 1, (size_t)length); - tot++; - } - } - - return tot; -} - - -/* compatible with BLI_strncpy, but esnure no partial utf8 chars */ - -/* array copied from glib's gutf8.c, - * note: this looks to be at odd's with 'trailingBytesForUTF8', - * need to find out what gives here! - campbell */ +/* array copied from glib's gutf8.c, */ +/* Note: last two values (0xfe and 0xff) are forbidden in utf-8, so they are considered 1 byte length too. */ static const size_t utf8_skip_data[256] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -176,6 +60,139 @@ static const size_t utf8_skip_data[256] = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1 }; +/* from libswish3, originally called u8_isvalid(), + * modified to return the index of the bad character (byte index not utf). + * http://svn.swish-e.org/libswish3/trunk/src/libswish3/utf8.c r3044 - campbell */ + +/* based on the valid_utf8 routine from the PCRE library by Philip Hazel + * + * length is in bytes, since without knowing whether the string is valid + * it's hard to know how many characters there are! */ + +/** + * Find first utf-8 invalid byte in given \a str, of \a length bytes. + * + * \return the offset of the first invalid byte. + */ +int BLI_utf8_invalid_byte(const char *str, int length) +{ + const unsigned char *p, *perr, *pend = (const unsigned char *)str + length; + unsigned char c; + int ab; + + for (p = (const unsigned char *)str; p < pend; p++, length--) { + c = *p; + perr = p; /* Erroneous char is always the first of an invalid utf8 sequence... */ + if (ELEM(c, 0xfe, 0xff, 0x00)) /* Those three values are not allowed in utf8 string. */ + goto utf8_error; + if (c < 128) + continue; + if ((c & 0xc0) != 0xc0) + goto utf8_error; + + /* Note that since we always increase p (and decrease length) by one byte in main loop, we only add/subtract + * extra utf8 bytes in code below + * (ab number, aka number of bytes remaining in the utf8 sequence after the initial one). */ + ab = utf8_skip_data[c] - 1; + if (length <= ab) { + goto utf8_error; + } + + /* Check top bits in the second byte */ + p++; + length--; + if ((*p & 0xc0) != 0x80) + goto utf8_error; + + /* Check for overlong sequences for each different length */ + switch (ab) { + case 1: + /* Check for xx00 000x */ + if ((c & 0x3e) == 0) goto utf8_error; + continue; /* We know there aren't any more bytes to check */ + + case 2: + /* Check for 1110 0000, xx0x xxxx */ + if (c == 0xe0 && (*p & 0x20) == 0) goto utf8_error; + /* Some special cases, see section 5 of utf-8 decoder stress-test by Markus Kuhn + * (https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt). */ + /* From section 5.1 (and 5.2) */ + if (c == 0xed) { + if (*p == 0xa0 && *(p + 1) == 0x80) goto utf8_error; + if (*p == 0xad && *(p + 1) == 0xbf) goto utf8_error; + if (*p == 0xae && *(p + 1) == 0x80) goto utf8_error; + if (*p == 0xaf && *(p + 1) == 0xbf) goto utf8_error; + if (*p == 0xb0 && *(p + 1) == 0x80) goto utf8_error; + if (*p == 0xbe && *(p + 1) == 0x80) goto utf8_error; + if (*p == 0xbf && *(p + 1) == 0xbf) goto utf8_error; + } + /* From section 5.3 */ + if (c == 0xef) { + if (*p == 0xbf && *(p + 1) == 0xbe) goto utf8_error; + if (*p == 0xbf && *(p + 1) == 0xbf) goto utf8_error; + } + break; + + case 3: + /* Check for 1111 0000, xx00 xxxx */ + if (c == 0xf0 && (*p & 0x30) == 0) goto utf8_error; + break; + + case 4: + /* Check for 1111 1000, xx00 0xxx */ + if (c == 0xf8 && (*p & 0x38) == 0) goto utf8_error; + break; + + case 5: + /* Check for 1111 1100, xx00 00xx */ + if (c == 0xfc && (*p & 0x3c) == 0) goto utf8_error; + break; + } + + /* Check for valid bytes after the 2nd, if any; all must start 10 */ + while (--ab > 0) { + p++; + length--; + if ((*p & 0xc0) != 0x80) goto utf8_error; + } + } + + return -1; + +utf8_error: + + return (int)((const char *)perr - (const char *)str); +} + +int BLI_utf8_invalid_strip(char *str, int length) +{ + int bad_char, tot = 0; + + BLI_assert(str[length] == '\0'); + + while ((bad_char = BLI_utf8_invalid_byte(str, length)) != -1) { + str += bad_char; + length -= (bad_char + 1); + + if (length == 0) { + /* last character bad, strip it */ + *str = '\0'; + tot++; + break; + } + else { + /* strip, keep looking */ + memmove(str, str + 1, (size_t)length + 1); /* +1 for NULL char! */ + tot++; + } + } + + return tot; +} + + +/* compatible with BLI_strncpy, but esnure no partial utf8 chars */ + #define BLI_STR_UTF8_CPY(dst, src, maxncpy) \ { \ size_t utf8_size; \ From 7924c84c44c70fefa64a872d6d767913fba636d2 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sun, 1 Jan 2017 02:27:03 +0100 Subject: [PATCH 446/590] Fix T50305: When adding new ID with same name as existing, Blender could generate invalid utf-8 ID name. `check_for_dupid()` would roughly truncate existing name, without doing any utf-8 validation. --- source/blender/blenkernel/intern/library.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 65f37d0a5b1..64535f229a9 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1431,14 +1431,18 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name) /* if new name will be too long, truncate it */ if (nr > 999 && left_len > (MAX_ID_NAME - 8)) { /* assumption: won't go beyond 9999 */ - left[MAX_ID_NAME - 8] = 0; + left[MAX_ID_NAME - 8] = '\0'; left_len = MAX_ID_NAME - 8; } else if (left_len > (MAX_ID_NAME - 7)) { - left[MAX_ID_NAME - 7] = 0; + left[MAX_ID_NAME - 7] = '\0'; left_len = MAX_ID_NAME - 7; } + /* Code above may have generated invalid utf-8 string, due to raw truncation. + * Ensure we get a valid one now! */ + left_len -= BLI_utf8_invalid_strip(left, left_len); + for (idtest = lb->first; idtest; idtest = idtest->next) { int nrtest; if ( (id != idtest) && From 911544c70cb0da53cb1df526e4c2cfa9f32a14be Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Sun, 1 Jan 2017 19:42:37 -0500 Subject: [PATCH 447/590] API: Fix double slashes in URLs --- doc/python_api/sphinx_doc_gen.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 432cceece1c..f0b5c6d832c 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1565,9 +1565,9 @@ def pyrna2sphinx(basepath): # operators def write_ops(): - API_BASEURL = "https://developer.blender.org/diffusion/B/browse/master/release/scripts/ " - API_BASEURL_ADDON = "https://developer.blender.org/diffusion/BA/" - API_BASEURL_ADDON_CONTRIB = "https://developer.blender.org/diffusion/BAC/" + API_BASEURL = "https://developer.blender.org/diffusion/B/browse/master/release/scripts " + API_BASEURL_ADDON = "https://developer.blender.org/diffusion/BA" + API_BASEURL_ADDON_CONTRIB = "https://developer.blender.org/diffusion/BAC" op_modules = {} for op in ops.values(): From 32c65faeb94e86af82e6e9e71ef1539fef82709b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Mon, 2 Jan 2017 13:55:48 +1100 Subject: [PATCH 448/590] Cleanup: redundant assignment in rect resize --- source/blender/blenlib/intern/rct.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/source/blender/blenlib/intern/rct.c b/source/blender/blenlib/intern/rct.c index 9d5a4630f68..ac73a981b45 100644 --- a/source/blender/blenlib/intern/rct.c +++ b/source/blender/blenlib/intern/rct.c @@ -420,20 +420,16 @@ void BLI_rctf_recenter(rctf *rect, float x, float y) /* change width & height around the central location */ void BLI_rcti_resize(rcti *rect, int x, int y) { - rect->xmin = rect->xmax = BLI_rcti_cent_x(rect); - rect->ymin = rect->ymax = BLI_rcti_cent_y(rect); - rect->xmin -= x / 2; - rect->ymin -= y / 2; + rect->xmin = BLI_rcti_cent_x(rect) - (x / 2); + rect->ymin = BLI_rcti_cent_y(rect) - (y / 2); rect->xmax = rect->xmin + x; rect->ymax = rect->ymin + y; } void BLI_rctf_resize(rctf *rect, float x, float y) { - rect->xmin = rect->xmax = BLI_rctf_cent_x(rect); - rect->ymin = rect->ymax = BLI_rctf_cent_y(rect); - rect->xmin -= x * 0.5f; - rect->ymin -= y * 0.5f; + rect->xmin = BLI_rctf_cent_x(rect) - (x * 0.5f); + rect->ymin = BLI_rctf_cent_y(rect) - (y * 0.5f); rect->xmax = rect->xmin + x; rect->ymax = rect->ymin + y; } From 143d9373e4baa6666415c8d01a840221baea4015 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Sun, 1 Jan 2017 23:54:24 -0500 Subject: [PATCH 449/590] API: Update to modern sphinx syntax --- doc/python_api/sphinx_doc_gen.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index f0b5c6d832c..3cb98c677c1 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1659,8 +1659,11 @@ def write_sphinx_conf_py(basepath): fw("\n") # needed for latex, pdf gen + fw("latex_elements = {\n") + fw(" 'papersize': 'a4paper',\n") + fw("}\n\n") + fw("latex_documents = [ ('contents', 'contents.tex', 'Blender Index', 'Blender Foundation', 'manual'), ]\n") - fw("latex_paper_size = 'a4paper'\n") file.close() From 42e4b0955cf2bf2bcb253f8ef00914ea021c93af Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Mon, 2 Jan 2017 00:24:40 -0500 Subject: [PATCH 450/590] API: Fix redirect in bgl page --- doc/python_api/rst/bgl.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/python_api/rst/bgl.rst b/doc/python_api/rst/bgl.rst index 99f481ce998..0b31e62963c 100644 --- a/doc/python_api/rst/bgl.rst +++ b/doc/python_api/rst/bgl.rst @@ -12,7 +12,7 @@ contents: dir(bgl). A simple search on the web can point to more than enough material to teach OpenGL programming, from books to many collections of tutorials. -Here is a comprehensive `list of books `__ (non free). +Here is a comprehensive `list of books `__ (non free). The `arcsynthesis tutorials `__ is one of the best resources to learn modern OpenGL and `g-truc `__ @@ -2067,7 +2067,7 @@ offers a set of extensive examples, including advanced features. :arg length: Returns the length of the string returned in source (excluding the null terminator). :type source: :class:`bgl.Buffer` char. :arg source: Specifies an array of characters that is used to return the source code string. - + .. function:: glShaderSource(shader, shader_string): From 13174df534e76c528e9d4f959eebbc6481ebf9f1 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Mon, 2 Jan 2017 00:33:15 -0500 Subject: [PATCH 451/590] API: Fix rst syntax --- doc/python_api/rst/info_overview.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/python_api/rst/info_overview.rst b/doc/python_api/rst/info_overview.rst index b4ae906277d..ba2e6949b81 100644 --- a/doc/python_api/rst/info_overview.rst +++ b/doc/python_api/rst/info_overview.rst @@ -19,7 +19,7 @@ This is a typical Python environment so tutorials on how to write Python scripts will work running the scripts in Blender too. Blender provides the :mod:`bpy` module to the Python interpreter. This module can be imported in a script and gives access to Blender data, classes, and functions. -Scripts that deal with Blender data will need to import this module. +Scripts that deal with Blender data will need to import this module. Here is a simple example of moving a vertex of the object named **Cube**: @@ -80,7 +80,7 @@ To run as modules: Add-ons ------- +------- Some of Blenders functionality is best kept optional, alongside scripts loaded at startup we have add-ons which are kept in their own directory ``scripts/addons``, @@ -213,7 +213,7 @@ A simple Blender/Python module can look like this: bpy.utils.register_class(SimpleOperator) def unregister(): - bpy.utils.unregister_class(SimpleOperator) + bpy.utils.unregister_class(SimpleOperator) if __name__ == "__main__": register() @@ -327,7 +327,7 @@ Say you want to store material settings for a custom engine. .. note:: *The class must be registered before being used in a property, failing to do so will raise an error:* - + ``ValueError: bpy_struct "Material" registration error: my_custom_props could not register`` @@ -429,4 +429,3 @@ Calling these operators: >>> bpy.ops.object.operator_2() Hello World OBJECT_OT_operator_2 {'FINISHED'} - From 070f22c44082c1a7405795744cec667157abbfbf Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Mon, 2 Jan 2017 11:27:36 +0100 Subject: [PATCH 452/590] Fix T49861: Interlace stereo is broken in 2.78 This is a regression introduced in rB5bd9e832 It looks more like a hack than a proper fix, but the shader logic changed a lot for blender2.8, so I would rather do the elegant fix there, while leaving master working. If we ever do a 2.78b (or 2.79) this should get in. --- source/blender/windowmanager/intern/wm_draw.c | 23 ++++++++++++++----- .../blender/windowmanager/intern/wm_stereo.c | 6 ++--- source/blender/windowmanager/wm_draw.h | 2 +- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 3825db14e93..77ffa46b990 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -430,7 +430,7 @@ static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple) return 1; } -void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) +void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha, bool is_interlace) { const int sizex = WM_window_pixels_x(win); const int sizey = WM_window_pixels_y(win); @@ -451,7 +451,13 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) halfy /= triple->y; } - GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT); + /* interlace stereo buffer bind the shader before calling wm_triple_draw_textures */ + if (is_interlace) { + glEnable(triple->target); + } + else { + GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT); + } glBindTexture(triple->target, triple->bind); @@ -472,7 +478,12 @@ void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha) glBindTexture(triple->target, 0); - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + if (is_interlace) { + glDisable(triple->target); + } + else { + GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); + } } static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple) @@ -495,7 +506,7 @@ static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *tripl wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true); glEnable(GL_BLEND); - wm_triple_draw_textures(win, triple, 1.0f - fac); + wm_triple_draw_textures(win, triple, 1.0f - fac, false); glDisable(GL_BLEND); } } @@ -516,7 +527,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win) wmSubWindowSet(win, screen->mainwin); - wm_triple_draw_textures(win, drawdata->triple, 1.0f); + wm_triple_draw_textures(win, drawdata->triple, 1.0f, false); } else { /* we run it when we start OR when we turn stereo on */ @@ -656,7 +667,7 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, StereoVi wmSubWindowSet(win, screen->mainwin); - wm_triple_draw_textures(win, drawdata->triple, 1.0f); + wm_triple_draw_textures(win, drawdata->triple, 1.0f, false); } } else { diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c index 1c1c2ad35af..46cee907991 100644 --- a/source/blender/windowmanager/intern/wm_stereo.c +++ b/source/blender/windowmanager/intern/wm_stereo.c @@ -77,7 +77,7 @@ static void wm_method_draw_stereo3d_pageflip(wmWindow *win) else //STEREO_RIGHT_ID glDrawBuffer(GL_BACK_RIGHT); - wm_triple_draw_textures(win, drawdata->triple, 1.0f); + wm_triple_draw_textures(win, drawdata->triple, 1.0f, false); } glDrawBuffer(GL_BACK); @@ -120,7 +120,7 @@ static void wm_method_draw_stereo3d_interlace(wmWindow *win) break; } - wm_triple_draw_textures(win, drawdata->triple, 1.0f); + wm_triple_draw_textures(win, drawdata->triple, 1.0f, true); GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); } interlace_prev_type = interlace_type; @@ -157,7 +157,7 @@ static void wm_method_draw_stereo3d_anaglyph(wmWindow *win) break; } - wm_triple_draw_textures(win, drawdata->triple, 1.0f); + wm_triple_draw_textures(win, drawdata->triple, 1.0f, false); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } diff --git a/source/blender/windowmanager/wm_draw.h b/source/blender/windowmanager/wm_draw.h index 0f125309045..5257bba45ff 100644 --- a/source/blender/windowmanager/wm_draw.h +++ b/source/blender/windowmanager/wm_draw.h @@ -56,7 +56,7 @@ void wm_draw_region_clear (struct wmWindow *win, struct ARegion *ar); void wm_tag_redraw_overlay (struct wmWindow *win, struct ARegion *ar); -void wm_triple_draw_textures (struct wmWindow *win, struct wmDrawTriple *triple, float alpha); +void wm_triple_draw_textures (struct wmWindow *win, struct wmDrawTriple *triple, float alpha, bool is_interlace); void wm_draw_data_free (struct wmWindow *win); From 3c7407163418fd9837951af2c252a918400435bf Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 29 Dec 2016 14:34:39 +1300 Subject: [PATCH 453/590] Fix: Passed wrong last argument to function --- source/blender/python/intern/bpy_rna_anim.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/python/intern/bpy_rna_anim.c b/source/blender/python/intern/bpy_rna_anim.c index 5fbe1ab971a..8a0130babd5 100644 --- a/source/blender/python/intern/bpy_rna_anim.c +++ b/source/blender/python/intern/bpy_rna_anim.c @@ -252,7 +252,7 @@ PyObject *pyrna_struct_keyframe_insert(BPy_StructRNA *self, PyObject *args, PyOb NlaStrip *strip = (NlaStrip *)ptr.data; FCurve *fcu = list_find_fcurve(&strip->fcurves, RNA_property_identifier(prop), index); - result = insert_keyframe_direct(&reports, ptr, prop, fcu, cfra, keytype, index); + result = insert_keyframe_direct(&reports, ptr, prop, fcu, cfra, keytype, options); } else { BKE_reportf(&reports, RPT_ERROR, "Could not resolve path (%s)", path_full); From 8f1f3a0d46df360f0715df5fa6d487f676940e89 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Mon, 2 Jan 2017 23:31:35 +1300 Subject: [PATCH 454/590] GPencil: Per-layer option to always show onion skinning Sometimes it can be useful to be able to keep onion skins visible in the OpenGL renders and/or when doing animation playback. In particular, there are two use cases where this is quite useful: 1) For creating a cheap motion-blur effect, especially when the before/after values are also animated. 2) If you've animated a shot with onion skinning enabled, the poses may end up looking odd if the ghosts are not shown (as you may have been accounting for the ghosts when making the compositions). This option can be found as the small "camera" toggle between the "Use Onion Skinning" and "Use Custom Colors" options. --- .../startup/bl_ui/properties_grease_pencil_common.py | 5 ++++- source/blender/editors/gpencil/drawgpencil.c | 12 ++++++++++-- source/blender/makesdna/DNA_gpencil_types.h | 5 ++++- source/blender/makesrna/intern/rna_gpencil.c | 7 +++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 08e07b8ed93..f8ee7c9a851 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -946,7 +946,10 @@ class GreasePencilDataPanel: row = col.row() row.prop(gpl, "use_onion_skinning") - row.prop(gpl, "use_ghost_custom_colors", text="", icon='COLOR') + sub = row.row(align=True) + icon = 'RESTRICT_RENDER_OFF' if gpl.use_ghosts_always else 'RESTRICT_RENDER_ON' + sub.prop(gpl, "use_ghosts_always", text="", icon=icon) + sub.prop(gpl, "use_ghost_custom_colors", text="", icon='COLOR') split = col.split(percentage=0.5) split.active = gpl.use_onion_skinning diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 9da3c3ee088..2fd574d6523 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -1419,8 +1419,16 @@ static void gp_draw_data_layers( #undef GP_DRAWFLAG_APPLY - /* draw 'onionskins' (frame left + right) */ - if ((gpl->flag & GP_LAYER_ONIONSKIN) && !(dflag & GP_DRAWDATA_NO_ONIONS)) { + /* Draw 'onionskins' (frame left + right) + * - It is only possible to show these if the option is enabled + * - The "no onions" flag prevents ghosts from appearing during animation playback/scrubbing + * and in renders + * - The per-layer "always show" flag however overrides the playback/render restriction, + * allowing artists to selectively turn onionskins on/off during playback + */ + if ((gpl->flag & GP_LAYER_ONIONSKIN) && + ((dflag & GP_DRAWDATA_NO_ONIONS) == 0 || (gpl->flag & GP_LAYER_GHOST_ALWAYS))) + { /* Drawing method - only immediately surrounding (gstep = 0), * or within a frame range on either side (gstep > 0) */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 23b73424da5..0364d855f69 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -244,6 +244,7 @@ typedef struct bGPDlayer { float inverse[4][4]; /* inverse matrix (only used if parented) */ char parsubstr[64]; /* String describing subobject info, MAX_ID_NAME-2 */ short partype, pad; + float tintcolor[4]; /* Color used to tint layer, alpha value is used as factor */ float opacity; /* Opacity of the layer */ } bGPDlayer; @@ -275,7 +276,9 @@ typedef enum eGPDlayer_Flag { /* Use high quality fill (instead of buggy legacy OpenGL Fill) */ GP_LAYER_HQ_FILL = (1 << 11), /* Unlock color */ - GP_LAYER_UNLOCK_COLOR = (1 << 12) + GP_LAYER_UNLOCK_COLOR = (1 << 12), + /* always show onion skins (i.e. even during renders/animation playback) */ + GP_LAYER_GHOST_ALWAYS = (1 << 13), } eGPDlayer_Flag; /* Grease-Pencil Annotations - 'DataBlock' */ diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 41a73cfc528..14da990278c 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -1242,6 +1242,13 @@ static void rna_def_gpencil_layer(BlenderRNA *brna) RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame"); RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + prop = RNA_def_property(srna, "use_ghosts_always", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_GHOST_ALWAYS); + RNA_def_property_ui_text(prop, "Always Show Ghosts", + "Ghosts are shown in renders and animation playback. Useful for special effects (e.g. motion blur)"); + RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update"); + + /* Flags */ prop = RNA_def_property(srna, "hide", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_HIDE); From 65582e75e3eadfe8c9574219fd6a8cb547355526 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 3 Jan 2017 11:42:50 +1300 Subject: [PATCH 455/590] Fix: NLA "Strip Time" setting cannot be edited This is a hacky fix for a regression introduced sometime after 2.76. The "Strip Time" setting on NLA Strips could not be edited without the value immediately jumping back to the current FCurve value (or 0.0 if no keyframes existed); even enabling autokey wouldn't let you key the property. Until we have proper overrides (that only lose their values on frame change), it's best that this setting is editable, even if it does mean it you have to manually change the frame to see the updated values. --- source/blender/makesrna/intern/rna_nla.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_nla.c b/source/blender/makesrna/intern/rna_nla.c index 078f6e237f0..e44a6420045 100644 --- a/source/blender/makesrna/intern/rna_nla.c +++ b/source/blender/makesrna/intern/rna_nla.c @@ -663,7 +663,10 @@ static void rna_def_nlastrip(BlenderRNA *brna) prop = RNA_def_property(srna, "strip_time", PROP_FLOAT, PROP_TIME); RNA_def_property_ui_text(prop, "Strip Time", "Frame of referenced Action to evaluate"); - RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, "rna_NlaStrip_update"); + /* XXX: Update temporarily disabled so that the property can be edited at all! + * Even autokey only applies after the curves have been re-evaluated, causing the unkeyed values to be lost + */ + RNA_def_property_update(prop, NC_ANIMATION | ND_NLA | NA_EDITED, /*"rna_NlaStrip_update"*/ NULL); /* TODO: should the animated_influence/time settings be animatable themselves? */ prop = RNA_def_property(srna, "use_animated_influence", PROP_BOOLEAN, PROP_NONE); From ff0221f5d848c2eb1f7e0066c9a5ae2ba1a1b217 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 3 Jan 2017 15:30:59 +0100 Subject: [PATCH 456/590] Fix implicit size_t to int conversion. Seems like it was erroring on some buildbots... --- source/blender/blenlib/intern/string_utf8.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c index 07437862c3e..0ab11810b48 100644 --- a/source/blender/blenlib/intern/string_utf8.c +++ b/source/blender/blenlib/intern/string_utf8.c @@ -93,7 +93,7 @@ int BLI_utf8_invalid_byte(const char *str, int length) /* Note that since we always increase p (and decrease length) by one byte in main loop, we only add/subtract * extra utf8 bytes in code below * (ab number, aka number of bytes remaining in the utf8 sequence after the initial one). */ - ab = utf8_skip_data[c] - 1; + ab = (int)utf8_skip_data[c] - 1; if (length <= ab) { goto utf8_error; } From 3a1b1100af29dfaf1199298ea943965f53f8e682 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Tue, 3 Jan 2017 10:34:05 -0500 Subject: [PATCH 457/590] Revert "Remove double menu entries" This reverts commit e2d7efc9503720770b9652284e25006eecbec8d4. --- release/scripts/startup/bl_ui/space_view3d.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index 55fa2c28011..5e936076d0e 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -2528,7 +2528,14 @@ class VIEW3D_MT_edit_mesh_edges(Menu): layout.operator("mesh.bevel").vertex_only = False layout.operator("mesh.edge_split") layout.operator("mesh.bridge_edge_loops") + + layout.separator() + layout.operator("transform.edge_slide") + layout.operator("mesh.loop_multi_select", text="Edge Loops").ring = False + layout.operator("mesh.loop_multi_select", text="Edge Rings").ring = True + layout.operator("mesh.loop_to_region") + layout.operator("mesh.region_to_loop") class VIEW3D_MT_edit_mesh_faces(Menu): From c0c48cdacc13742e804b19abb7b9b2049fb1bcbd Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Wed, 4 Jan 2017 10:13:28 +0100 Subject: [PATCH 458/590] Fix T50350: Quick Explode time frame problem The settings.frame_start rna was clamping frame start to frame end when frame start was bigger than frame end. The fix is simply to set frame end first --- release/scripts/startup/bl_operators/object_quick_effects.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index cdab380bb9c..ef10e279bb4 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -210,8 +210,9 @@ class QuickExplode(Operator): settings = obj.particle_systems[-1].settings settings.count = self.amount - settings.frame_start = self.frame_start + # first set frame end, to prevent frame start clamping settings.frame_end = self.frame_end - self.frame_duration + settings.frame_start = self.frame_start settings.lifetime = self.frame_duration settings.normal_factor = self.velocity settings.render_type = 'NONE' From 351a9d084f59a6d11be9148830cec86eacb85529 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 4 Jan 2017 10:25:27 +0100 Subject: [PATCH 459/590] Fix T50369: Objects can't be deleted from scene when using "link group objects to scene" Main issue here was that in old usercount system 'user_real' did simply not allow that kind of thing to work. With new pait of 'USER_EXTRA' tags, it becomes possible to handle the case correctly, by merely refining checks about indirectly use objects whene removing them from a scene. Incidently, found another related bug, 'link group objects to scene' was not incrementing objects' usercount - bad, very very bad! --- source/blender/blenkernel/intern/library_remap.c | 3 ++- source/blender/editors/object/object_add.c | 8 +++++--- source/blender/editors/space_outliner/outliner_tools.c | 10 +++++++--- source/blender/makesdna/DNA_ID.h | 1 + 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index 4f1f6d963ed..cc7de92c96a 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -883,9 +883,10 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes, * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets * fully unlinked. + * But only for local objects, not linked ones! * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO. */ - if ((GS(id->name) == ID_OB) && (id->us == 1)) { + if ((GS(id->name) == ID_OB) && (id->us == 1) && (id->lib == NULL)) { id_us_clear_real(id); } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index f42dafd094c..02b2d8492b4 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1111,7 +1111,9 @@ static void object_delete_check_glsl_update(Object *ob) /* note: now unlinks constraints as well */ void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base) { - if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) { + if (BKE_library_ID_is_indirectly_used(bmain, base->object) && + ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) + { /* We cannot delete indirectly used object... */ printf("WARNING, undeletable object '%s', should have been catched before reaching this function!", base->object->id.name + 2); @@ -1145,7 +1147,7 @@ static int object_delete_exec(bContext *C, wmOperator *op) BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); continue; } - else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) { + else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) { BKE_reportf(op->reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", base->object->id.name + 2, scene->id.name + 2); @@ -1179,7 +1181,7 @@ static int object_delete_exec(bContext *C, wmOperator *op) if (scene_iter != scene && !ID_IS_LINKED_DATABLOCK(scene_iter)) { base_other = BKE_scene_base_find(scene_iter, base->object); if (base_other) { - if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) { + if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) { BKE_reportf(op->reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", base->object->id.name + 2, scene_iter->id.name + 2); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 7739d241bd3..4eda7977622 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -411,7 +411,9 @@ static void object_delete_cb( BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); return; } - else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) { + else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && + ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) + { BKE_reportf(reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", base->object->id.name + 2, scene->id.name + 2); @@ -525,7 +527,7 @@ static void group_linkobs2scene_cb( if (!base) { /* link to scene */ base = BKE_scene_base_add(scene, gob->ob); - id_lib_extern((ID *)gob->ob); /* in case these are from a linked group */ + id_us_plus(&gob->ob->id); } base->object->flag |= SELECT; base->flag |= SELECT; @@ -842,7 +844,9 @@ static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *s BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); return base_next; } - else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) { + else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && + ID_REAL_USERS(base->object) <= 1 && ID_EXTRA_USERS(base->object) == 0) + { BKE_reportf(reports, RPT_WARNING, "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", base->object->id.name + 2, scene->id.name + 2); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index ed719b66eb3..2c6f3d2fc66 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -277,6 +277,7 @@ typedef enum ID_Type { #define ID_FAKE_USERS(id) ((((ID *)id)->flag & LIB_FAKEUSER) ? 1 : 0) #define ID_REAL_USERS(id) (((ID *)id)->us - ID_FAKE_USERS(id)) +#define ID_EXTRA_USERS(id) (((ID *)id)->tag & LIB_TAG_EXTRAUSER ? 1 : 0) #define ID_CHECK_UNDO(id) ((GS((id)->name) != ID_SCR) && (GS((id)->name) != ID_WM)) From a9163f7d222d9d4949987c9690f44bdb6e43f163 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 4 Jan 2017 14:07:38 +0100 Subject: [PATCH 460/590] Fix (IRC reported) bad handling of Text data-block user count. Reported on IRC by dfelinto, thanks. Root of the issue was that opening a new text file would create datablock with one user, when Text editor is actually a 'user one' user. This was leaving Text datablocks in inconsitent user count, and generating asserts in BKE_library area. Also changed a weird piece of code related to that extra user thing in main remapping func. --- source/blender/blenkernel/intern/library_remap.c | 3 +-- source/blender/blenkernel/intern/text.c | 1 + source/blender/editors/space_text/text_ops.c | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index cc7de92c96a..f76fc628ed0 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -522,8 +522,7 @@ void BKE_libblock_remap_locked( * been incremented for that, we have to decrease once more its user count... unless we had to skip * some 'user_one' cases. */ if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { - id_us_min(old_id); - old_id->tag &= ~LIB_TAG_EXTRAUSER_SET; + id_us_clear_real(old_id); } BLI_assert(old_id->us - skipped_refcounted >= 0); diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 1636042f479..672857e88fe 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -410,6 +410,7 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const } ta = BKE_libblock_alloc(bmain, ID_TXT, BLI_path_basename(filepath_abs)); + ta->id.us = 0; BLI_listbase_clear(&ta->lines); ta->curl = ta->sell = NULL; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 83012eac39e..df3620843ad 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -254,6 +254,7 @@ static int text_open_exec(bContext *C, wmOperator *op) } else if (st) { st->text = text; + id_us_ensure_real(&text->id); st->left = 0; st->top = 0; st->scroll_accum[0] = 0.0f; From b86042f21a8d905bea91af7c04b1265b7517f4cf Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Wed, 4 Jan 2017 19:40:34 +0300 Subject: [PATCH 461/590] Dynamic Paint: Fix random pixel flooding by absolute brush with spread. If a very low wetness absolute alpha brush is used with spread and drying effects enabled, some pixels will rapidly accumulate paint. This happens because paint drying code applies a minimal wetness threshold that causes the paint to instantly dry out. Specifically, every frame the brush adds paint at the specified absolute alpha and wetness set to the minimal threshold, spread drops it below threshold, and finally drying moves all paint to the dry layer. This drastically accelerates the rate of flow of paint into the affected pixels. Fortunately, the reason paint spread actually ends up decreasing wetness turns out to be a simple floating point precision problem, which can be easily fixed by restructuring the affected expression. --- source/blender/blenkernel/intern/dynamicpaint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 66070923153..4d9e314afc4 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -4737,7 +4737,7 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index) CLAMP(w_factor, 0.0f, 1.0f); /* mix new wetness and color */ - pPoint->wetness = (1.0f - w_factor) * pPoint->wetness + w_factor * pPoint_prev->wetness; + pPoint->wetness = pPoint->wetness + w_factor * (pPoint_prev->wetness - pPoint->wetness); pPoint->e_color[3] = mixColors(pPoint->e_color, pPoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], w_factor); } From 82b9e1e3126a5c9de36d57d2d04edd11f00de9a5 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 5 Jan 2017 00:09:42 +0100 Subject: [PATCH 462/590] Show 'Manipulate Center Points' in weight paint mode If the active object is in weight paint mode, but some armatures in pose mode, 'manipulate center points' still affects the transformation. See bd2034a749a9a9. Also removed redundant check, we basically did the same check for paint modes twice. --- .../editors/space_view3d/view3d_header.c | 23 +++++-------------- source/blender/makesrna/intern/rna_space.c | 2 +- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index 0713377d210..bf1bdf68619 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -337,13 +337,13 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) /* Draw type */ uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - if (obedit == NULL && is_paint) { - if (ob->mode & OB_MODE_ALL_PAINT) { - /* Only for Weight Paint. makes no sense in other paint modes. */ - row = uiLayoutRow(layout, true); - uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - } + row = uiLayoutRow(layout, true); + uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + if (!ob || ELEM(ob->mode, OB_MODE_OBJECT, OB_MODE_POSE, OB_MODE_WEIGHT_PAINT)) { + uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); + } + if (obedit == NULL && is_paint) { /* Manipulators aren't used in paint modes */ if (!ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_PARTICLE_EDIT)) { /* masks aren't used for sculpt and particle painting */ @@ -361,17 +361,6 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C) } } else { - row = uiLayoutRow(layout, true); - uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - - /* pose/object only however we want to allow in weight paint mode too - * so don't be totally strict and just check not-editmode for now - * XXX We never get here when we are in Weight Paint mode - */ - if (obedit == NULL) { - uiItemR(row, &v3dptr, "use_pivot_point_align", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); - } - /* Transform widget / manipulators */ row = uiLayoutRow(layout, true); uiItemR(row, &v3dptr, "show_manipulator", UI_ITEM_R_ICON_ONLY, "", ICON_NONE); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 1feae9e0bca..5e364a3adf1 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2624,7 +2624,7 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop = RNA_def_property(srna, "use_pivot_point_align", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_ALIGN); - RNA_def_property_ui_text(prop, "Align", "Manipulate center points (object and pose mode only)"); + RNA_def_property_ui_text(prop, "Align", "Manipulate center points (object, pose and weight paint mode only)"); RNA_def_property_ui_icon(prop, ICON_ALIGN, 0); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_pivot_update"); From b2159b94bcd6c4e30c47b9970601e6f2ca2a0750 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Wed, 4 Jan 2017 23:21:45 -0500 Subject: [PATCH 463/590] Remove instances of old vector icons I checked and this makes consistent with other area of blender. See https://developer.blender.org/rBf86eccb1ca2388ae203df2a59285a2f2fb9b6aa8#131061 --- .../startup/bl_ui/properties_particle.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_particle.py b/release/scripts/startup/bl_ui/properties_particle.py index 4e2666d7e40..29fc56c3fad 100644 --- a/release/scripts/startup/bl_ui/properties_particle.py +++ b/release/scripts/startup/bl_ui/properties_particle.py @@ -752,8 +752,8 @@ class PARTICLE_PT_physics(ParticleButtonsPanel, Panel): subsub.operator("particle.target_remove", icon='ZOOMOUT', text="") sub = col.row() subsub = sub.column(align=True) - subsub.operator("particle.target_move_up", icon='MOVE_UP_VEC', text="") - subsub.operator("particle.target_move_down", icon='MOVE_DOWN_VEC', text="") + subsub.operator("particle.target_move_up", icon='TRIA_UP', text="") + subsub.operator("particle.target_move_down", icon='TRIA_DOWN', text="") key = psys.active_particle_target if key: @@ -816,8 +816,8 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): #sub.operator("boid.state_add", icon='ZOOMIN', text="") #sub.operator("boid.state_del", icon='ZOOMOUT', text="") #sub = row.row(align=True) - #sub.operator("boid.state_move_up", icon='MOVE_UP_VEC', text="") - #sub.operator("boid.state_move_down", icon='MOVE_DOWN_VEC', text="") + #sub.operator("boid.state_move_up", icon='TRIA_UP', text="") + #sub.operator("boid.state_move_down", icon='TRIA_DOWN', text="") state = boids.active_boid_state @@ -840,8 +840,8 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): subsub.operator("boid.rule_del", icon='ZOOMOUT', text="") sub = col.row() subsub = sub.column(align=True) - subsub.operator("boid.rule_move_up", icon='MOVE_UP_VEC', text="") - subsub.operator("boid.rule_move_down", icon='MOVE_DOWN_VEC', text="") + subsub.operator("boid.rule_move_up", icon='TRIA_UP', text="") + subsub.operator("boid.rule_move_down", icon='TRIA_DOWN', text="") rule = state.active_boid_rule @@ -849,8 +849,8 @@ class PARTICLE_PT_boidbrain(ParticleButtonsPanel, Panel): row = layout.row() row.prop(rule, "name", text="") #somebody make nice icons for boids here please! -jahka - row.prop(rule, "use_in_air", icon='MOVE_UP_VEC', text="") - row.prop(rule, "use_on_land", icon='MOVE_DOWN_VEC', text="") + row.prop(rule, "use_in_air", icon='TRIA_UP', text="") + row.prop(rule, "use_on_land", icon='TRIA_DOWN', text="") row = layout.row() @@ -1009,8 +1009,8 @@ class PARTICLE_PT_render(ParticleButtonsPanel, Panel): subsub = sub.column(align=True) subsub.operator("particle.dupliob_copy", icon='ZOOMIN', text="") subsub.operator("particle.dupliob_remove", icon='ZOOMOUT', text="") - subsub.operator("particle.dupliob_move_up", icon='MOVE_UP_VEC', text="") - subsub.operator("particle.dupliob_move_down", icon='MOVE_DOWN_VEC', text="") + subsub.operator("particle.dupliob_move_up", icon='TRIA_UP', text="") + subsub.operator("particle.dupliob_move_down", icon='TRIA_DOWN', text="") weight = part.active_dupliweight if weight: From 62604c5c20f5649b95d6fd371db1e918e2ba2b73 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Thu, 5 Jan 2017 15:41:14 -0500 Subject: [PATCH 464/590] Make button span the full width of the properties editor --- release/scripts/startup/bl_ui/properties_game.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index 386ad254892..98b7a76e541 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -289,7 +289,6 @@ class RENDER_PT_embedded(RenderButtonsPanel, Panel): row = layout.row() row.operator("view3d.game_start", text="Start") - row.label() row = layout.row() row.label(text="Resolution:") row = layout.row(align=True) @@ -310,8 +309,6 @@ class RENDER_PT_game_player(RenderButtonsPanel, Panel): row = layout.row() row.operator("wm.blenderplayer_start", text="Start") - row.label() - row = layout.row() row.label(text="Resolution:") row = layout.row(align=True) From e713009e9b83bc7a43443712799c7a24c9dec1cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20M=C3=BCller?= Date: Fri, 6 Jan 2017 18:18:20 +0100 Subject: [PATCH 465/590] Fix: Audio plays back incorrectly after rendering to a video file D2365 --- source/blender/blenkernel/BKE_sound.h | 2 ++ source/blender/blenkernel/intern/sound.c | 18 ++++++++++++------ source/blender/editors/sound/sound_ops.c | 2 ++ source/blender/render/intern/source/pipeline.c | 2 ++ 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 28b15b2a310..a5c626e74d7 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -90,6 +90,8 @@ void BKE_sound_create_scene(struct Scene *scene); void BKE_sound_destroy_scene(struct Scene *scene); +void BKE_sound_reset_scene_specs(struct Scene *scene); + void BKE_sound_mute_scene(struct Scene *scene, int muted); void BKE_sound_update_fps(struct Scene *scene); diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index d5a395ffc4b..22288127119 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -454,6 +454,16 @@ void BKE_sound_destroy_scene(struct Scene *scene) AUD_destroySet(scene->speaker_handles); } +void BKE_sound_reset_scene_specs(struct Scene *scene) +{ + AUD_Specs specs; + + specs.channels = AUD_Device_getChannels(sound_device); + specs.rate = AUD_Device_getRate(sound_device); + + AUD_Sequence_setSpecs(scene->sound_scene, specs); +} + void BKE_sound_mute_scene(struct Scene *scene, int muted) { if (scene->sound_scene) @@ -580,15 +590,10 @@ void BKE_sound_update_sequencer(struct Main *main, bSound *sound) static void sound_start_play_scene(struct Scene *scene) { - AUD_Specs specs; - if (scene->playback_handle) AUD_Handle_stop(scene->playback_handle); - specs.channels = AUD_Device_getChannels(sound_device); - specs.rate = AUD_Device_getRate(sound_device); - - AUD_Sequence_setSpecs(scene->sound_scene, specs); + BKE_sound_reset_scene_specs(scene); if ((scene->playback_handle = AUD_Device_play(sound_device, scene->sound_scene, 1))) AUD_Handle_setLoopCount(scene->playback_handle, -1); @@ -910,6 +915,7 @@ void BKE_sound_delete_cache(struct bSound *UNUSED(sound)) {} void BKE_sound_load(struct Main *UNUSED(bmain), struct bSound *UNUSED(sound)) {} void BKE_sound_create_scene(struct Scene *UNUSED(scene)) {} void BKE_sound_destroy_scene(struct Scene *UNUSED(scene)) {} +void BKE_sound_reset_scene_specs(struct Scene *UNUSED(scene)) {} void BKE_sound_mute_scene(struct Scene *UNUSED(scene), int UNUSED(muted)) {} void *BKE_sound_scene_add_scene_sound(struct Scene *UNUSED(scene), struct Sequence *UNUSED(sequence), int UNUSED(startframe), int UNUSED(endframe), int UNUSED(frameskip)) { return NULL; } diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 432918f0e37..c2c52f58181 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -383,6 +383,8 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op) result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA + 1) * specs.rate / FPS, accuracy, filename, specs, container, codec, bitrate); + BKE_sound_reset_scene_specs(scene); + if (result) { BKE_report(op->reports, RPT_ERROR, result); return OPERATOR_CANCELLED; diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 9f1ae4a96e0..aff0d2cf15f 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -74,6 +74,7 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_sequencer.h" +#include "BKE_sound.h" #include "BKE_writeavi.h" /* <------ should be replaced once with generic movie module */ #include "BKE_object.h" @@ -3791,6 +3792,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri re->flag &= ~R_ANIMATION; BLI_callback_exec(re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE); + BKE_sound_reset_scene_specs(scene); /* UGLY WARNING */ G.is_rendering = false; From 9c756162aed5354ff3d4fd7ba6c84253b39d14fa Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 9 Jan 2017 10:43:23 +0100 Subject: [PATCH 466/590] Fix T50385: Deadlock in BKE_libblock_remap_locked. Am pretty sure node update should not touch to Main database like that, but for now let's allow it, I guess the hack is needed for things like Sverchok. ;) --- source/blender/blenkernel/intern/library_remap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c index f76fc628ed0..d7d566a9ec0 100644 --- a/source/blender/blenkernel/intern/library_remap.c +++ b/source/blender/blenkernel/intern/library_remap.c @@ -562,8 +562,14 @@ void BKE_libblock_remap_locked( default: break; } + /* Node trees may virtually use any kind of data-block... */ + /* XXX Yuck!!!! nodetree update can do pretty much any thing when talking about py nodes, + * including creating new data-blocks (see T50385), so we need to unlock main here. :( + * Why can't we have re-entrent locks? */ + BKE_main_unlock(bmain); libblock_remap_data_postprocess_nodetree_update(bmain, new_id); + BKE_main_lock(bmain); /* Full rebuild of DAG! */ DAG_relations_tag_update(bmain); From 378afc98302bec1ab36011176ea5665e825f7b04 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Mon, 9 Jan 2017 12:24:34 +0100 Subject: [PATCH 467/590] Fix for T50373: lattices should not be able to get subsurf modifiers Reviewers: mont29 Reviewed By: mont29 Subscribers: sergey Differential Revision: https://developer.blender.org/D2449 --- source/blender/blenkernel/intern/object.c | 4 ++++ source/blender/editors/object/object_modifier.c | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index c6666ec5ced..e93bfcdda83 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -246,6 +246,10 @@ bool BKE_object_support_modifier_type_check(Object *ob, int modifier_type) mti = modifierType_getInfo(modifier_type); + /* only geometry objects should be able to get modifiers [#25291] */ + if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + return false; + } if (ob->type == OB_LATTICE && (mti->flags & eModifierTypeFlag_AcceptsLattice) == 0) { return false; diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index b44ddf925a8..619313e9c3f 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -98,12 +98,12 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc ModifierData *md = NULL, *new_md = NULL; const ModifierTypeInfo *mti = modifierType_getInfo(type); - /* only geometry objects should be able to get modifiers [#25291] */ - if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) { + // check compatibility of modifier [T25291, T50373] + if (!BKE_object_support_modifier_type_check(ob, type)) { BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); return NULL; } - + if (mti->flags & eModifierTypeFlag_Single) { if (modifiers_findByType(ob, type)) { BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); From 1b75cd5aa80b38a8bee6693cf2dfc9a3e8e62abf Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 9 Jan 2017 12:35:08 +0100 Subject: [PATCH 468/590] Cleanup: Don't use C++ comments style in C code --- source/blender/editors/object/object_modifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 619313e9c3f..06f495fb9f1 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -98,7 +98,7 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc ModifierData *md = NULL, *new_md = NULL; const ModifierTypeInfo *mti = modifierType_getInfo(type); - // check compatibility of modifier [T25291, T50373] + /* Check compatibility of modifier [T25291, T50373]. */ if (!BKE_object_support_modifier_type_check(ob, type)) { BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); return NULL; From bb88c7af8157fa3292398cf8b31d74b59f46373a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 9 Jan 2017 13:11:42 +0100 Subject: [PATCH 469/590] Cleanup: Indentation --- intern/smoke/intern/VEC3.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/intern/smoke/intern/VEC3.h b/intern/smoke/intern/VEC3.h index dafe5e52dbd..74f6e52a737 100644 --- a/intern/smoke/intern/VEC3.h +++ b/intern/smoke/intern/VEC3.h @@ -943,14 +943,14 @@ operator<<( std::ostream& os, const BasicVector::Vector3Dim& i ) { #if 0 char buf[256]; -#if _WIN32 - sprintf(buf,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]); -#else - snprintf(buf,256,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]); -#endif +# if _WIN32 + sprintf(buf,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]); +# else + snprintf(buf,256,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]); +# endif os << std::string(buf); #endif - return os; + return os; } From d5cf90f59f7f416663963bca0d765f4a5c615a9b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 9 Jan 2017 13:12:43 +0100 Subject: [PATCH 470/590] Cleanup: Strict CLang warning in Smoke module --- intern/smoke/intern/VEC3.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/intern/smoke/intern/VEC3.h b/intern/smoke/intern/VEC3.h index 74f6e52a737..ffc7da88138 100644 --- a/intern/smoke/intern/VEC3.h +++ b/intern/smoke/intern/VEC3.h @@ -949,6 +949,8 @@ operator<<( std::ostream& os, const BasicVector::Vector3Dim& i ) snprintf(buf,256,globVecFormatStr, (double)i[0],(double)i[1],(double)i[2]); # endif os << std::string(buf); +#else + (void)i; /* Ignored. */ #endif return os; } From da026249abbe058321f815a9ac39c92761e405ea Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 10 Jan 2017 16:19:10 +0100 Subject: [PATCH 471/590] UI Layout: fix some cases mixing fixed and expandable sizes When layout has only small buttons (buttons with icon and without label) its size should be fixed. Code was modified to be able to add a new UI_ITEM_MIN flag which indicates that the layout has only small fixed-width buttons. Patch by @raa, with minor style edits by @mont29. Reviewers: Severin, mont29 Reviewed By: mont29 Tags: #bf_blender, #user_interface Differential Revision: https://developer.blender.org/D2423 --- .../editors/interface/interface_layout.c | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 940e982d326..b02a909d009 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -125,6 +125,11 @@ typedef struct uiItem { int flag; } uiItem; +enum { + UI_ITEM_FIXED = 1 << 0, + UI_ITEM_MIN = 1 << 1, +}; + typedef struct uiButtonItem { uiItem item; uiBut *but; @@ -232,6 +237,7 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X); if (variable) { + layout->item.flag |= UI_ITEM_MIN; const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; /* it may seem odd that the icon only adds (UI_UNIT_X / 4) * but taking margins into account its fine */ @@ -2060,6 +2066,7 @@ static void ui_litem_estimate_row(uiLayout *litem) { uiItem *item; int itemw, itemh; + bool min_size_flag = true; litem->w = 0; litem->h = 0; @@ -2067,12 +2074,26 @@ static void ui_litem_estimate_row(uiLayout *litem) for (item = litem->items.first; item; item = item->next) { ui_item_size(item, &itemw, &itemh); + if (item->type == ITEM_BUTTON) { + const uiBut *but = ((uiButtonItem *)item)->but; + const bool icon_only = (but->flag & UI_HAS_ICON) && (but->str == NULL || but->str[0] == '\0'); + + min_size_flag = min_size_flag && icon_only; + } + else { + min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN); + } + litem->w += itemw; litem->h = MAX2(itemh, litem->h); if (item->next) litem->w += litem->space; } + + if (min_size_flag) { + litem->item.flag |= UI_ITEM_MIN; + } } static int ui_litem_min_width(int itemw) @@ -2113,7 +2134,7 @@ static void ui_litem_layout_row(uiLayout *litem) newtotw = totw; for (item = litem->items.first; item; item = item->next) { - if (item->flag) + if (item->flag & UI_ITEM_FIXED) continue; ui_item_size(item, &itemw, &itemh); @@ -2126,16 +2147,19 @@ static void ui_litem_layout_row(uiLayout *litem) x += neww; - if ((neww < minw || itemw == minw) && w != 0) { + if ((neww < minw || itemw == minw || item->flag & UI_ITEM_MIN) && w != 0) { /* fixed size */ - item->flag = 1; + item->flag |= UI_ITEM_FIXED; + if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) { + minw = itemw; + } fixedw += minw; flag = 1; newtotw -= itemw; } else { /* keep free size */ - item->flag = 0; + item->flag &= ~UI_ITEM_FIXED; freew += itemw; } } @@ -2152,8 +2176,11 @@ static void ui_litem_layout_row(uiLayout *litem) ui_item_size(item, &itemw, &itemh); minw = ui_litem_min_width(itemw); - if (item->flag) { + if (item->flag & UI_ITEM_FIXED) { /* fixed minimum size items */ + if (item->type != ITEM_BUTTON && item->flag & UI_ITEM_MIN) { + minw = itemw; + } itemw = ui_item_fit(minw, fixedx, fixedw, min_ii(w, fixedw), !item->next, litem->alignment); fixedx += itemw; } @@ -2193,6 +2220,7 @@ static void ui_litem_estimate_column(uiLayout *litem) { uiItem *item; int itemw, itemh; + bool min_size_flag = true; litem->w = 0; litem->h = 0; @@ -2200,12 +2228,26 @@ static void ui_litem_estimate_column(uiLayout *litem) for (item = litem->items.first; item; item = item->next) { ui_item_size(item, &itemw, &itemh); + if (item->type == ITEM_BUTTON) { + const uiBut *but = ((uiButtonItem *)item)->but; + const bool icon_only = (but->flag & UI_HAS_ICON) && (but->str == NULL || but->str[0] == '\0'); + + min_size_flag = min_size_flag && icon_only; + } + else { + min_size_flag = min_size_flag && (item->flag & UI_ITEM_MIN); + } + litem->w = MAX2(litem->w, itemw); litem->h += itemh; if (item->next) litem->h += litem->space; } + + if (min_size_flag) { + litem->item.flag |= UI_ITEM_MIN; + } } static void ui_litem_layout_column(uiLayout *litem) From 1dbaf0dbcca2c2756b2aa9f849334a5462739ddc Mon Sep 17 00:00:00 2001 From: Luca Rood Date: Tue, 10 Jan 2017 17:46:31 -0200 Subject: [PATCH 472/590] Add mid_v3_v3_array function and remove redundant functions Other than implementing a `mid_v3_v3_array` function, this removes `cent_tri_v3` and `cent_quad_v3` in favor of `mid_v3_v3v3v3` and `mid_v3_v3v3v3v3` respectively. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D2459 --- .../blender/blenkernel/intern/mesh_evaluate.c | 24 +++++++++---------- source/blender/blenlib/BLI_math_geom.h | 3 --- source/blender/blenlib/BLI_math_vector.h | 1 + source/blender/blenlib/intern/math_geom.c | 14 ----------- source/blender/blenlib/intern/math_vector.c | 10 ++++++++ source/blender/bmesh/intern/bmesh_interp.c | 2 +- .../blender/render/intern/source/occlusion.c | 4 ++-- 7 files changed, 26 insertions(+), 32 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index a3fe73e4b11..f9eba118383 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -1909,19 +1909,19 @@ void BKE_mesh_calc_poly_center( const MVert *mvarray, float r_cent[3]) { if (mpoly->totloop == 3) { - cent_tri_v3(r_cent, - mvarray[loopstart[0].v].co, - mvarray[loopstart[1].v].co, - mvarray[loopstart[2].v].co - ); + mid_v3_v3v3v3(r_cent, + mvarray[loopstart[0].v].co, + mvarray[loopstart[1].v].co, + mvarray[loopstart[2].v].co + ); } else if (mpoly->totloop == 4) { - cent_quad_v3(r_cent, - mvarray[loopstart[0].v].co, - mvarray[loopstart[1].v].co, - mvarray[loopstart[2].v].co, - mvarray[loopstart[3].v].co - ); + mid_v3_v3v3v3v3(r_cent, + mvarray[loopstart[0].v].co, + mvarray[loopstart[1].v].co, + mvarray[loopstart[2].v].co, + mvarray[loopstart[3].v].co + ); } else { mesh_calc_ngon_center(mpoly, loopstart, mvarray, r_cent); @@ -1978,7 +1978,7 @@ static float mesh_calc_poly_planar_area_centroid( tri_area = area_tri_signed_v3(v1, v2, v3, normal); total_area += tri_area; - cent_tri_v3(tri_cent, v1, v2, v3); + mid_v3_v3v3v3(tri_cent, v1, v2, v3); madd_v3_v3fl(r_cent, tri_cent, tri_area); copy_v3_v3(v2, v3); diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 514b0300274..b5007b29f4c 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -44,9 +44,6 @@ extern "C" { /********************************** Polygons *********************************/ -void cent_tri_v3(float r[3], const float a[3], const float b[3], const float c[3]); -void cent_quad_v3(float r[3], const float a[3], const float b[3], const float c[3], const float d[3]); - float normal_tri_v3(float r[3], const float a[3], const float b[3], const float c[3]); float normal_quad_v3(float r[3], const float a[3], const float b[3], const float c[3], const float d[3]); float normal_poly_v3(float r[3], const float verts[][3], unsigned int nr); diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index d15fe1a95dc..8e0884ba347 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -234,6 +234,7 @@ void mid_v3_v3v3(float r[3], const float a[3], const float b[3]); void mid_v2_v2v2(float r[2], const float a[2], const float b[2]); void mid_v3_v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3]); void mid_v3_v3v3v3v3(float v[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]); +void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr); void mid_v3_v3v3_angle_weighted(float r[3], const float a[3], const float b[3]); void mid_v3_angle_weighted(float r[3]); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 46d963ee268..76dac5487f2 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -37,20 +37,6 @@ /********************************** Polygons *********************************/ -void cent_tri_v3(float cent[3], const float v1[3], const float v2[3], const float v3[3]) -{ - cent[0] = (v1[0] + v2[0] + v3[0]) / 3.0f; - cent[1] = (v1[1] + v2[1] + v3[1]) / 3.0f; - cent[2] = (v1[2] + v2[2] + v3[2]) / 3.0f; -} - -void cent_quad_v3(float cent[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3]) -{ - cent[0] = 0.25f * (v1[0] + v2[0] + v3[0] + v4[0]); - cent[1] = 0.25f * (v1[1] + v2[1] + v3[1] + v4[1]); - cent[2] = 0.25f * (v1[2] + v2[2] + v3[2] + v4[2]); -} - void cross_tri_v3(float n[3], const float v1[3], const float v2[3], const float v3[3]) { float n1[3], n2[3]; diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 95d5c9fde87..dfecc3b556a 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -280,6 +280,16 @@ void mid_v3_v3v3v3v3(float v[3], const float v1[3], const float v2[3], const flo v[2] = (v1[2] + v2[2] + v3[2] + v4[2]) / 4.0f; } +void mid_v3_v3_array(float r[3], const float (*vec_arr)[3], const unsigned int nbr) +{ + const float factor = 1.0f / (float)nbr; + zero_v3(r); + + for (unsigned int i = 0; i < nbr; i++) { + madd_v3_v3fl(r, vec_arr[i], factor); + } +} + /** * Specialized function for calculating normals. * fastpath for: diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index f51013c3f1c..20ee31251e8 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -339,7 +339,7 @@ static bool mdisp_in_mdispquad( compute_mdisp_quad(l_dst, l_dst_f_center, v1, v2, v3, v4, e1, e2); /* expand quad a bit */ - cent_quad_v3(c, v1, v2, v3, v4); + mid_v3_v3v3v3v3(c, v1, v2, v3, v4); sub_v3_v3(v1, c); sub_v3_v3(v2, c); sub_v3_v3(v3, c); sub_v3_v3(v4, c); diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index b3d31e3b93a..ddcd2e84520 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -329,7 +329,7 @@ static void occ_face(const OccFace *face, float co[3], float normal[3], float *a if (vlr->v4) mid_v3_v3v3(co, vlr->v1->co, vlr->v3->co); else - cent_tri_v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co); + mid_v3_v3v3v3(co, vlr->v1->co, vlr->v2->co, vlr->v3->co); if (obi->flag & R_TRANSFORMED) mul_m4_v3(obi->mat, co); @@ -1245,7 +1245,7 @@ static void *exec_strandsurface_sample(void *data) normal_quad_v3(n, co1, co2, co3, co4); } else { - cent_tri_v3(co, co1, co2, co3); + mid_v3_v3v3v3(co, co1, co2, co3); normal_tri_v3(n, co1, co2, co3); } negate_v3(n); From e041bf757944efee55a4a8bdc599c12bb8829863 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 00:08:16 +0100 Subject: [PATCH 473/590] Cleanup: Use more meaningful constants other than 0 --- .../blender/blenkernel/intern/writeffmpeg.c | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index b0ab6f707fa..9994d479ce7 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -444,7 +444,7 @@ static void set_ffmpeg_property_option(AVCodecContext *c, IDProperty *prop, AVDi param = strchr(name, ':'); if (param) { - *param++ = 0; + *param++ = '\0'; } switch (prop->type) { @@ -1114,7 +1114,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData BLI_make_existing_file(string); - autosplit[0] = 0; + autosplit[0] = '\0'; if ((rd->ffcodecdata.flags & FFMPEG_AUTOSPLIT_OUTPUT) != 0) { if (context) { @@ -1137,7 +1137,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context, char *string, RenderData strcat(string, *exts); } else { - *(string + strlen(string) - strlen(*fe)) = 0; + *(string + strlen(string) - strlen(*fe)) = '\0'; strcat(string, autosplit); strcat(string, *fe); } @@ -1267,7 +1267,7 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit) if (is_autosplit == false) { if (context->audio_mixdown_device) { AUD_Device_free(context->audio_mixdown_device); - context->audio_mixdown_device = 0; + context->audio_mixdown_device = NULL; } } #endif @@ -1283,50 +1283,50 @@ static void end_ffmpeg_impl(FFMpegContext *context, int is_autosplit) /* Close the video codec */ - if (context->video_stream && context->video_stream->codec) { + if (context->video_stream != NULL && context->video_stream->codec != NULL) { avcodec_close(context->video_stream->codec); PRINT("zero video stream %p\n", context->video_stream); - context->video_stream = 0; + context->video_stream = NULL; } - if (context->audio_stream && context->audio_stream->codec) { + if (context->audio_stream != NULL && context->audio_stream->codec != NULL) { avcodec_close(context->audio_stream->codec); - context->audio_stream = 0; + context->audio_stream = NULL; } /* free the temp buffer */ - if (context->current_frame) { + if (context->current_frame != NULL) { delete_picture(context->current_frame); - context->current_frame = 0; + context->current_frame = NULL; } - if (context->outfile && context->outfile->oformat) { + if (context->outfile != NULL && context->outfile->oformat) { if (!(context->outfile->oformat->flags & AVFMT_NOFILE)) { avio_close(context->outfile->pb); } } - if (context->outfile) { + if (context->outfile != NULL) { avformat_free_context(context->outfile); - context->outfile = 0; + context->outfile = NULL; } - if (context->audio_input_buffer) { + if (context->audio_input_buffer != NULL) { av_free(context->audio_input_buffer); - context->audio_input_buffer = 0; + context->audio_input_buffer = NULL; } #ifndef FFMPEG_HAVE_ENCODE_AUDIO2 - if (context->audio_output_buffer) { + if (context->audio_output_buffer != NULL) { av_free(context->audio_output_buffer); - context->audio_output_buffer = 0; + context->audio_output_buffer = NULL; } #endif - if (context->audio_deinterleave_buffer) { + if (context->audio_deinterleave_buffer != NULL) { av_free(context->audio_deinterleave_buffer); - context->audio_deinterleave_buffer = 0; + context->audio_deinterleave_buffer = NULL; } - if (context->img_convert_ctx) { + if (context->img_convert_ctx != NULL) { sws_freeContext(context->img_convert_ctx); - context->img_convert_ctx = 0; + context->img_convert_ctx = NULL; } } @@ -1425,8 +1425,8 @@ static IDProperty *BKE_ffmpeg_property_add(RenderData *rd, const char *type, con int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char *str) { AVCodecContext c; - const AVOption *o = 0; - const AVOption *p = 0; + const AVOption *o = NULL; + const AVOption *p = NULL; char name_[128]; char *name; char *param; @@ -1445,7 +1445,7 @@ int BKE_ffmpeg_property_add_string(RenderData *rd, const char *type, const char param = strchr(name, ' '); } if (param) { - *param++ = 0; + *param++ = '\0'; while (*param == ' ') param++; } From e068d09a4bc8cee957e3cfee90fb852180b6be5f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 14:34:56 +0100 Subject: [PATCH 474/590] Cycles: Improve logging of cases when motion blur is disabled Next logical step is to expose this somehow to the interface. --- intern/cycles/blender/blender_mesh.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index fab03c7659b..ab909c4527f 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -1157,10 +1157,12 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, { /* no motion, remove attributes again */ if(b_mesh.vertices.length() != numverts) { - VLOG(1) << "Topology differs, disabling motion blur."; + VLOG(1) << "Topology differs, disabling motion blur for object " + << b_ob.name(); } else { - VLOG(1) << "No actual deformation motion for object " << b_ob.name(); + VLOG(1) << "No actual deformation motion for object " + << b_ob.name(); } mesh->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); if(attr_mN) From 7bbb2292dc3ed997abd98ea17e2d66df6cd83ddc Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 15:16:22 +0100 Subject: [PATCH 475/590] Cycles: Cleanup, whitespace around operator --- intern/cycles/blender/blender_mesh.cpp | 4 ++-- intern/cycles/blender/blender_session.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index ab909c4527f..c3676ea5de6 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -597,8 +597,8 @@ static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh& b_mesh, const vector& used_shaders, - bool subdivision=false, - bool subdivide_uvs=true) + bool subdivision = false, + bool subdivide_uvs = true) { /* count vertices and faces */ int numverts = b_mesh.vertices.length(); diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 71c1eefe65f..21166b2f155 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -580,7 +580,7 @@ static void populate_bake_data(BakeData *data, const BL::BakePixel bp = pixel_array; int i; - for(i=0; i < num_pixels; i++) { + for(i = 0; i < num_pixels; i++) { if(bp.object_id() == object_id) { data->set(i, bp.primitive_id(), bp.uv(), bp.du_dx(), bp.du_dy(), bp.dv_dx(), bp.dv_dy()); } else { From 8576efc98a8f84eded32c406e83de3fe5f17f3e6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 15:59:32 +0100 Subject: [PATCH 476/590] RNA: Expose autosmooth face splitting This way render engine can request mesh to be auto-split and not worry about implementing this functionality on it's own. Please note that this split is to be performed prior to tessellation. --- source/blender/makesrna/intern/rna_mesh_api.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 4a078ef9182..cd48bc1a3df 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -240,6 +240,9 @@ void RNA_api_mesh(StructRNA *srna) func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split"); RNA_def_function_ui_description(func, "Free split vertex normals"); + func = RNA_def_function(srna, "split_faces", "BKE_mesh_split_faces"); + RNA_def_function_ui_description(func, "Spli faces based on the edge angle"); + func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, From 2b66a17e50ce1971977630b3493fb198dcd9cfef Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 16:04:39 +0100 Subject: [PATCH 477/590] Copy autosmooth mesh settings BKE_mesh_new_from_object This way render engine can first apply all modifiers on the new mesh and then optionally perform autosmooth face splitting on it. --- source/blender/blenkernel/intern/mesh.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index d21f43ac484..af02e02b017 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2346,6 +2346,11 @@ Mesh *BKE_mesh_new_from_object( tmpmesh = BKE_mesh_add(bmain, "Mesh"); DM_to_mesh(dm, tmpmesh, ob, mask, true); + + /* Copy autosmooth settings from original mesh. */ + Mesh *me = (Mesh *)ob->data; + tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH); + tmpmesh->smoothresh = me->smoothresh; } /* BKE_mesh_add/copy gives us a user count we don't need */ From 38b01415546f2530ced77e91ac2d57b37b576b07 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 16:23:54 +0100 Subject: [PATCH 478/590] Cycles: Pass explicit subdivision type to object_to_mesh This allows us to do some extra logic checks there based on particular subdivision type. Additionally avoids implicit cast of enum to bool. --- intern/cycles/blender/blender_mesh.cpp | 16 ++++++++++++++-- intern/cycles/blender/blender_util.h | 8 ++++---- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index c3676ea5de6..a83e756de91 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -961,7 +961,13 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, mesh->subdivision_type = object_subdivision_type(b_ob, preview, experimental); - BL::Mesh b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, need_undeformed, mesh->subdivision_type); + BL::Mesh b_mesh = object_to_mesh(b_data, + b_ob, + b_scene, + true, + !preview, + need_undeformed, + mesh->subdivision_type); if(b_mesh) { if(render_layer.use_surfaces && !hide_tris) { @@ -1086,7 +1092,13 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { /* get derived mesh */ - b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false, false); + b_mesh = object_to_mesh(b_data, + b_ob, + b_scene, + true, + !preview, + false, + Mesh::SUBDIVISION_NONE); } if(!b_mesh) { diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index f17a61f0ac8..92db5fdfd45 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -48,12 +48,12 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, bool apply_modifiers, bool render, bool calc_undeformed, - bool subdivision) + Mesh::SubdivisionType subdivision_type) { bool subsurf_mod_show_render; bool subsurf_mod_show_viewport; - if(subdivision) { + if(subdivision_type != Mesh::SUBDIVISION_NONE) { BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; subsurf_mod_show_render = subsurf_mod.show_render(); @@ -65,7 +65,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, BL::Mesh me = data.meshes.new_from_object(scene, object, apply_modifiers, (render)? 2: 1, false, calc_undeformed); - if(subdivision) { + if(subdivision_type != Mesh::SUBDIVISION_NONE) { BL::Modifier subsurf_mod = object.modifiers[object.modifiers.length()-1]; subsurf_mod.show_render(subsurf_mod_show_render); @@ -76,7 +76,7 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, if(me.use_auto_smooth()) { me.calc_normals_split(); } - if(!subdivision) { + if(subdivision_type == Mesh::SUBDIVISION_NONE) { me.calc_tessface(true); } } From 394fa07d41bf403920806522e6ca09a9531bca29 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 11 Jan 2017 16:32:57 +0100 Subject: [PATCH 479/590] Cycles: Fix wrong motion blur when combining deformation motion blur with autosplit The issue was that we used to compare number of vertices for mesh after the auto smooth was applied (at the center of the shutter time) with number of vertices prior to the auto smooth applied. This caused false-positive consideration of a mesh as changing topology. Now we do autosplit as early as possible and do it from blender side, so Cycles does not need to re-implement splitting on it's side. --- intern/cycles/blender/blender_mesh.cpp | 42 +++----------------------- intern/cycles/blender/blender_util.h | 7 ++++- 2 files changed, 10 insertions(+), 39 deletions(-) diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index a83e756de91..66893d4d668 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -671,28 +671,10 @@ static void create_mesh(Scene *scene, int shader = clamp(f->material_index(), 0, used_shaders.size()-1); bool smooth = f->use_smooth() || use_loop_normals; - /* split vertices if normal is different + /* Create triangles. * - * note all vertex attributes must have been set here so we can split - * and copy attributes in split_vertex without remapping later */ - if(use_loop_normals) { - BL::Array loop_normals = f->split_normals(); - - for(int i = 0; i < n; i++) { - float3 loop_N = make_float3(loop_normals[i * 3], loop_normals[i * 3 + 1], loop_normals[i * 3 + 2]); - - if(N[vi[i]] != loop_N) { - int new_vi = mesh->split_vertex(vi[i]); - - /* set new normal and vertex index */ - N = attr_N->data_float3(); - N[new_vi] = loop_N; - vi[i] = new_vi; - } - } - } - - /* create triangles */ + * NOTE: Autosmooth is already taken care about. + */ if(n == 4) { if(is_zero(cross(mesh->verts[vi[1]] - mesh->verts[vi[0]], mesh->verts[vi[2]] - mesh->verts[vi[0]])) || is_zero(cross(mesh->verts[vi[2]] - mesh->verts[vi[0]], mesh->verts[vi[3]] - mesh->verts[vi[0]]))) @@ -724,24 +706,8 @@ static void create_mesh(Scene *scene, vi.reserve(n); for(int i = 0; i < n; i++) { + /* NOTE: Autosmooth is already taken care about. */ vi[i] = b_mesh.loops[p->loop_start() + i].vertex_index(); - - /* split vertices if normal is different - * - * note all vertex attributes must have been set here so we can split - * and copy attributes in split_vertex without remapping later */ - if(use_loop_normals) { - float3 loop_N = get_float3(b_mesh.loops[p->loop_start() + i].normal()); - - if(N[vi[i]] != loop_N) { - int new_vi = mesh->split_vertex(vi[i]); - - /* set new normal and vertex index */ - N = attr_N->data_float3(); - N[new_vi] = loop_N; - vi[i] = new_vi; - } - } } /* create subd faces */ diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 92db5fdfd45..b67834cdea3 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -74,7 +74,12 @@ static inline BL::Mesh object_to_mesh(BL::BlendData& data, if((bool)me) { if(me.use_auto_smooth()) { - me.calc_normals_split(); + if(subdivision_type == Mesh::SUBDIVISION_CATMULL_CLARK) { + me.calc_normals_split(); + } + else { + me.split_faces(); + } } if(subdivision_type == Mesh::SUBDIVISION_NONE) { me.calc_tessface(true); From 0507b3e4c41ff058c00b7a45d937d82939b4e0d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Foucault?= Date: Wed, 11 Jan 2017 18:47:06 +0100 Subject: [PATCH 480/590] Viewport SSAO: Fix normals not normalized --- source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl index 054a2f795ee..50c8e255162 100644 --- a/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_fx_ssao_frag.glsl @@ -27,8 +27,7 @@ vec3 calculate_view_space_normal(in vec3 viewposition) { vec3 normal = cross(normalize(dFdx(viewposition)), ssao_params.w * normalize(dFdy(viewposition))); - normalize(normal); - return normal; + return normalize(normal); } float calculate_ssao_factor(float depth) From c910beaa2133989150cdafa556ca11ddc9fffc92 Mon Sep 17 00:00:00 2001 From: Luca Rood Date: Wed, 11 Jan 2017 15:15:54 -0200 Subject: [PATCH 481/590] Split interp_weights_face_v3 into specific functions for tris and quads This splits `interp_weights_face_v3` into `interp_weights_tri_v3` and `interp_weights_quad_v3`, in order to properly handle three sided polygons without needing a useless extra index in your weight array. This also improves clarity and consistency with other math_geom functions, thus reducing potential future errors. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D2461 --- source/blender/blenkernel/intern/collision.c | 6 +-- .../blender/blenkernel/intern/dynamicpaint.c | 4 +- source/blender/blenkernel/intern/smoke.c | 9 ++-- source/blender/blenlib/BLI_math_geom.h | 6 +-- source/blender/blenlib/intern/math_geom.c | 47 +++++++++---------- .../render/intern/source/convertblender.c | 15 ++++-- .../blender/render/intern/source/occlusion.c | 9 +++- 7 files changed, 50 insertions(+), 46 deletions(-) diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c index 18ca1407ba0..ee25be36855 100644 --- a/source/blender/blenkernel/intern/collision.c +++ b/source/blender/blenkernel/intern/collision.c @@ -1014,7 +1014,7 @@ static bool cloth_points_collision_response_static(ClothModifierData *clmd, Coll } BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3], - float r_nor[3], float *r_lambda, float r_w[4]) + float r_nor[3], float *r_lambda, float r_w[3]) { float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3]; float nor_v0p2, nor_p1p2; @@ -1026,7 +1026,7 @@ BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float nor_v0p2 = dot_v3v3(v0p2, r_nor); madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2); - interp_weights_face_v3(r_w, v0, v1, v2, NULL, p2face); + interp_weights_tri_v3(r_w, v0, v1, v2, p2face); sub_v3_v3v3(p1p2, p2, p1); sub_v3_v3v3(v0p2, p2, v0); @@ -1085,7 +1085,7 @@ static CollPair *cloth_point_collpair( const float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co; float lambda /*, distance1 */, distance2; float facenor[3], v1p1[3], v1p2[3]; - float w[4]; + float w[3]; if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w)) return collpair; diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 4d9e314afc4..1d198e36e05 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -3739,7 +3739,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex( /* velocity brush, only do on main sample */ if (brush->flags & MOD_DPAINT_USES_VELOCITY && ss == 0 && brushVelocity) { - float weights[4]; + float weights[3]; float brushPointVelocity[3]; float velocity[3]; @@ -3748,7 +3748,7 @@ static void dynamic_paint_paint_mesh_cell_point_cb_ex( const int v3 = mloop[mlooptri[hitTri].tri[2]].v; /* calculate barycentric weights for hit point */ - interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, hitCoord); + interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, hitCoord); /* simple check based on brush surface velocity, * todo: perhaps implement something that handles volume movement as well */ diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c index e8970d416e9..d0ef5cfc092 100644 --- a/source/blender/blenkernel/intern/smoke.c +++ b/source/blender/blenkernel/intern/smoke.c @@ -758,15 +758,14 @@ static void obstacles_from_derivedmesh_task_cb(void *userdata, const int z) /* find the nearest point on the mesh */ if (BLI_bvhtree_find_nearest(data->tree->tree, ray_start, &nearest, data->tree->nearest_callback, data->tree) != -1) { const MLoopTri *lt = &data->looptri[nearest.index]; - float weights[4]; + float weights[3]; int v1, v2, v3; /* calculate barycentric weights for nearest point */ v1 = data->mloop[lt->tri[0]].v; v2 = data->mloop[lt->tri[1]].v; v3 = data->mloop[lt->tri[2]].v; - interp_weights_face_v3( - weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, NULL, nearest.co); + interp_weights_tri_v3(weights, data->mvert[v1].co, data->mvert[v2].co, data->mvert[v3].co, nearest.co); // DG TODO if (data->has_velocity) @@ -1454,7 +1453,7 @@ static void sample_derivedmesh( /* find the nearest point on the mesh */ if (BLI_bvhtree_find_nearest(treeData->tree, ray_start, &nearest, treeData->nearest_callback, treeData) != -1) { - float weights[4]; + float weights[3]; int v1, v2, v3, f_index = nearest.index; float n1[3], n2[3], n3[3], hit_normal[3]; @@ -1471,7 +1470,7 @@ static void sample_derivedmesh( v1 = mloop[mlooptri[f_index].tri[0]].v; v2 = mloop[mlooptri[f_index].tri[1]].v; v3 = mloop[mlooptri[f_index].tri[2]].v; - interp_weights_face_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, NULL, nearest.co); + interp_weights_tri_v3(weights, mvert[v1].co, mvert[v2].co, mvert[v3].co, nearest.co); if (sfs->flags & MOD_SMOKE_FLOW_INITVELOCITY && velocity_map) { /* apply normal directional velocity */ diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index b5007b29f4c..d33c2cb3279 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -323,10 +323,8 @@ bool clip_segment_v3_plane_n( float r_p1[3], float r_p2[3]); /****************************** Interpolation ********************************/ - -/* tri or quad, d can be NULL */ -void interp_weights_face_v3(float w[4], - const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]); +void interp_weights_tri_v3(float w[3], const float a[3], const float b[3], const float c[3], const float p[3]); +void interp_weights_quad_v3(float w[4], const float a[3], const float b[3], const float c[3], const float d[3], const float p[3]); void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]); void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]); diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 76dac5487f2..74ede1e7559 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -2950,7 +2950,15 @@ static bool barycentric_weights(const float v1[3], const float v2[3], const floa } } -void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3]) +void interp_weights_tri_v3(float w[3], const float v1[3], const float v2[3], const float v3[3], const float co[3]) +{ + float n[3]; + + normal_tri_v3(n, v1, v2, v3); + barycentric_weights(v1, v2, v3, co, n, w); +} + +void interp_weights_quad_v3(float w[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3], const float co[3]) { float w2[3]; @@ -2963,7 +2971,7 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co w[1] = 1.0f; else if (equals_v3v3(co, v3)) w[2] = 1.0f; - else if (v4 && equals_v3v3(co, v4)) + else if (equals_v3v3(co, v4)) w[3] = 1.0f; else { /* otherwise compute barycentric interpolation weights */ @@ -2971,35 +2979,24 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co bool degenerate; sub_v3_v3v3(n1, v1, v3); - if (v4) { - sub_v3_v3v3(n2, v2, v4); - } - else { - sub_v3_v3v3(n2, v2, v3); - } + sub_v3_v3v3(n2, v2, v4); cross_v3_v3v3(n, n1, n2); - /* OpenGL seems to split this way, so we do too */ - if (v4) { - degenerate = barycentric_weights(v1, v2, v4, co, n, w); - SWAP(float, w[2], w[3]); + degenerate = barycentric_weights(v1, v2, v4, co, n, w); + SWAP(float, w[2], w[3]); - if (degenerate || (w[0] < 0.0f)) { - /* if w[1] is negative, co is on the other side of the v1-v3 edge, - * so we interpolate using the other triangle */ - degenerate = barycentric_weights(v2, v3, v4, co, n, w2); + if (degenerate || (w[0] < 0.0f)) { + /* if w[1] is negative, co is on the other side of the v1-v3 edge, + * so we interpolate using the other triangle */ + degenerate = barycentric_weights(v2, v3, v4, co, n, w2); - if (!degenerate) { - w[0] = 0.0f; - w[1] = w2[0]; - w[2] = w2[1]; - w[3] = w2[2]; - } + if (!degenerate) { + w[0] = 0.0f; + w[1] = w2[0]; + w[2] = w2[1]; + w[3] = w2[2]; } } - else { - barycentric_weights(v1, v2, v3, co, n, w); - } } } diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index 86961cdd169..263ea3d4ef2 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -5569,12 +5569,17 @@ static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *ve /* interpolate speed vectors from strand surface */ face= mesh->face[*index]; - co1= mesh->co[face[0]]; - co2= mesh->co[face[1]]; - co3= mesh->co[face[2]]; - co4= (face[3])? mesh->co[face[3]]: NULL; + co1 = mesh->co[face[0]]; + co2 = mesh->co[face[1]]; + co3 = mesh->co[face[2]]; - interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co); + if (face[3]) { + co4 = mesh->co[face[3]]; + interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co); + } + else { + interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co); + } zero_v4(speed); madd_v4_v4fl(speed, winspeed[face[0]], w[0]); diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index ddcd2e84520..cd93898d846 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -1190,9 +1190,14 @@ static void sample_occ_surface(ShadeInput *shi) co1 = mesh->co[face[0]]; co2 = mesh->co[face[1]]; co3 = mesh->co[face[2]]; - co4 = (face[3]) ? mesh->co[face[3]] : NULL; - interp_weights_face_v3(w, co1, co2, co3, co4, strand->vert->co); + if (face[3]) { + co4 = mesh->co[face[3]]; + interp_weights_quad_v3(w, co1, co2, co3, co4, strand->vert->co); + } + else { + interp_weights_tri_v3(w, co1, co2, co3, strand->vert->co); + } zero_v3(shi->ao); zero_v3(shi->env); From c4f60319d1709723d8076429c13965b0c94dc88b Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 11 Jan 2017 22:11:13 +0100 Subject: [PATCH 482/590] UI: Try limiting 'x' icon to search buttons Reusing PROP_TEXTEDIT_UPDATE instead of adding a new property flag just for search strings. Currently it's only used for search strings anyway so seems fine for now. Fixes T50336. --- source/blender/editors/interface/interface_utils.c | 8 +++----- source/blender/makesrna/RNA_types.h | 6 ++++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 8dfbbdd02eb..df6f098ee81 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -119,12 +119,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind else but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL); - PropertySubType subtype = RNA_property_subtype(prop); - if (!(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME) || (block->flag & UI_BLOCK_LIST_ITEM))) { - UI_but_flag_enable(but, UI_BUT_VALUE_CLEAR); - } if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) { - UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE); + /* TEXTEDIT_UPDATE is usally used for search buttons. For these we also want + * the 'x' icon to clear search string, so setting VALUE_CLEAR flag, too. */ + UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE | UI_BUT_VALUE_CLEAR); } break; case PROP_POINTER: diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 1a191a68668..dee8df7d933 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -174,8 +174,10 @@ typedef enum PropertyFlag { * and collections */ PROP_ANIMATABLE = (1 << 1), - /* This flag means when the property's widget is in 'textedit' mode, it will be updated after every typed char, - * instead of waiting final validation. Used e.g. for text searchbox. */ + /* This flag means when the property's widget is in 'textedit' mode, it will be updated + * after every typed char, instead of waiting final validation. Used e.g. for text searchbox. + * It will also cause UI_BUT_VALUE_CLEAR to be set for text buttons. We could add an own flag + * for search/filter properties, but this works just fine for now. */ PROP_TEXTEDIT_UPDATE = (1 << 31), /* icon */ From 092cbcd1d2c31b10af31ce326bdf4efc2819a5fa Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 11 Jan 2017 23:01:07 +0100 Subject: [PATCH 483/590] Fix T50056: Dyntopo brush size shortcut broken using constant detail setting. --- source/blender/editors/sculpt_paint/sculpt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 47f0220726b..84e98181dfb 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5693,11 +5693,11 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op)) WM_operator_properties_create_ptr(&props_ptr, ot); if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) { - set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0); - RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail"); + set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0); + RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.constant_detail_resolution"); } else if (sd->flags & SCULPT_DYNTOPO_DETAIL_BRUSH) { - set_brush_rc_props(&props_ptr, "sculpt", "constant_detail", NULL, 0); + set_brush_rc_props(&props_ptr, "sculpt", "constant_detail_resolution", NULL, 0); RNA_string_set(&props_ptr, "data_path_primary", "tool_settings.sculpt.detail_percent"); } else { From 65c8937f7ed815c74203dddc8d41429e0185744e Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Thu, 12 Jan 2017 01:03:23 -0500 Subject: [PATCH 484/590] Add Add Modifiers tab to the NLA & VSE editors This is a follow up to rBca935ab Differential Revision: https://developer.blender.org/D2442 --- .../scripts/startup/bl_ui/space_sequencer.py | 10 ++++++++++ source/blender/editors/space_nla/nla_buttons.c | 18 ++++++++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 26136a8e024..0648db3746d 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -497,6 +497,7 @@ class SequencerButtonsPanel_Output: class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel): bl_label = "Edit Strip" + bl_category = "Strip" def draw(self, context): layout = self.layout @@ -563,6 +564,7 @@ class SEQUENCER_PT_edit(SequencerButtonsPanel, Panel): class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): bl_label = "Effect Strip" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -701,6 +703,7 @@ class SEQUENCER_PT_effect(SequencerButtonsPanel, Panel): class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): bl_label = "Strip Input" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -795,6 +798,7 @@ class SEQUENCER_PT_input(SequencerButtonsPanel, Panel): class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel): bl_label = "Sound" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -848,6 +852,7 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, Panel): class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel): bl_label = "Scene" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -894,6 +899,7 @@ class SEQUENCER_PT_scene(SequencerButtonsPanel, Panel): class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel): bl_label = "Mask" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -923,6 +929,7 @@ class SEQUENCER_PT_mask(SequencerButtonsPanel, Panel): class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): bl_label = "Filter" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -977,6 +984,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel): bl_label = "Proxy/Timecode" + bl_category = "Strip" @classmethod def poll(cls, context): @@ -1109,6 +1117,7 @@ class SEQUENCER_PT_view_safe_areas(SequencerButtonsPanel_Output, Panel): class SEQUENCER_PT_modifiers(SequencerButtonsPanel, Panel): bl_label = "Modifiers" + bl_category = "Modifiers" def draw(self, context): layout = self.layout @@ -1211,6 +1220,7 @@ class SEQUENCER_PT_custom_props(SequencerButtonsPanel, PropertyPanel, Panel): COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} _context_path = "scene.sequence_editor.active_strip" _property_type = (bpy.types.Sequence,) + bl_category = "Strip" if __name__ == "__main__": # only for live edit. diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 3243579f7d0..5355b8012db 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -502,51 +502,57 @@ static void nla_panel_modifiers(const bContext *C, Panel *pa) void nla_buttons_register(ARegionType *art) { PanelType *pt; - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel animdata"); strcpy(pt->idname, "NLA_PT_animdata"); strcpy(pt->label, N_("Animation Data")); + strcpy(pt->category, "Animations"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_animdata; pt->poll = nla_animdata_panel_poll; pt->flag = PNL_DEFAULT_CLOSED; BLI_addtail(&art->paneltypes, pt); - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel track"); strcpy(pt->idname, "NLA_PT_track"); strcpy(pt->label, N_("Active Track")); + strcpy(pt->category, "Animations"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_track; pt->poll = nla_track_panel_poll; BLI_addtail(&art->paneltypes, pt); - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties"); strcpy(pt->idname, "NLA_PT_properties"); strcpy(pt->label, N_("Active Strip")); + strcpy(pt->category, "Animations"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_properties; pt->poll = nla_strip_panel_poll; BLI_addtail(&art->paneltypes, pt); - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel properties"); strcpy(pt->idname, "NLA_PT_actionclip"); strcpy(pt->label, N_("Action Clip")); + strcpy(pt->category, "Animations"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_actclip; pt->poll = nla_strip_actclip_panel_poll; BLI_addtail(&art->paneltypes, pt); - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel evaluation"); strcpy(pt->idname, "NLA_PT_evaluation"); strcpy(pt->label, N_("Evaluation")); + strcpy(pt->category, "Animations"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_evaluation; pt->poll = nla_strip_eval_panel_poll; BLI_addtail(&art->paneltypes, pt); - + pt = MEM_callocN(sizeof(PanelType), "spacetype nla panel modifiers"); strcpy(pt->idname, "NLA_PT_modifiers"); strcpy(pt->label, N_("Modifiers")); + strcpy(pt->category, "Modifiers"); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); pt->draw = nla_panel_modifiers; pt->poll = nla_strip_eval_panel_poll; From 67f68295be523d0dca5343db68352441f9e58d92 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 09:45:04 +0100 Subject: [PATCH 485/590] Cycles tests: Rework output messages Made them closer to how GTest shows the output, so reading test logs is easier now (at least feels more uniform). Additionally now we know how much time tests are taking so can tweak samples/resolution to reduce render time of slow tests. It is now also possible to enable colored messages using magic CYCLESTEST_COLOR environment variable. This makes it even easier to visually grep failed/passed tests using `ctest -R cycles -V`. --- tests/python/cycles_render_tests.py | 99 ++++++++++++++++++++++++----- 1 file changed, 82 insertions(+), 17 deletions(-) diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index 78b4b346f24..ae8848570f0 100755 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -6,9 +6,46 @@ import os import shutil import subprocess import sys +import time import tempfile +class COLORS_ANSI: + RED = '\033[00;31m' + GREEN = '\033[00;32m' + ENDC = '\033[0m' + + +class COLORS_DUMMY: + RED = '' + GREEN = '' + ENDC = '' + +COLORS = COLORS_DUMMY + + +def printMessage(type, status, message): + if type == 'SUCCESS': + print(COLORS.GREEN, end="") + elif type == 'FAILURE': + print(COLORS.RED, end="") + status_text = ... + if status == 'RUN': + status_text = " RUN " + elif status == 'OK': + status_text = " OK " + elif status == 'PASSED': + status_text = " PASSED " + elif status == 'FAILED': + status_text = " FAILED " + else: + status_text = status + print("[{}]" . format(status_text), end="") + print(COLORS.ENDC, end="") + print(" {}" . format(message)) + sys.stdout.flush() + + def render_file(filepath): command = ( BLENDER, @@ -83,16 +120,32 @@ def verify_output(filepath): def run_test(filepath): testname = test_get_name(filepath) spacer = "." * (32 - len(testname)) - print(testname, spacer, end="") - sys.stdout.flush() + printMessage('SUCCESS', 'RUN', testname) + time_start = time.time() error = render_file(filepath) + status = "FAIL" if not error: - if verify_output(filepath): - print("PASS") - else: + if not verify_output(filepath): error = "VERIFY" - if error: - print("FAIL", error) + time_end = time.time() + elapsed_ms = int((time_end - time_start) * 1000) + if not error: + printMessage('SUCCESS', 'OK', "{} ({} ms)" . + format(testname, elapsed_ms)) + else: + if error == "NO_CYCLES": + print("Can't perform tests because Cycles failed to load!") + return False + elif error == "NO_START": + print('Can not perform tests because blender fails to start.', + 'Make sure INSTALL target was run.') + return False + elif error == 'VERIFY': + print("Rendered result is different from reference image") + else: + print("Unknown error %r" % error) + printMessage('FAILURE', 'FAILED', "{} ({} ms)" . + format(testname, elapsed_ms)) return error @@ -105,30 +158,38 @@ def blend_list(path): def run_all_tests(dirpath): + passed_tests = [] failed_tests = [] all_files = list(blend_list(dirpath)) all_files.sort() + printMessage('SUCCESS', "==========", + "Running {} tests from 1 test case." . format(len(all_files))) + time_start = time.time() for filepath in all_files: error = run_test(filepath) + testname = test_get_name(filepath) if error: if error == "NO_CYCLES": - print("Can't perform tests because Cycles failed to load!") return False elif error == "NO_START": - print('Can not perform tests because blender fails to start.', - 'Make sure INSTALL target was run.') return False - elif error == 'VERIFY': - pass - else: - print("Unknown error %r" % error) - testname = test_get_name(filepath) failed_tests.append(testname) + else: + passed_tests.append(testname) + time_end = time.time() + elapsed_ms = int((time_end - time_start) * 1000) + print("") + printMessage('SUCCESS', "==========", + "{} tests from 1 test case ran. ({} ms total)" . + format(len(all_files), elapsed_ms)) + printMessage('SUCCESS', 'PASSED', "{} tests." . + format(len(passed_tests))) if failed_tests: + printMessage('FAILURE', 'FAILED', "{} tests, listed below:" . + format(len(failed_tests))) failed_tests.sort() - print("\n\nFAILED tests:") for test in failed_tests: - print(" ", test) + printMessage('FAILURE', "FAILED", "{}" . format(test)) return False return True @@ -145,10 +206,14 @@ def main(): parser = create_argparse() args = parser.parse_args() + global COLORS global BLENDER, ROOT, IDIFF global TEMP_FILE, TEMP_FILE_MASK, TEST_SCRIPT global VERBOSE + if os.environ.get("CYCLESTEST_COLOR") is not None: + COLORS = COLORS_ANSI + BLENDER = args.blender[0] ROOT = args.testdir[0] IDIFF = args.idiff[0] From 554024e08e7855685446b33d8bdbde5cacc196a5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 11 Oct 2016 16:33:07 +0200 Subject: [PATCH 486/590] Cycles: move hair particle settings to scene context Since the beginning of times hair settings in cycles were global for the whole scene but were located in the particle context. This causes quite some trickery to get shots set up for the movies here in the studio by forcing artists to create dummy particle system to change settings of hair on the shot. While ideally this settings should be properly become per-particle system for the time being it will save sweat and blood to move the settings to scene context. Reviewers: brecht Subscribers: jtheninja, eyecandy, venomgfx, Blendify Differential Revision: https://developer.blender.org/D2287 --- intern/cycles/blender/addon/ui.py | 57 +++++++++++-------------------- 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 3f7730efbb0..925f923dd41 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -226,6 +226,7 @@ class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel): scene = context.scene cscene = scene.cycles + ccscene = scene.cycles_curves if cscene.feature_set == 'EXPERIMENTAL': split = layout.split() @@ -252,6 +253,25 @@ class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel): row.prop(cscene, "volume_step_size") row.prop(cscene, "volume_max_steps") + layout.prop(ccscene, "use_curves", text="Use Hair") + col = layout.column() + col.active = ccscene.use_curves + + col.prop(ccscene, "primitive", text="Primitive") + col.prop(ccscene, "shape", text="Shape") + + if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'): + col.prop(ccscene, "cull_backfacing", text="Cull back-faces") + + if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK': + col.prop(ccscene, "resolution", text="Resolution") + elif ccscene.primitive == 'CURVE_SEGMENTS': + col.prop(ccscene, "subdivisions", text="Curve subdivisions") + + row = col.row() + row.prop(ccscene, "minimum_width", text="Min Pixels") + row.prop(ccscene, "maximum_width", text="Max Ext.") + class CyclesRender_PT_light_paths(CyclesButtonsPanel, Panel): bl_label = "Light Paths" @@ -1391,43 +1411,6 @@ class CyclesParticle_PT_textures(CyclesButtonsPanel, Panel): layout.template_ID(slot, "texture", new="texture.new") -class CyclesRender_PT_CurveRendering(CyclesButtonsPanel, Panel): - bl_label = "Cycles Hair Rendering" - bl_context = "particle" - - @classmethod - def poll(cls, context): - psys = context.particle_system - return CyclesButtonsPanel.poll(context) and psys and psys.settings.type == 'HAIR' - - def draw_header(self, context): - ccscene = context.scene.cycles_curves - self.layout.prop(ccscene, "use_curves", text="") - - def draw(self, context): - layout = self.layout - - scene = context.scene - ccscene = scene.cycles_curves - - layout.active = ccscene.use_curves - - layout.prop(ccscene, "primitive", text="Primitive") - layout.prop(ccscene, "shape", text="Shape") - - if not (ccscene.primitive in {'CURVE_SEGMENTS', 'LINE_SEGMENTS'} and ccscene.shape == 'RIBBONS'): - layout.prop(ccscene, "cull_backfacing", text="Cull back-faces") - - if ccscene.primitive == 'TRIANGLES' and ccscene.shape == 'THICK': - layout.prop(ccscene, "resolution", text="Resolution") - elif ccscene.primitive == 'CURVE_SEGMENTS': - layout.prop(ccscene, "subdivisions", text="Curve subdivisions") - - row = layout.row() - row.prop(ccscene, "minimum_width", text="Min Pixels") - row.prop(ccscene, "maximum_width", text="Max Ext.") - - class CyclesRender_PT_bake(CyclesButtonsPanel, Panel): bl_label = "Bake" bl_context = "render" From 511dbe56db0036406965c271e4daec3c715a7691 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 12:45:37 +0100 Subject: [PATCH 487/590] Cycles: Cleanup, use switch() instead of if-else chain About to add extra debug passes, which will be more clear to use switch(). --- intern/cycles/blender/blender_session.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 21166b2f155..f37e7d17559 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -305,12 +305,14 @@ static PassType get_pass_type(BL::RenderPass& b_pass) #ifdef WITH_CYCLES_DEBUG case BL::RenderPass::type_DEBUG: { - if(b_pass.debug_type() == BL::RenderPass::debug_type_BVH_TRAVERSAL_STEPS) - return PASS_BVH_TRAVERSAL_STEPS; - if(b_pass.debug_type() == BL::RenderPass::debug_type_BVH_TRAVERSED_INSTANCES) - return PASS_BVH_TRAVERSED_INSTANCES; - if(b_pass.debug_type() == BL::RenderPass::debug_type_RAY_BOUNCES) - return PASS_RAY_BOUNCES; + switch(b_pass.debug_type()) { + case BL::RenderPass::debug_type_BVH_TRAVERSAL_STEPS: + return PASS_BVH_TRAVERSAL_STEPS; + case BL::RenderPass::debug_type_BVH_TRAVERSED_INSTANCES: + return PASS_BVH_TRAVERSED_INSTANCES; + case BL::RenderPass::debug_type_RAY_BOUNCES: + return PASS_RAY_BOUNCES; + } break; } #endif From d1131227c54d1ae5c410d8f23ffe3a4770afc67d Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 12:54:24 +0100 Subject: [PATCH 488/590] Cycles: Cleanup, indentation within preprocessor --- intern/cycles/kernel/geom/geom_curve.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h index 636dbcc71e0..9de335403ce 100644 --- a/intern/cycles/kernel/geom/geom_curve.h +++ b/intern/cycles/kernel/geom/geom_curve.h @@ -911,7 +911,7 @@ ccl_device_forceinline bool bvh_curve_intersect(KernelGlobals *kg, Intersection # undef len3_squared # undef len3 # undef dot3 -# endif +#endif } ccl_device_inline float3 curvetangent(float t, float3 p0, float3 p1, float3 p2, float3 p3) From 618b3480c84500bc3a6bda2320c206000a80556e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 13:31:35 +0100 Subject: [PATCH 489/590] Cycles: Cleanup, remove duplicated code --- intern/cycles/render/buffers.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index cb20e811708..5030de69174 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -185,13 +185,9 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int } } #ifdef WITH_CYCLES_DEBUG - else if(type == PASS_BVH_TRAVERSAL_STEPS) { - for(int i = 0; i < size; i++, in += pass_stride, pixels++) { - float f = *in; - pixels[0] = f*scale; - } - } - else if(type == PASS_RAY_BOUNCES) { + else if(type == PASS_BVH_TRAVERSAL_STEPS || + type == PASS_RAY_BOUNCES) + { for(int i = 0; i < size; i++, in += pass_stride, pixels++) { float f = *in; pixels[0] = f*scale; From 789fdab825642d78aaa1fa7dde399bbc0c5b96ac Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 13:32:13 +0100 Subject: [PATCH 490/590] Cycles: Fix wrong scaling of traversed instances debug pass --- intern/cycles/render/buffers.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index 5030de69174..6aca6ffa3ca 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -186,6 +186,7 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int } #ifdef WITH_CYCLES_DEBUG else if(type == PASS_BVH_TRAVERSAL_STEPS || + type == PASS_BVH_TRAVERSED_INSTANCES || type == PASS_RAY_BOUNCES) { for(int i = 0; i < size; i++, in += pass_stride, pixels++) { From 8daf02f134692b21e62649acf2906aed344a70ae Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 13:33:53 +0100 Subject: [PATCH 491/590] Cycles: Remove more duplicated code in debug passes logic --- intern/cycles/render/film.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index e10a938e1eb..4cc9cb925c0 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -155,13 +155,7 @@ void Pass::add(PassType type, array& passes) break; #ifdef WITH_CYCLES_DEBUG case PASS_BVH_TRAVERSAL_STEPS: - pass.components = 1; - pass.exposure = false; - break; case PASS_BVH_TRAVERSED_INSTANCES: - pass.components = 1; - pass.exposure = false; - break; case PASS_RAY_BOUNCES: pass.components = 1; pass.exposure = false; From 53fa389802161e9e4ff6b5e0bfaa61cd4c761be6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 13:44:35 +0100 Subject: [PATCH 492/590] Cycles: Use dedicated debug passes for traversed nodes and intersection tests This way it's more clear whether some issue is caused by lots of geometry in the node or by lots of "transparent" BVH nodes. --- intern/cycles/blender/blender_session.cpp | 6 ++++-- intern/cycles/kernel/bvh/bvh_traversal.h | 8 ++++---- intern/cycles/kernel/bvh/bvh_types.h | 14 ++++++++++---- intern/cycles/kernel/bvh/qbvh_traversal.h | 8 ++++---- intern/cycles/kernel/kernel_debug.h | 14 ++++++++++---- intern/cycles/kernel/kernel_path.h | 3 ++- intern/cycles/kernel/kernel_path_branched.h | 3 ++- intern/cycles/kernel/kernel_types.h | 17 +++++++++-------- .../kernel/split/kernel_scene_intersect.h | 3 ++- intern/cycles/render/buffers.cpp | 3 ++- intern/cycles/render/film.cpp | 10 +++++++--- source/blender/makesrna/intern/rna_render.c | 11 ++++++++--- .../blender/render/extern/include/RE_pipeline.h | 3 ++- .../render/intern/source/render_result.c | 6 ++++-- 14 files changed, 70 insertions(+), 39 deletions(-) diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index f37e7d17559..04b5c3fa013 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -306,10 +306,12 @@ static PassType get_pass_type(BL::RenderPass& b_pass) case BL::RenderPass::type_DEBUG: { switch(b_pass.debug_type()) { - case BL::RenderPass::debug_type_BVH_TRAVERSAL_STEPS: - return PASS_BVH_TRAVERSAL_STEPS; + case BL::RenderPass::debug_type_BVH_TRAVERSED_NODES: + return PASS_BVH_TRAVERSED_NODES; case BL::RenderPass::debug_type_BVH_TRAVERSED_INSTANCES: return PASS_BVH_TRAVERSED_INSTANCES; + case BL::RenderPass::debug_type_BVH_INTERSECTIONS: + return PASS_BVH_INTERSECTIONS; case BL::RenderPass::debug_type_RAY_BOUNCES: return PASS_RAY_BOUNCES; } diff --git a/intern/cycles/kernel/bvh/bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h index a0e478e972b..c80a769ffa6 100644 --- a/intern/cycles/kernel/bvh/bvh_traversal.h +++ b/intern/cycles/kernel/bvh/bvh_traversal.h @@ -213,7 +213,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, --stack_ptr; } } - BVH_DEBUG_NEXT_STEP(); + BVH_DEBUG_NEXT_NODE(); } /* if node is leaf, fetch triangle list */ @@ -235,7 +235,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { for(; prim_addr < prim_addr2; prim_addr++) { - BVH_DEBUG_NEXT_STEP(); + BVH_DEBUG_NEXT_INTERSECTION(); kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); if(triangle_intersect(kg, &isect_precalc, @@ -264,7 +264,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { for(; prim_addr < prim_addr2; prim_addr++) { - BVH_DEBUG_NEXT_STEP(); + BVH_DEBUG_NEXT_INTERSECTION(); kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); if(motion_triangle_intersect(kg, isect, @@ -296,7 +296,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { for(; prim_addr < prim_addr2; prim_addr++) { - BVH_DEBUG_NEXT_STEP(); + BVH_DEBUG_NEXT_INTERSECTION(); kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); bool hit; if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { diff --git a/intern/cycles/kernel/bvh/bvh_types.h b/intern/cycles/kernel/bvh/bvh_types.h index c3abe2e157d..ead424aaaaf 100644 --- a/intern/cycles/kernel/bvh/bvh_types.h +++ b/intern/cycles/kernel/bvh/bvh_types.h @@ -50,12 +50,17 @@ CCL_NAMESPACE_BEGIN #ifdef __KERNEL_DEBUG__ # define BVH_DEBUG_INIT() \ do { \ - isect->num_traversal_steps = 0; \ + isect->num_traversed_nodes = 0; \ isect->num_traversed_instances = 0; \ + isect->num_intersections = 0; \ } while(0) -# define BVH_DEBUG_NEXT_STEP() \ +# define BVH_DEBUG_NEXT_NODE() \ do { \ - ++isect->num_traversal_steps; \ + ++isect->num_traversed_nodes; \ + } while(0) +# define BVH_DEBUG_NEXT_INTERSECTION() \ + do { \ + ++isect->num_intersections; \ } while(0) # define BVH_DEBUG_NEXT_INSTANCE() \ do { \ @@ -63,7 +68,8 @@ CCL_NAMESPACE_BEGIN } while(0) #else /* __KERNEL_DEBUG__ */ # define BVH_DEBUG_INIT() -# define BVH_DEBUG_NEXT_STEP() +# define BVH_DEBUG_NEXT_NODE() +# define BVH_DEBUG_NEXT_INTERSECTION() # define BVH_DEBUG_NEXT_INSTANCE() #endif /* __KERNEL_DEBUG__ */ diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h index f2d8e558dcc..1846a6073ac 100644 --- a/intern/cycles/kernel/bvh/qbvh_traversal.h +++ b/intern/cycles/kernel/bvh/qbvh_traversal.h @@ -131,7 +131,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, int child_mask; ssef dist; - BVH_DEBUG_NEXT_STEP(); + BVH_DEBUG_NEXT_NODE(); #if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) if(difl != 0.0f) { @@ -326,7 +326,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { for(; prim_addr < prim_addr2; prim_addr++) { - BVH_DEBUG_NEXT_STEP(); + BVH_DEBUG_NEXT_INTERSECTION(); kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); if(triangle_intersect(kg, &isect_precalc, @@ -347,7 +347,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { for(; prim_addr < prim_addr2; prim_addr++) { - BVH_DEBUG_NEXT_STEP(); + BVH_DEBUG_NEXT_INTERSECTION(); kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); if(motion_triangle_intersect(kg, isect, @@ -371,7 +371,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { for(; prim_addr < prim_addr2; prim_addr++) { - BVH_DEBUG_NEXT_STEP(); + BVH_DEBUG_NEXT_INTERSECTION(); kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); bool hit; if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { diff --git a/intern/cycles/kernel/kernel_debug.h b/intern/cycles/kernel/kernel_debug.h index 24d6458567e..5647bbae5b5 100644 --- a/intern/cycles/kernel/kernel_debug.h +++ b/intern/cycles/kernel/kernel_debug.h @@ -18,8 +18,9 @@ CCL_NAMESPACE_BEGIN ccl_device_inline void debug_data_init(DebugData *debug_data) { - debug_data->num_bvh_traversal_steps = 0; + debug_data->num_bvh_traversed_nodes = 0; debug_data->num_bvh_traversed_instances = 0; + debug_data->num_bvh_intersections = 0; debug_data->num_ray_bounces = 0; } @@ -30,16 +31,21 @@ ccl_device_inline void kernel_write_debug_passes(KernelGlobals *kg, int sample) { int flag = kernel_data.film.pass_flag; - if(flag & PASS_BVH_TRAVERSAL_STEPS) { - kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversal_steps, + if(flag & PASS_BVH_TRAVERSED_NODES) { + kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversed_nodes, sample, - debug_data->num_bvh_traversal_steps); + debug_data->num_bvh_traversed_nodes); } if(flag & PASS_BVH_TRAVERSED_INSTANCES) { kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_traversed_instances, sample, debug_data->num_bvh_traversed_instances); } + if(flag & PASS_BVH_INTERSECTIONS) { + kernel_write_pass_float(buffer + kernel_data.film.pass_bvh_intersections, + sample, + debug_data->num_bvh_intersections); + } if(flag & PASS_RAY_BOUNCES) { kernel_write_pass_float(buffer + kernel_data.film.pass_ray_bounces, sample, diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 6a36c68d69f..e25f2597366 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -634,8 +634,9 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, #ifdef __KERNEL_DEBUG__ if(state.flag & PATH_RAY_CAMERA) { - debug_data.num_bvh_traversal_steps += isect.num_traversal_steps; + debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes; debug_data.num_bvh_traversed_instances += isect.num_traversed_instances; + debug_data.num_bvh_intersections += isect.num_intersections; } debug_data.num_ray_bounces++; #endif /* __KERNEL_DEBUG__ */ diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index 10174e1c4ce..72a8d98ac00 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -288,8 +288,9 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in #endif /* __HAIR__ */ #ifdef __KERNEL_DEBUG__ - debug_data.num_bvh_traversal_steps += isect.num_traversal_steps; + debug_data.num_bvh_traversed_nodes += isect.num_traversed_nodes; debug_data.num_bvh_traversed_instances += isect.num_traversed_instances; + debug_data.num_bvh_intersections += isect.num_intersections; debug_data.num_ray_bounces++; #endif /* __KERNEL_DEBUG__ */ diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 2563f1491b1..4180465d1a1 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -345,9 +345,10 @@ typedef enum PassType { PASS_SUBSURFACE_COLOR = (1 << 24), PASS_LIGHT = (1 << 25), /* no real pass, used to force use_light_pass */ #ifdef __KERNEL_DEBUG__ - PASS_BVH_TRAVERSAL_STEPS = (1 << 26), + PASS_BVH_TRAVERSED_NODES = (1 << 26), PASS_BVH_TRAVERSED_INSTANCES = (1 << 27), - PASS_RAY_BOUNCES = (1 << 28), + PASS_BVH_INTERSECTIONS = (1 << 28), + PASS_RAY_BOUNCES = (1 << 29), #endif } PassType; @@ -542,8 +543,9 @@ typedef ccl_addr_space struct Intersection { int type; #ifdef __KERNEL_DEBUG__ - int num_traversal_steps; + int num_traversed_nodes; int num_traversed_instances; + int num_intersections; #endif } Intersection; @@ -1040,10 +1042,10 @@ typedef struct KernelFilm { float mist_falloff; #ifdef __KERNEL_DEBUG__ - int pass_bvh_traversal_steps; + int pass_bvh_traversed_nodes; int pass_bvh_traversed_instances; + int pass_bvh_intersections; int pass_ray_bounces; - int pass_pad3; #endif } KernelFilm; static_assert_align(KernelFilm, 16); @@ -1188,10 +1190,9 @@ static_assert_align(KernelData, 16); * really important here. */ typedef ccl_addr_space struct DebugData { - // Total number of BVH node traversal steps and primitives intersections - // for the camera rays. - int num_bvh_traversal_steps; + int num_bvh_traversed_nodes; int num_bvh_traversed_instances; + int num_bvh_intersections; int num_ray_bounces; } DebugData; #endif diff --git a/intern/cycles/kernel/split/kernel_scene_intersect.h b/intern/cycles/kernel/split/kernel_scene_intersect.h index fc4b4ee38e5..2388580051f 100644 --- a/intern/cycles/kernel/split/kernel_scene_intersect.h +++ b/intern/cycles/kernel/split/kernel_scene_intersect.h @@ -116,8 +116,9 @@ ccl_device void kernel_scene_intersect( #ifdef __KERNEL_DEBUG__ if(state.flag & PATH_RAY_CAMERA) { - debug_data->num_bvh_traversal_steps += isect->num_traversal_steps; + debug_data->num_bvh_traversed_nodes += isect->num_traversed_nodes; debug_data->num_bvh_traversed_instances += isect->num_traversed_instances; + debug_data->num_bvh_intersections += isect->num_intersections; } debug_data->num_ray_bounces++; #endif diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index 6aca6ffa3ca..f1692712d61 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -185,8 +185,9 @@ bool RenderBuffers::get_pass_rect(PassType type, float exposure, int sample, int } } #ifdef WITH_CYCLES_DEBUG - else if(type == PASS_BVH_TRAVERSAL_STEPS || + else if(type == PASS_BVH_TRAVERSED_NODES || type == PASS_BVH_TRAVERSED_INSTANCES || + type == PASS_BVH_INTERSECTIONS || type == PASS_RAY_BOUNCES) { for(int i = 0; i < size; i++, in += pass_stride, pixels++) { diff --git a/intern/cycles/render/film.cpp b/intern/cycles/render/film.cpp index 4cc9cb925c0..923252bb375 100644 --- a/intern/cycles/render/film.cpp +++ b/intern/cycles/render/film.cpp @@ -154,8 +154,9 @@ void Pass::add(PassType type, array& passes) pass.components = 0; break; #ifdef WITH_CYCLES_DEBUG - case PASS_BVH_TRAVERSAL_STEPS: + case PASS_BVH_TRAVERSED_NODES: case PASS_BVH_TRAVERSED_INSTANCES: + case PASS_BVH_INTERSECTIONS: case PASS_RAY_BOUNCES: pass.components = 1; pass.exposure = false; @@ -415,12 +416,15 @@ void Film::device_update(Device *device, DeviceScene *dscene, Scene *scene) break; #ifdef WITH_CYCLES_DEBUG - case PASS_BVH_TRAVERSAL_STEPS: - kfilm->pass_bvh_traversal_steps = kfilm->pass_stride; + case PASS_BVH_TRAVERSED_NODES: + kfilm->pass_bvh_traversed_nodes = kfilm->pass_stride; break; case PASS_BVH_TRAVERSED_INSTANCES: kfilm->pass_bvh_traversed_instances = kfilm->pass_stride; break; + case PASS_BVH_INTERSECTIONS: + kfilm->pass_bvh_intersections = kfilm->pass_stride; + break; case PASS_RAY_BOUNCES: kfilm->pass_ray_bounces = kfilm->pass_stride; break; diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index d69ae2b78bb..518c7efd915 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -78,9 +78,14 @@ EnumPropertyItem rna_enum_render_pass_type_items[] = { }; EnumPropertyItem rna_enum_render_pass_debug_type_items[] = { - {RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS, "BVH_TRAVERSAL_STEPS", 0, "BVH Traversal Steps", ""}, - {RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES, "BVH_TRAVERSED_INSTANCES", 0, "BVH Traversed Instances", ""}, - {RENDER_PASS_DEBUG_RAY_BOUNCES, "RAY_BOUNCES", 0, "Ray Steps", ""}, + {RENDER_PASS_DEBUG_BVH_TRAVERSED_NODES, "BVH_TRAVERSED_NODES", 0, "BVH Traversed Nodes", + "Number of nodes traversed in BVH for the camera rays"}, + {RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES, "BVH_TRAVERSED_INSTANCES", 0, "BVH Traversed Instances", + "Number of BVH instances traversed by camera rays"}, + {RENDER_PASS_DEBUG_BVH_INTERSECTIONS, "BVH_INTERSECTIONS", 0, "BVH Intersections", + "Number of primitive intersections performed by the camera rays"}, + {RENDER_PASS_DEBUG_RAY_BOUNCES, "RAY_BOUNCES", 0, "Ray Steps", + "Number of bounces done by the main integration loop"}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 7021477a702..f535aa5aa71 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -97,9 +97,10 @@ typedef struct RenderPass { } RenderPass; enum { - RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS = 0, + RENDER_PASS_DEBUG_BVH_TRAVERSED_NODES = 0, RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES = 1, RENDER_PASS_DEBUG_RAY_BOUNCES = 2, + RENDER_PASS_DEBUG_BVH_INTERSECTIONS = 3, }; /* a renderlayer is a full image, but with all passes and samples */ diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c index 2be6238eeec..f276c01e86a 100644 --- a/source/blender/render/intern/source/render_result.c +++ b/source/blender/render/intern/source/render_result.c @@ -550,10 +550,12 @@ RenderPass *gp_add_pass(RenderResult *rr, RenderLayer *rl, int channels, int pas const char *RE_debug_pass_name_get(int debug_type) { switch (debug_type) { - case RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS: - return "BVH Traversal Steps"; + case RENDER_PASS_DEBUG_BVH_TRAVERSED_NODES: + return "BVH Traversed Nodes"; case RENDER_PASS_DEBUG_BVH_TRAVERSED_INSTANCES: return "BVH Traversed Instances"; + case RENDER_PASS_DEBUG_BVH_INTERSECTIONS: + return "BVH Primitive Intersections"; case RENDER_PASS_DEBUG_RAY_BOUNCES: return "Ray Bounces"; } From 83d18a2a918964a1a587bb2d4795ec9cc6b8de53 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 15:22:41 +0100 Subject: [PATCH 493/590] Cycles: Make it more clear message why curve motion attribute was removed --- intern/cycles/blender/blender_curves.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 378ae67f0c7..30bacc007b0 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -677,8 +677,13 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int /* in case of new attribute, we verify if there really was any motion */ if(new_attribute) { if(i != numkeys || !have_motion) { - /* no motion, remove attributes again */ - VLOG(1) << "No motion, removing attribute"; + /* No motion or hair "topology" changed, remove attributes again. */ + if(i != numkeys) { + VLOG(1) << "Hair topology changed, removing attribute."; + } + else { + VLOG(1) << "No motion, removing attribute."; + } mesh->curve_attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); } else if(time_index > 0) { From 985c121c0b20bcf394bd5f54014a079ac29e9d6b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 15:28:19 +0100 Subject: [PATCH 494/590] Cycles: Cleanup, make curve functions private Not only they don't really follow naming convention (we don't use camel case) but also was not necessary to keep them in the global symbol table. --- intern/cycles/blender/blender_curves.cpp | 91 +++++++++++++----------- 1 file changed, 51 insertions(+), 40 deletions(-) diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 30bacc007b0..96a208b338f 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -29,24 +29,6 @@ CCL_NAMESPACE_BEGIN -/* Utilities */ - -/* Hair curve functions */ - -void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]); -void interp_weights(float t, float data[4]); -float shaperadius(float shape, float root, float tip, float time); -void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData); -bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num); -bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num); -bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background); -void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData); -void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, - float3 RotCam, bool is_ortho); -void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution); -void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata); -void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata); - ParticleCurveData::ParticleCurveData() { } @@ -55,7 +37,7 @@ ParticleCurveData::~ParticleCurveData() { } -void interp_weights(float t, float data[4]) +static void interp_weights(float t, float data[4]) { /* Cardinal curve interpolation */ float t2 = t * t; @@ -68,17 +50,19 @@ void interp_weights(float t, float data[4]) data[3] = fc * t3 - fc * t2; } -void curveinterp_v3_v3v3v3v3(float3 *p, float3 *v1, float3 *v2, float3 *v3, float3 *v4, const float w[4]) +static void curveinterp_v3_v3v3v3v3(float3 *p, + float3 *v1, float3 *v2, float3 *v3, float3 *v4, + const float w[4]) { p->x = v1->x * w[0] + v2->x * w[1] + v3->x * w[2] + v4->x * w[3]; p->y = v1->y * w[0] + v2->y * w[1] + v3->y * w[2] + v4->y * w[3]; p->z = v1->z * w[0] + v2->z * w[1] + v3->z * w[2] + v4->z * w[3]; } -float shaperadius(float shape, float root, float tip, float time) +static float shaperadius(float shape, float root, float tip, float time) { float radius = 1.0f - time; - + if(shape != 0.0f) { if(shape < 0.0f) radius = powf(radius, 1.0f + shape); @@ -90,7 +74,13 @@ float shaperadius(float shape, float root, float tip, float time) /* curve functions */ -void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyloc, float *time, ParticleCurveData *CData) +static void InterpolateKeySegments(int seg, + int segno, + int key, + int curve, + float3 *keyloc, + float *time, + ParticleCurveData *CData) { float3 ckey_loc1 = CData->curvekey_co[key]; float3 ckey_loc2 = ckey_loc1; @@ -119,7 +109,11 @@ void InterpolateKeySegments(int seg, int segno, int key, int curve, float3 *keyl curveinterp_v3_v3v3v3v3(keyloc, &ckey_loc1, &ckey_loc2, &ckey_loc3, &ckey_loc4, t); } -bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background) +static bool ObtainCacheParticleData(Mesh *mesh, + BL::Mesh *b_mesh, + BL::Object *b_ob, + ParticleCurveData *CData, + bool background) { int curvenum = 0; int keyno = 0; @@ -143,7 +137,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par int totparts = b_psys.particles.length(); int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f); int totcurves = totchild; - + if(b_part.child_type() == 0 || totchild == 0) totcurves += totparts; @@ -161,7 +155,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par CData->psys_shader.push_back_slow(shader); float radius = get_float(cpsys, "radius_scale") * 0.5f; - + CData->psys_rootradius.push_back_slow(radius * get_float(cpsys, "root_width")); CData->psys_tipradius.push_back_slow(radius * get_float(cpsys, "tip_width")); CData->psys_shape.push_back_slow(get_float(cpsys, "shape")); @@ -181,7 +175,7 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par for(; pa_no < totparts+totchild; pa_no++) { int keynum = 0; CData->curve_firstkey.push_back_slow(keyno); - + float curve_length = 0.0f; float3 pcKey; for(int step_no = 0; step_no < ren_step; step_no++) { @@ -213,7 +207,12 @@ bool ObtainCacheParticleData(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par return true; } -bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num) +static bool ObtainCacheParticleUV(Mesh *mesh, + BL::Mesh *b_mesh, + BL::Object *b_ob, + ParticleCurveData *CData, + bool background, + int uv_num) { if(!(mesh && b_mesh && b_ob && CData)) return false; @@ -231,7 +230,7 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti int totparts = b_psys.particles.length(); int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f); int totcurves = totchild; - + if(b_part.child_type() == 0 || totchild == 0) totcurves += totparts; @@ -267,7 +266,12 @@ bool ObtainCacheParticleUV(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Parti return true; } -bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num) +static bool ObtainCacheParticleVcol(Mesh *mesh, + BL::Mesh *b_mesh, + BL::Object *b_ob, + ParticleCurveData *CData, + bool background, + int vcol_num) { if(!(mesh && b_mesh && b_ob && CData)) return false; @@ -285,7 +289,7 @@ bool ObtainCacheParticleVcol(Mesh *mesh, BL::Mesh *b_mesh, BL::Object *b_ob, Par int totparts = b_psys.particles.length(); int totchild = background ? b_psys.child_particles.length() : (int)((float)b_psys.child_particles.length() * (float)b_part.draw_percentage() / 100.0f); int totcurves = totchild; - + if(b_part.child_type() == 0 || totchild == 0) totcurves += totparts; @@ -333,8 +337,8 @@ static void set_resolution(BL::Object *b_ob, BL::Scene *scene, bool render) } } -void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, - float3 RotCam, bool is_ortho) +static void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, + float3 RotCam, bool is_ortho) { int vertexno = mesh->verts.size(); int vertexindex = vertexno; @@ -380,7 +384,7 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, if(curvekey == CData->curve_firstkey[curve] + CData->curve_keynum[curve] - 1) v1 = CData->curvekey_co[curvekey] - CData->curvekey_co[max(curvekey - 1, CData->curve_firstkey[curve])]; - else + else v1 = CData->curvekey_co[curvekey + 1] - CData->curvekey_co[curvekey - 1]; time = CData->curvekey_time[curvekey]/CData->curve_length[curve]; @@ -416,7 +420,9 @@ void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, /* texture coords still needed */ } -void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resolution) +static void ExportCurveTriangleGeometry(Mesh *mesh, + ParticleCurveData *CData, + int resolution) { int vertexno = mesh->verts.size(); int vertexindex = vertexno; @@ -548,7 +554,7 @@ void ExportCurveTriangleGeometry(Mesh *mesh, ParticleCurveData *CData, int resol /* texture coords still needed */ } -void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) +static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) { int num_keys = 0; int num_curves = 0; @@ -557,7 +563,7 @@ void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CData) return; Attribute *attr_intercept = NULL; - + if(mesh->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT); @@ -703,7 +709,10 @@ static void ExportCurveSegmentsMotion(Mesh *mesh, ParticleCurveData *CData, int } } -void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, float3 *uvdata) +static void ExportCurveTriangleUV(ParticleCurveData *CData, + int vert_offset, + int resol, + float3 *uvdata) { if(uvdata == NULL) return; @@ -748,7 +757,10 @@ void ExportCurveTriangleUV(ParticleCurveData *CData, int vert_offset, int resol, } } -void ExportCurveTriangleVcol(ParticleCurveData *CData, int vert_offset, int resol, uchar4 *cdata) +static void ExportCurveTriangleVcol(ParticleCurveData *CData, + int vert_offset, + int resol, + uchar4 *cdata) { if(cdata == NULL) return; @@ -1049,4 +1061,3 @@ void BlenderSync::sync_curves(Mesh *mesh, } CCL_NAMESPACE_END - From d9cd9ff322f3d4b6b055627ccd1e7a556e6b91d4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 15:30:56 +0100 Subject: [PATCH 495/590] Cycles: Cleanup, space prior to semicolon We don't have that in Blender style, no reason to violate it here. --- intern/cycles/blender/blender_curves.cpp | 32 ++++++++++++------------ 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/intern/cycles/blender/blender_curves.cpp b/intern/cycles/blender/blender_curves.cpp index 96a208b338f..e42ff5d72a6 100644 --- a/intern/cycles/blender/blender_curves.cpp +++ b/intern/cycles/blender/blender_curves.cpp @@ -345,8 +345,8 @@ static void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, int numverts = 0, numtris = 0; /* compute and reserve size of arrays */ - for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; @@ -358,8 +358,8 @@ static void ExportCurveTrianglePlanes(Mesh *mesh, ParticleCurveData *CData, mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); /* actually export */ - for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; @@ -429,8 +429,8 @@ static void ExportCurveTriangleGeometry(Mesh *mesh, int numverts = 0, numtris = 0; /* compute and reserve size of arrays */ - for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; @@ -442,8 +442,8 @@ static void ExportCurveTriangleGeometry(Mesh *mesh, mesh->reserve_mesh(mesh->verts.size() + numverts, mesh->num_triangles() + numtris); /* actually export */ - for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; @@ -568,8 +568,8 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa attr_intercept = mesh->curve_attributes.add(ATTR_STD_CURVE_INTERCEPT); /* compute and reserve size of arrays */ - for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; @@ -588,8 +588,8 @@ static void ExportCurveSegments(Scene *scene, Mesh *mesh, ParticleCurveData *CDa num_curves = 0; /* actually export */ - for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; @@ -722,8 +722,8 @@ static void ExportCurveTriangleUV(ParticleCurveData *CData, int vertexindex = vert_offset; - for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; @@ -767,8 +767,8 @@ static void ExportCurveTriangleVcol(ParticleCurveData *CData, int vertexindex = vert_offset; - for(int sys = 0; sys < CData->psys_firstcurve.size() ; sys++) { - for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys] ; curve++) { + for(int sys = 0; sys < CData->psys_firstcurve.size(); sys++) { + for(int curve = CData->psys_firstcurve[sys]; curve < CData->psys_firstcurve[sys] + CData->psys_curvenum[sys]; curve++) { if(CData->curve_keynum[curve] <= 1 || CData->curve_length[curve] == 0.0f) continue; From 0421ae056d8ebb7e10894e39d86334b41c061f39 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 15:48:21 +0100 Subject: [PATCH 496/590] Cycles: Change confusing logic of max leaf size check Maximal number of elements is supposed to be inclusive. That is what it was always meant in this file and what @brecht considered still the case in 6974b69c6172. In fact, the commit message to that change mentions that we allowed up to 2 curve primitives per leaf while in fact it was doing up to 1 curve primitive. Making it real 2 primitives at a max gives about 5% slowdown for the koro.blend scene. This is a reason why BVHParams.max_curve_leaf_size was changed to 1 by this change. --- intern/cycles/bvh/bvh_build.cpp | 6 +++--- intern/cycles/bvh/bvh_params.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 14f66aca70f..d283cdaf9d7 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -449,9 +449,9 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange& range, num_triangles++; } - return (num_triangles < params.max_triangle_leaf_size) && - (num_curves < params.max_curve_leaf_size) && - (num_motion_curves < params.max_curve_leaf_size); + return (num_triangles <= params.max_triangle_leaf_size) && + (num_curves <= params.max_curve_leaf_size) && + (num_motion_curves <= params.max_curve_leaf_size); } /* multithreaded binning builder */ diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index 2e698a80742..431e42a0d6a 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -80,7 +80,7 @@ public: min_leaf_size = 1; max_triangle_leaf_size = 8; - max_curve_leaf_size = 2; + max_curve_leaf_size = 1; top_level = false; use_qbvh = false; From 76a4cf1941ef0f1e8ca2dd641fb94703dce5a9b0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 16:54:08 +0100 Subject: [PATCH 497/590] Cycles: Use separate limit for motion primitives for BVH node limits This way we can have different limits for regular and motion curves which we'll do in one of the upcoming commits in order to gain some percents of speedup. The reasoning here is that motion curves are usually intersecting lots of others bounding boxes, which makes it inefficient to have single primitive in the leaf node. --- intern/cycles/bvh/bvh_build.cpp | 8 ++++++-- intern/cycles/bvh/bvh_params.h | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index d283cdaf9d7..48f1d063fd1 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -435,6 +435,7 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange& range, return false; size_t num_triangles = 0; + size_t num_motion_triangles = 0; size_t num_curves = 0; size_t num_motion_curves = 0; @@ -445,13 +446,16 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange& range, num_curves++; if(ref.prim_type() & PRIMITIVE_MOTION_CURVE) num_motion_curves++; - else if(ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) + else if(ref.prim_type() & PRIMITIVE_TRIANGLE) num_triangles++; + else if(ref.prim_type() & PRIMITIVE_MOTION_TRIANGLE) + num_motion_triangles++; } return (num_triangles <= params.max_triangle_leaf_size) && + (num_motion_triangles <= params.max_motion_triangle_leaf_size) && (num_curves <= params.max_curve_leaf_size) && - (num_motion_curves <= params.max_curve_leaf_size); + (num_motion_curves <= params.max_motion_curve_leaf_size); } /* multithreaded binning builder */ diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index 431e42a0d6a..38a2e557a5d 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -43,7 +43,9 @@ public: /* number of primitives in leaf */ int min_leaf_size; int max_triangle_leaf_size; + int max_motion_triangle_leaf_size; int max_curve_leaf_size; + int max_motion_curve_leaf_size; /* object or mesh level bvh */ bool top_level; @@ -80,7 +82,9 @@ public: min_leaf_size = 1; max_triangle_leaf_size = 8; + max_motion_triangle_leaf_size = 8; max_curve_leaf_size = 1; + max_motion_curve_leaf_size = 1; top_level = false; use_qbvh = false; From f12f906dd92764746faf90a56a14d366a366940b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 17:38:27 +0100 Subject: [PATCH 498/590] Cycles: Correct assert() for cases when there are multiple curves per BVH node --- intern/cycles/kernel/bvh/bvh_traversal.h | 2 +- intern/cycles/kernel/bvh/qbvh_traversal.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/intern/cycles/kernel/bvh/bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h index c80a769ffa6..e85716df33f 100644 --- a/intern/cycles/kernel/bvh/bvh_traversal.h +++ b/intern/cycles/kernel/bvh/bvh_traversal.h @@ -297,7 +297,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, case PRIMITIVE_MOTION_CURVE: { for(; prim_addr < prim_addr2; prim_addr++) { BVH_DEBUG_NEXT_INTERSECTION(); - kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL)); bool hit; if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { hit = bvh_cardinal_curve_intersect(kg, diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h index 1846a6073ac..c51b3a91153 100644 --- a/intern/cycles/kernel/bvh/qbvh_traversal.h +++ b/intern/cycles/kernel/bvh/qbvh_traversal.h @@ -372,7 +372,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, case PRIMITIVE_MOTION_CURVE: { for(; prim_addr < prim_addr2; prim_addr++) { BVH_DEBUG_NEXT_INTERSECTION(); - kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL)); bool hit; if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { hit = bvh_cardinal_curve_intersect(kg, From b53ce9a1d0dc05c04c950cc614b6bba845cabfa4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 18:20:19 +0100 Subject: [PATCH 499/590] Cycles: Prepare BVH traversal code to work with multiple curve primitives per node --- intern/cycles/kernel/bvh/bvh_traversal.h | 7 ++++--- intern/cycles/kernel/bvh/qbvh_traversal.h | 7 ++++--- intern/cycles/kernel/bvh/qbvh_volume.h | 1 - 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/intern/cycles/kernel/bvh/bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h index e85716df33f..80c8f31473a 100644 --- a/intern/cycles/kernel/bvh/bvh_traversal.h +++ b/intern/cycles/kernel/bvh/bvh_traversal.h @@ -297,7 +297,8 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, case PRIMITIVE_MOTION_CURVE: { for(; prim_addr < prim_addr2; prim_addr++) { BVH_DEBUG_NEXT_INTERSECTION(); - kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL)); + const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr); + kernel_assert((curve_type & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL)); bool hit; if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { hit = bvh_cardinal_curve_intersect(kg, @@ -308,7 +309,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, object, prim_addr, ray->time, - type, + curve_type, lcg_state, difl, extmax); @@ -322,7 +323,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, object, prim_addr, ray->time, - type, + curve_type, lcg_state, difl, extmax); diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h index c51b3a91153..1d5643ca540 100644 --- a/intern/cycles/kernel/bvh/qbvh_traversal.h +++ b/intern/cycles/kernel/bvh/qbvh_traversal.h @@ -372,7 +372,8 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, case PRIMITIVE_MOTION_CURVE: { for(; prim_addr < prim_addr2; prim_addr++) { BVH_DEBUG_NEXT_INTERSECTION(); - kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL)); + const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr); + kernel_assert((curve_type & PRIMITIVE_ALL) == (type & PRIMITIVE_ALL)); bool hit; if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { hit = bvh_cardinal_curve_intersect(kg, @@ -383,7 +384,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, object, prim_addr, ray->time, - type, + curve_type, lcg_state, difl, extmax); @@ -397,7 +398,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, object, prim_addr, ray->time, - type, + curve_type, lcg_state, difl, extmax); diff --git a/intern/cycles/kernel/bvh/qbvh_volume.h b/intern/cycles/kernel/bvh/qbvh_volume.h index 424710b69f2..1e77d8e67ec 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume.h +++ b/intern/cycles/kernel/bvh/qbvh_volume.h @@ -295,7 +295,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, int object_flag = kernel_tex_fetch(__object_flag, object); if(object_flag & SD_OBJECT_HAS_VOLUME) { - # if BVH_FEATURE(BVH_MOTION) bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm); # else From 720e5648824c102155ba3dd4551a73e5589a0272 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 12 Jan 2017 18:23:23 +0100 Subject: [PATCH 500/590] Cycles: Allow up to 4 motion curve primitives per BVH node This avoids intersection AABB of different curve primitives which makes it less ray-to-primitive intersections. This gives about 30% speedup of hair rendering in the barber shop scenes here. There is still some work to be done on those files to solve major speed issues on certain frames. --- intern/cycles/bvh/bvh_params.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index 38a2e557a5d..6d426475737 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -84,7 +84,7 @@ public: max_triangle_leaf_size = 8; max_motion_triangle_leaf_size = 8; max_curve_leaf_size = 1; - max_motion_curve_leaf_size = 1; + max_motion_curve_leaf_size = 4; top_level = false; use_qbvh = false; From 99ca90e80865a99a609cad53f7de435b160549f8 Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 3 Jan 2017 18:50:15 +0300 Subject: [PATCH 501/590] Dynamic Paint: improve UV island border handling in effects. 1. Forcibly symmetrize the neighbor relations, so that if A is neighbor of B, B is neighbor of A. The existing code is guaranteed to violate this if texture resolution is different between the sides of a seam. 2. In texture mode dynamic paint adds a 1 pixel wide border around the islands. These pixels aren't really part of the dynamic paint domain and thus by design can't have symmetrical neighbor relations. This means they can't be treated by effects like normal pixels. The simplest way to handle it in a consistent way is to exclude them from effects, but add an additional pass that recomputes them as average of their non-border neighbors, located on both sides of the seam. --- .../blender/blenkernel/intern/dynamicpaint.c | 238 +++++++++++++++++- 1 file changed, 228 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 1d198e36e05..4f204f2892f 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -215,6 +215,7 @@ typedef struct ImgSeqFormatData { /* adjacency data flags */ #define ADJ_ON_MESH_EDGE (1 << 0) +#define ADJ_BORDER_PIXEL (1 << 1) typedef struct PaintAdjData { int *n_target; /* array of neighboring point indexes, for single sample use (n_index + neigh_num) */ @@ -222,6 +223,8 @@ typedef struct PaintAdjData { int *n_num; /* num of neighs for each point */ int *flags; /* vertex adjacency flags */ int total_targets; /* size of n_target */ + int *border; /* indices of border pixels (only for texture paint) */ + int total_border; /* size of border */ } PaintAdjData; /***************************** General Utils ******************************/ @@ -822,6 +825,8 @@ static void dynamicPaint_freeAdjData(PaintSurfaceData *data) MEM_freeN(data->adj_data->n_target); if (data->adj_data->flags) MEM_freeN(data->adj_data->flags); + if (data->adj_data->border) + MEM_freeN(data->adj_data->border); MEM_freeN(data->adj_data); data->adj_data = NULL; } @@ -1298,6 +1303,8 @@ static void dynamicPaint_initAdjacencyData(DynamicPaintSurface *surface, const b ad->n_target = MEM_callocN(sizeof(int) * neigh_points, "Surface Adj Targets"); ad->flags = MEM_callocN(sizeof(int) * sData->total_points, "Surface Adj Flags"); ad->total_targets = neigh_points; + ad->border = NULL; + ad->total_border = 0; /* in case of allocation error, free memory */ if (!ad->n_index || !ad->n_num || !ad->n_target || !temp_data) { @@ -2520,6 +2527,108 @@ static int dynamic_paint_find_neighbour_pixel( } } +static bool dynamicPaint_pointHasNeighbor(PaintAdjData *ed, int index, int neighbor) +{ + const int idx = ed->n_index[index]; + + for (int i = 0; i < ed->n_num[index]; i++) { + if (ed->n_target[idx + i] == neighbor) { + return true; + } + } + + return false; +} + +/* Makes the adjacency data symmetric, except for border pixels. I.e. if A is neighbor of B, B is neighbor of A. */ +static bool dynamicPaint_symmetrizeAdjData(PaintAdjData *ed, int active_points) +{ + int *new_n_index = MEM_callocN(sizeof(int) * active_points, "Surface Adj Index"); + int *new_n_num = MEM_callocN(sizeof(int) * active_points, "Surface Adj Counts"); + + if (new_n_num && new_n_index) { + /* Count symmetrized neigbors */ + int total_targets = 0; + + for (int index = 0; index < active_points; index++) { + total_targets += ed->n_num[index]; + new_n_num[index] = ed->n_num[index]; + } + + for (int index = 0; index < active_points; index++) { + if (ed->flags[index] & ADJ_BORDER_PIXEL) { + continue; + } + + for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) { + const int target = ed->n_target[idx + i]; + + assert(!(ed->flags[target] & ADJ_BORDER_PIXEL)); + + if (!dynamicPaint_pointHasNeighbor(ed, target, index)) { + new_n_num[target]++; + total_targets++; + } + } + } + + /* Allocate a new target map */ + int *new_n_target = MEM_callocN(sizeof(int) * total_targets, "Surface Adj Targets"); + + if (new_n_target) { + /* Copy existing neighbors to the new map */ + int n_pos = 0; + + for (int index = 0; index < active_points; index++) { + new_n_index[index] = n_pos; + memcpy(&new_n_target[n_pos], &ed->n_target[ed->n_index[index]], sizeof(int) * ed->n_num[index]); + + /* Reset count to old, but advance position by new, leaving a gap to fill below. */ + n_pos += new_n_num[index]; + new_n_num[index] = ed->n_num[index]; + } + + assert(n_pos == total_targets); + + /* Add symmetrized - this loop behavior must exactly match the count pass above */ + for (int index = 0; index < active_points; index++) { + if (ed->flags[index] & ADJ_BORDER_PIXEL) { + continue; + } + + for (int i = 0, idx = ed->n_index[index]; i < ed->n_num[index]; i++) { + const int target = ed->n_target[idx + i]; + + if (!dynamicPaint_pointHasNeighbor(ed, target, index)) { + const int num = new_n_num[target]++; + new_n_target[new_n_index[target] + num] = index; + } + } + } + + /* Swap maps */ + MEM_freeN(ed->n_target); + ed->n_target = new_n_target; + + MEM_freeN(ed->n_index); + ed->n_index = new_n_index; + + MEM_freeN(ed->n_num); + ed->n_num = new_n_num; + + ed->total_targets = total_targets; + return true; + } + } + + if (new_n_index) + MEM_freeN(new_n_index); + if (new_n_num) + MEM_freeN(new_n_num); + + return false; +} + int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, float *progress, short *do_update) { /* Antialias jitter point relative coords */ @@ -2668,30 +2777,28 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo &vert_to_looptri_map, &vert_to_looptri_map_mem, dm->getVertArray(dm), dm->getNumVerts(dm), mlooptri, tottri, mloop, dm->getNumLoops(dm)); + int total_border = 0; + for (int ty = 0; ty < h; ty++) { for (int tx = 0; tx < w; tx++) { const int index = tx + w * ty; if (tempPoints[index].tri_index != -1) { - int start_pos = n_pos; ed->n_index[final_index[index]] = n_pos; ed->n_num[final_index[index]] = 0; + if (tempPoints[index].neighbour_pixel != -1) { + ed->flags[final_index[index]] |= ADJ_BORDER_PIXEL; + total_border++; + } + for (int i = 0; i < 8; i++) { /* Try to find a neighboring pixel in defined direction. If not found, -1 is returned */ const int n_target = dynamic_paint_find_neighbour_pixel( &data, vert_to_looptri_map, w, h, tx, ty, i); if (n_target >= 0 && n_target != index) { - bool duplicate = false; - for (int j = start_pos; j < n_pos; j++) { - if (ed->n_target[j] == final_index[n_target]) { - duplicate = true; - break; - } - } - - if (!duplicate) { + if (!dynamicPaint_pointHasNeighbor(ed, final_index[index], final_index[n_target])) { ed->n_target[n_pos] = final_index[n_target]; ed->n_num[final_index[index]]++; n_pos++; @@ -2707,6 +2814,24 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo MEM_freeN(vert_to_looptri_map); MEM_freeN(vert_to_looptri_map_mem); + + /* Make neighbors symmetric */ + if (!dynamicPaint_symmetrizeAdjData(ed, active_points)) { + error = true; + } + + /* Create a list of border pixels */ + ed->border = MEM_callocN(sizeof(int) * total_border, "Border Pixel Index"); + + if (ed->border) { + ed->total_border = total_border; + + for (int i = 0, next = 0; i < active_points; i++) { + if (ed->flags[i] & ADJ_BORDER_PIXEL) { + ed->border[next++] = i; + } + } + } } } @@ -4529,6 +4654,10 @@ static void dynamicPaint_doSmudge(DynamicPaintSurface *surface, DynamicPaintBrus for (step = 0; step < steps; step++) { for (index = 0; index < sData->total_points; index++) { int i; + + if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) + continue; + PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index]; float smudge_str = bData->brush_velocity[index * 4 + 3]; @@ -4708,6 +4837,9 @@ static void dynamic_paint_effect_spread_cb(void *userdata, const int index) const DynamicPaintSurface *surface = data->surface; const PaintSurfaceData *sData = surface->data; + if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) + return; + const int numOfNeighs = sData->adj_data->n_num[index]; BakeAdjPoint *bNeighs = sData->bData->bNeighs; PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index]; @@ -4750,6 +4882,9 @@ static void dynamic_paint_effect_shrink_cb(void *userdata, const int index) const DynamicPaintSurface *surface = data->surface; const PaintSurfaceData *sData = surface->data; + if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) + return; + const int numOfNeighs = sData->adj_data->n_num[index]; BakeAdjPoint *bNeighs = sData->bData->bNeighs; PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index]; @@ -4796,6 +4931,10 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index) const DynamicPaintSurface *surface = data->surface; const PaintSurfaceData *sData = surface->data; + + if (sData->adj_data->flags[index] & ADJ_BORDER_PIXEL) + return; + BakeAdjPoint *bNeighs = sData->bData->bNeighs; PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index]; const PaintPoint *prevPoint = data->prevPoint; @@ -4964,6 +5103,80 @@ static void dynamicPaint_doEffectStep( } } +static void dynamic_paint_border_cb(void *userdata, const int b_index) +{ + const DynamicPaintEffectData *data = userdata; + + const DynamicPaintSurface *surface = data->surface; + const PaintSurfaceData *sData = surface->data; + + const int index = sData->adj_data->border[b_index]; + + const int numOfNeighs = sData->adj_data->n_num[index]; + PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index]; + + const int *n_index = sData->adj_data->n_index; + const int *n_target = sData->adj_data->n_target; + + /* Average neighboring points. Intermediaries use premultiplied alpha. */ + float mix_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float mix_e_color[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float mix_wetness = 0.0f; + + for (int i = 0; i < numOfNeighs; i++) { + const int n_idx = n_index[index] + i; + const int target = n_target[n_idx]; + + PaintPoint *pPoint2 = &((PaintPoint *)sData->type_data)[target]; + + assert(!(sData->adj_data->flags[target] & ADJ_BORDER_PIXEL)); + + madd_v3_v3fl(mix_color, pPoint2->color, pPoint2->color[3]); + mix_color[3] += pPoint2->color[3]; + + madd_v3_v3fl(mix_e_color, pPoint2->e_color, pPoint2->e_color[3]); + mix_e_color[3] += pPoint2->e_color[3]; + + mix_wetness += pPoint2->wetness; + } + + const float divisor = 1.0f / numOfNeighs; + + if (mix_color[3]) { + pPoint->color[3] = mix_color[3] * divisor; + mul_v3_v3fl(pPoint->color, mix_color, divisor / pPoint->color[3]); + } + else { + pPoint->color[3] = 0.0f; + } + + if (mix_e_color[3]) { + pPoint->e_color[3] = mix_e_color[3] * divisor; + mul_v3_v3fl(pPoint->e_color, mix_e_color, divisor / pPoint->e_color[3]); + } + else { + pPoint->e_color[3] = 0.0f; + } + + pPoint->wetness = mix_wetness / numOfNeighs; +} + +static void dynamicPaint_doBorderStep(DynamicPaintSurface *surface) +{ + PaintSurfaceData *sData = surface->data; + + if (!sData->adj_data || !sData->adj_data->border) + return; + + /* Don't use prevPoint, relying on the condition that neighbors are never border pixels. */ + DynamicPaintEffectData data = { + .surface = surface + }; + + BLI_task_parallel_range( + 0, sData->adj_data->total_border, &data, dynamic_paint_border_cb, sData->adj_data->total_border > 1000); +} + static void dynamic_paint_wave_step_cb(void *userdata, const int index) { const DynamicPaintEffectData *data = userdata; @@ -5636,6 +5849,11 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su if (force) MEM_freeN(force); } + + /* paint island border pixels */ + if (surface->type == MOD_DPAINT_SURFACE_T_PAINT) { + dynamicPaint_doBorderStep(surface); + } } return ret; From c937c3af460c9e91524b8dd70c9bdb98085af86d Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 3 Jan 2017 19:13:02 +0300 Subject: [PATCH 502/590] Dynamic Paint: provide margin of error for linking neighbors across seams. The code requires the pixel on the other side of the seam to be assigned precisely to the expected triangle. This can cause false negatives around vertices, where a pixel is likely to touch multiple triangles and thus cannot be said to unambiguously belong to any one of them, so check distance to the intended triangle and accept the result if it's close. --- .../blender/blenkernel/intern/dynamicpaint.c | 32 +++++++++++++++++-- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 4f204f2892f..9e3f123d5d8 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2302,6 +2302,24 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in #undef JITTER_SAMPLES +static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri, const MLoopUV *mloopuv, int tri_index, const float point[2]) +{ + float min_distance = FLT_MAX; + + for (int i = 0; i < 3; i++) { + const float dist_squared = dist_squared_to_line_segment_v2( + point, + mloopuv[mlooptri[tri_index].tri[(i + 0)]].uv, + mloopuv[mlooptri[tri_index].tri[(i + 1) % 3]].uv + ); + + if (dist_squared < min_distance) + min_distance = dist_squared; + } + + return min_distance; +} + /* Tries to find the neighboring pixel in given (uv space) direction. * Result is used by effect system to move paint on the surface. * @@ -2510,9 +2528,6 @@ static int dynamic_paint_find_neighbour_pixel( /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */ if (final_index == (px + w * py)) return NOT_FOUND; - /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */ - if (tempPoints[final_index].tri_index != target_tri) - return NOT_FOUND; /* If final point is an "edge pixel", use it's "real" neighbor instead */ if (tempPoints[final_index].neighbour_pixel != -1) { @@ -2523,6 +2538,17 @@ static int dynamic_paint_find_neighbour_pixel( return NOT_FOUND; } + /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */ + if (tempPoints[final_index].tri_index != target_tri) { + /* Check if it's close enough to likely touch the intended triangle. Any triangle + * becomes thinner than a pixel at its vertices, so robustness requires some margin. */ + const float final_pt[2] = { ((final_index % w) + 0.5f) / w, ((final_index / w) + 0.5f) / h }; + const float threshold = SQUARE(0.7f) / (w * h); + + if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold) + return NOT_FOUND; + } + return final_index; } } From d464fb0996d71cafcde865657affd145518108ab Mon Sep 17 00:00:00 2001 From: Alexander Gavrilov Date: Tue, 3 Jan 2017 19:11:59 +0300 Subject: [PATCH 503/590] Dynamic Paint: recursively search for island border edges. It is quite likely in a triangulated mesh that the actual island edge belongs to a different triangle than the current pixel; for example consider corners of a triangulated axis aligned rectangle face that have the additional edge: a pixel there will have to be assigned to one of the triangles, but one of the edges of the original rectangle can only be accessed through the other triangle. Thus for robust operation it is necessary to do a recursive search. The search is limited by requiring that it only goes through edges that bring it closer to the target point, and also by depth as a safeguard. Differential Revision: https://developer.blender.org/D2409 --- .../blender/blenkernel/intern/dynamicpaint.c | 286 ++++++++++-------- 1 file changed, 165 insertions(+), 121 deletions(-) diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 9e3f123d5d8..de3dfd772f6 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -2320,6 +2320,18 @@ static float dist_squared_to_looptri_uv_edges(const MLoopTri *mlooptri, const ML return min_distance; } +typedef struct DynamicPaintFindIslandBorderData { + const MeshElemMap *vert_to_looptri_map; + int w, h, px, py; + + int best_index; + float best_weight; +} DynamicPaintFindIslandBorderData; + +static void dynamic_paint_find_island_border( + const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata, + int tri_index, const float pixel[2], int in_edge, int depth); + /* Tries to find the neighboring pixel in given (uv space) direction. * Result is used by effect system to move paint on the surface. * @@ -2370,164 +2382,162 @@ static int dynamic_paint_find_neighbour_pixel( * TODO: Implement something more accurate / optimized? */ { - const MLoop *mloop = data->mloop; - const MLoopTri *mlooptri = data->mlooptri; - const MLoopUV *mloopuv = data->mloopuv; - - /* Get closest edge to that subpixel on UV map */ + DynamicPaintFindIslandBorderData bdata = { + .vert_to_looptri_map = vert_to_looptri_map, + .w = w, .h = h, .px = px, .py = py, + .best_index = NOT_FOUND, .best_weight = 1.0f + }; float pixel[2]; - /* distances only used for comparison */ - float dist_squared, t_dist_squared; - - int edge1_index, edge2_index; - int e1_index, e2_index, target_tri; - float closest_point[2], lambda, dir_vec[2]; - int target_uv1 = 0, target_uv2 = 0, final_pixel[2], final_index; - - const float *s_uv1, *s_uv2, *t_uv1, *t_uv2; pixel[0] = ((float)(px + neighX[n_index]) + 0.5f) / (float)w; pixel[1] = ((float)(py + neighY[n_index]) + 0.5f) / (float)h; - /* - * Find closest edge to that pixel - */ + /* Do a small recursive search for the best island edge. */ + dynamic_paint_find_island_border(data, &bdata, cPoint->tri_index, pixel, -1, 5); - /* Dist to first edge */ - e1_index = cPoint->v1; - e2_index = cPoint->v2; - edge1_index = 0; - edge2_index = 1; - dist_squared = dist_squared_to_line_segment_v2( - pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv); + return bdata.best_index; + } +} - /* Dist to second edge */ - t_dist_squared = dist_squared_to_line_segment_v2( - pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv); - if (t_dist_squared < dist_squared) { - e1_index = cPoint->v2; - e2_index = cPoint->v3; - edge1_index = 1; - edge2_index = 2; - dist_squared = t_dist_squared; - } +static void dynamic_paint_find_island_border( + const DynamicPaintCreateUVSurfaceData *data, DynamicPaintFindIslandBorderData *bdata, + int tri_index, const float pixel[2], int in_edge, int depth) +{ + const MLoop *mloop = data->mloop; + const MLoopTri *mlooptri = data->mlooptri; + const MLoopUV *mloopuv = data->mloopuv; - /* Dist to third edge */ - t_dist_squared = dist_squared_to_line_segment_v2( - pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv); - if (t_dist_squared < dist_squared) { - e1_index = cPoint->v3; - e2_index = cPoint->v1; - edge1_index = 2; - edge2_index = 0; - dist_squared = t_dist_squared; - } + const unsigned int *loop_idx = mlooptri[tri_index].tri; - /* - * Now find another face that is linked to that edge - */ - target_tri = -1; + /* Enumerate all edges of the triangle, rotating the vertex list accordingly. */ + for (int edge_idx = 0; edge_idx < 3; edge_idx++) { + /* but not the edge we have just recursed through */ + if (edge_idx == in_edge) + continue; + + float uv0[2], uv1[2], uv2[2]; + + copy_v2_v2(uv0, mloopuv[loop_idx[(edge_idx + 0)]].uv); + copy_v2_v2(uv1, mloopuv[loop_idx[(edge_idx + 1) % 3]].uv); + copy_v2_v2(uv2, mloopuv[loop_idx[(edge_idx + 2) % 3]].uv); + + /* Verify the target point is on the opposite side of the edge from the third triangle + * vertex, to ensure that we always move closer to the goal point. */ + const float sidep = line_point_side_v2(uv0, uv1, pixel); + const float side2 = line_point_side_v2(uv0, uv1, uv2); + + if (side2 == 0.0f) + continue; + + /* Hack: allow all edges of the original triangle */ + const bool correct_side = (in_edge == -1) || (sidep < 0 && side2 > 0) || (sidep > 0 && side2 < 0); + + /* Allow exactly on edge for the non-recursive case */ + if (!correct_side && sidep != 0.0f) + continue; + + /* Now find another face that is linked to that edge. */ + const int vert0 = mloop[loop_idx[(edge_idx + 0)]].v; + const int vert1 = mloop[loop_idx[(edge_idx + 1) % 3]].v; /* Use a pre-computed vert-to-looptri mapping, speeds up things a lot compared to looping over all loopti. */ - for (int i = 0; i < vert_to_looptri_map[e1_index].count; i++) { - const int lt_index = vert_to_looptri_map[e1_index].indices[i]; - const int v0 = mloop[mlooptri[lt_index].tri[0]].v; - const int v1 = mloop[mlooptri[lt_index].tri[1]].v; - const int v2 = mloop[mlooptri[lt_index].tri[2]].v; + const MeshElemMap *map = &bdata->vert_to_looptri_map[vert0]; - BLI_assert(ELEM(e1_index, v0, v1, v2)); + bool found_other = false; + int target_tri = -1; + int target_edge = -1; - if (ELEM(e2_index, v0, v1, v2)) { - if (lt_index == cPoint->tri_index) - continue; + float ouv0[2], ouv1[2]; - target_tri = lt_index; + for (int i = 0; i < map->count && !found_other; i++) { + const int lt_index = map->indices[i]; - /* Get edge UV index */ - target_uv1 = (e1_index == v0) ? 0 : ((e1_index == v1) ? 1 : 2); - target_uv2 = (e2_index == v0) ? 0 : ((e2_index == v1) ? 1 : 2); - break; + if (lt_index == tri_index) + continue; + + const unsigned int *other_loop_idx = mlooptri[lt_index].tri; + + /* Check edges for match, looping in the same order as the outer loop. */ + for (int j = 0; j < 3; j++) + { + const int overt0 = mloop[other_loop_idx[(j + 0)]].v; + const int overt1 = mloop[other_loop_idx[(j + 1) % 3]].v; + + /* Allow for swapped vertex order */ + if (overt0 == vert0 && overt1 == vert1) { + found_other = true; + copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 0)]].uv); + copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 1) % 3]].uv); + } + else if (overt0 == vert1 && overt1 == vert0) { + found_other = true; + copy_v2_v2(ouv1, mloopuv[other_loop_idx[(j + 0)]].uv); + copy_v2_v2(ouv0, mloopuv[other_loop_idx[(j + 1) % 3]].uv); + } + + if (found_other) { + target_tri = lt_index; + target_edge = j; + break; + } } } - /* If none found pixel is on mesh edge */ - if (target_tri == -1) - return ON_MESH_EDGE; + if (!found_other) { + if (bdata->best_index < 0) + bdata->best_index = ON_MESH_EDGE; - /* - * If target face is connected in UV space as well, just use original index - */ - s_uv1 = mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv; - s_uv2 = mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv; - t_uv1 = mloopuv[mlooptri[target_tri].tri[target_uv1]].uv; - t_uv2 = mloopuv[mlooptri[target_tri].tri[target_uv2]].uv; + continue; + } - //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]); - - if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) && - (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) || - ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) && - (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]))) - { - final_index = x + w * y; - - /* If not an active pixel, bail out */ - if (tempPoints[final_index].tri_index == -1) - return NOT_FOUND; - - /* If final point is an "edge pixel", use it's "real" neighbor instead */ - if (tempPoints[final_index].neighbour_pixel != -1) { - final_index = tempPoints[final_index].neighbour_pixel; - - /* If we ended up to our origin point */ - if (final_index == (px + w * py)) - return NOT_FOUND; + /* If this edge is connected in UV space too, recurse */ + if (equals_v2v2(uv0, ouv0) && equals_v2v2(uv1, ouv1)) { + if (depth > 0 && correct_side) { + dynamic_paint_find_island_border(data, bdata, target_tri, pixel, target_edge, depth - 1); } - return final_index; + continue; } + /* Otherwise try to map to the other side of the edge. + * First check if there already is a better solution. */ + const float dist_squared = dist_squared_to_line_segment_v2(pixel, uv0, uv1); + + if (bdata->best_index >= 0 && dist_squared >= bdata->best_weight) + continue; + /* * Find a point that is relatively at same edge position * on this other face UV */ - lambda = closest_to_line_v2( - closest_point, pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv); + float closest_point[2], dir_vec[2], tgt_pixel[2]; + + float lambda = closest_to_line_v2(closest_point, pixel, uv0, uv1); CLAMP(lambda, 0.0f, 1.0f); - sub_v2_v2v2( - dir_vec, - mloopuv[mlooptri[target_tri].tri[target_uv2]].uv, - mloopuv[mlooptri[target_tri].tri[target_uv1]].uv); + sub_v2_v2v2(dir_vec, ouv1, ouv0); + madd_v2_v2v2fl(tgt_pixel, ouv0, dir_vec, lambda); - mul_v2_fl(dir_vec, lambda); + int w = bdata->w, h = bdata->h, px = bdata->px, py = bdata->py; - copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv); - add_v2_v2(pixel, dir_vec); - pixel[0] = (pixel[0] * (float)w); - pixel[1] = (pixel[1] * (float)h); - - final_pixel[0] = (int)floorf(pixel[0]); - final_pixel[1] = (int)floorf(pixel[1]); + int final_pixel[2] = { (int)floorf(tgt_pixel[0] * w), (int)floorf(tgt_pixel[1] * h) }; /* If current pixel uv is outside of texture */ if (final_pixel[0] < 0 || final_pixel[0] >= w || final_pixel[1] < 0 || final_pixel[1] >= h) - return OUT_OF_TEXTURE; + { + if (bdata->best_index == NOT_FOUND) + bdata->best_index = OUT_OF_TEXTURE; - final_index = final_pixel[0] + w * final_pixel[1]; + continue; + } + + const PaintUVPoint *tempPoints = data->tempPoints; + int final_index = final_pixel[0] + w * final_pixel[1]; /* If we ended up to our origin point ( mesh has smaller than pixel sized faces) */ if (final_index == (px + w * py)) - return NOT_FOUND; + continue; /* If final point is an "edge pixel", use it's "real" neighbor instead */ if (tempPoints[final_index].neighbour_pixel != -1) { @@ -2535,7 +2545,7 @@ static int dynamic_paint_find_neighbour_pixel( /* If we ended up to our origin point */ if (final_index == (px + w * py)) - return NOT_FOUND; + continue; } /* If found pixel still lies on wrong face ( mesh has smaller than pixel sized faces) */ @@ -2546,10 +2556,11 @@ static int dynamic_paint_find_neighbour_pixel( const float threshold = SQUARE(0.7f) / (w * h); if (dist_squared_to_looptri_uv_edges(mlooptri, mloopuv, tempPoints[final_index].tri_index, final_pt) > threshold) - return NOT_FOUND; + continue; } - return final_index; + bdata->best_index = final_index; + bdata->best_weight = dist_squared; } } @@ -2858,6 +2869,39 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo } } } + +#if 0 + /* ----------------------------------------------------------------- + * For debug, write a dump of adjacency data to a file. + * -----------------------------------------------------------------*/ + FILE *dump_file = fopen("dynpaint-adj-data.txt", "w"); + int *tmp = MEM_callocN(sizeof(int) * active_points, "tmp"); + for (int ty = 0; ty < h; ty++) { + for (int tx = 0; tx < w; tx++) { + const int index = tx + w * ty; + if (tempPoints[index].tri_index != -1) + tmp[final_index[index]] = index; + } + } + for (int ty = 0; ty < h; ty++) { + for (int tx = 0; tx < w; tx++) { + const int index = tx + w * ty; + const int fidx = final_index[index]; + + if (tempPoints[index].tri_index != -1) { + int nidx = tempPoints[index].neighbour_pixel; + fprintf(dump_file, "%d\t%d,%d\t%u\t%d,%d\t%d\t", fidx, tx, h-1-ty, tempPoints[index].tri_index, nidx<0?-1:(nidx%w), nidx<0?-1:h-1-(nidx/w), ed->flags[fidx]); + for (int i = 0; i < ed->n_num[fidx]; i++) { + int tgt = tmp[ed->n_target[ed->n_index[fidx]+i]]; + fprintf(dump_file, "%s%d,%d", i?" ":"", tgt%w, h-1-tgt/w); + } + fprintf(dump_file, "\n"); + } + } + } + MEM_freeN(tmp); + fclose(dump_file); +#endif } } From bd6bd6275363017bacbbdeff29eb3a4a323ee48a Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Thu, 12 Jan 2017 23:36:08 -0500 Subject: [PATCH 504/590] Fix small spelling error --- source/blender/makesrna/intern/rna_mesh_api.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index cd48bc1a3df..ff9873fb3d1 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -241,7 +241,7 @@ void RNA_api_mesh(StructRNA *srna) RNA_def_function_ui_description(func, "Free split vertex normals"); func = RNA_def_function(srna, "split_faces", "BKE_mesh_split_faces"); - RNA_def_function_ui_description(func, "Spli faces based on the edge angle"); + RNA_def_function_ui_description(func, "Split faces based on the edge angle"); func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents"); RNA_def_function_flag(func, FUNC_USE_REPORTS); @@ -320,4 +320,3 @@ void RNA_api_mesh(StructRNA *srna) } #endif - From 3160472a66fb66ceee18fcb8d08d8a785a4b34d5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 13 Jan 2017 10:53:01 +0100 Subject: [PATCH 505/590] Cycles: Avoid shadowing in BVH code Run into some nasty bugs while trying various things here. Wouldn't mind enabling -Wshadow for Cycles actually.. --- intern/cycles/bvh/bvh_build.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 48f1d063fd1..66e9ecae327 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -165,12 +165,13 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, /* motion curve */ if(curve_attr_mP) { - size_t mesh_size = mesh->curve_keys.size(); - size_t steps = mesh->motion_steps - 1; - float3 *key_steps = curve_attr_mP->data_float3(); + const size_t mesh_size = mesh->curve_keys.size(); + const size_t num_steps = mesh->motion_steps - 1; + const float3 *key_steps = curve_attr_mP->data_float3(); - for(size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bounds); + for(size_t step = 0; step < num_steps; step++) { + curve.bounds_grow(k, key_steps + step*mesh_size, &mesh->curve_radius[0], bounds); + } type = PRIMITIVE_MOTION_CURVE; } From 807b1a262ff36c2e40203f52b31bd4be523980b9 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 13 Jan 2017 10:59:34 +0100 Subject: [PATCH 506/590] Cycles: Simplify some code in Curve BVH reference fill makes code slightly shorter and uses idea of const qualifiers. --- intern/cycles/bvh/bvh_build.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 66e9ecae327..036500843c7 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -156,12 +156,13 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, size_t num_curves = mesh->num_curves(); for(uint j = 0; j < num_curves; j++) { - Mesh::Curve curve = mesh->get_curve(j); + const Mesh::Curve curve = mesh->get_curve(j); PrimitiveType type = PRIMITIVE_CURVE; + const float *curve_radius = &mesh->curve_radius[0]; for(int k = 0; k < curve.num_keys - 1; k++) { BoundBox bounds = BoundBox::empty; - curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bounds); + curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds); /* motion curve */ if(curve_attr_mP) { @@ -170,7 +171,7 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, const float3 *key_steps = curve_attr_mP->data_float3(); for(size_t step = 0; step < num_steps; step++) { - curve.bounds_grow(k, key_steps + step*mesh_size, &mesh->curve_radius[0], bounds); + curve.bounds_grow(k, key_steps + step*mesh_size, curve_radius, bounds); } type = PRIMITIVE_MOTION_CURVE; From 14f6e27f6a4875243c78f9942e3ba199fedb6d3e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 13 Jan 2017 15:24:56 +0100 Subject: [PATCH 507/590] Cycles: Cleanup, style --- intern/cycles/app/cycles_xml.cpp | 2 +- intern/cycles/blender/blender_object_cull.cpp | 2 +- intern/cycles/render/session.cpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index 29a68bf272e..35a30ae683f 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -523,7 +523,7 @@ static void xml_read_mesh(const XMLReadState& state, pugi::xml_node node) /* we don't yet support arbitrary attributes, for now add vertex * coordinates as generated coordinates if requested */ - if (mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) { + if(mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) { Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); memcpy(attr->data_float3(), mesh->verts.data(), sizeof(float3)*mesh->verts.size()); } diff --git a/intern/cycles/blender/blender_object_cull.cpp b/intern/cycles/blender/blender_object_cull.cpp index b8582df0f93..08918dd1a49 100644 --- a/intern/cycles/blender/blender_object_cull.cpp +++ b/intern/cycles/blender/blender_object_cull.cpp @@ -43,7 +43,7 @@ BlenderObjectCulling::BlenderObjectCulling(Scene *scene, BL::Scene& b_scene) camera_cull_margin_ = get_float(cscene, "camera_cull_margin"); distance_cull_margin_ = get_float(cscene, "distance_cull_margin"); - if (distance_cull_margin_ == 0.0f) { + if(distance_cull_margin_ == 0.0f) { use_scene_distance_cull_ = false; } } diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 33721048722..73caf93ea00 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -834,11 +834,11 @@ void Session::update_status_time(bool show_pause, bool show_done) substatus = string_printf("Path Tracing Tile %d/%d", tile, num_tiles); - if(device->show_samples() || (is_cpu && is_last_tile)) - { + if(device->show_samples() || (is_cpu && is_last_tile)) { /* Some devices automatically support showing the sample number: * - CUDADevice - * - OpenCLDevice when using the megakernel (the split kernel renders multiple samples at the same time, so the current sample isn't really defined) + * - OpenCLDevice when using the megakernel (the split kernel renders multiple + * samples at the same time, so the current sample isn't really defined) * - CPUDevice when using one thread * For these devices, the current sample is always shown. * From e5a665fe24aa4783ada62d28f28ecfb7d70b2f7b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 13 Jan 2017 15:41:20 +0100 Subject: [PATCH 508/590] Cycles: Fix wrong transparent shadows for motion blur hair This was a missing bit from b53ce9a. --- intern/cycles/kernel/bvh/bvh_shadow_all.h | 7 ++++--- intern/cycles/kernel/bvh/qbvh_shadow_all.h | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/intern/cycles/kernel/bvh/bvh_shadow_all.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h index 294362ea995..df33a86bb18 100644 --- a/intern/cycles/kernel/bvh/bvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h @@ -187,7 +187,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* primitive intersection */ while(prim_addr < prim_addr2) { - kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type); bool hit; @@ -222,6 +222,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_HAIR) case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { + const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr); if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { hit = bvh_cardinal_curve_intersect(kg, isect_array, @@ -231,7 +232,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, object, prim_addr, ray->time, - type, + curve_type, NULL, 0, 0); } @@ -244,7 +245,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, object, prim_addr, ray->time, - type, + curve_type, NULL, 0, 0); } diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index 5f4d06f12ea..b2e99725626 100644 --- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -262,7 +262,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Primitive intersection. */ while(prim_addr < prim_addr2) { - kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + kernel_assert((kernel_tex_fetch(__prim_type, prim_addr) & PRIMITIVE_ALL) == p_type); bool hit; @@ -297,6 +297,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_HAIR) case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { + const uint curve_type = kernel_tex_fetch(__prim_type, prim_addr); if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { hit = bvh_cardinal_curve_intersect(kg, isect_array, @@ -306,7 +307,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, object, prim_addr, ray->time, - type, + curve_type, NULL, 0, 0); } @@ -319,7 +320,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, object, prim_addr, ray->time, - type, + curve_type, NULL, 0, 0); } From 646aa40cf707b866515ff3c5118d49ad964f1109 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 13 Jan 2017 18:12:56 +0100 Subject: [PATCH 509/590] Fix missing user when opening text from ID UI widget. Own mistake in recent fix for Text data-block usercount (rBa9163f7d2). Reported by @sergey over IRC, thanks. --- source/blender/editors/space_text/text_ops.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index df3620843ad..f603fa1b0f1 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -248,6 +248,7 @@ static int text_open_exec(bContext *C, wmOperator *op) pprop = op->customdata; if (pprop->prop) { + id_us_ensure_real(&text->id); RNA_id_pointer_create(&text->id, &idptr); RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr); RNA_property_update(C, &pprop->ptr, pprop->prop); From 0a446d7276e74e3c8472453948204ca6463d158e Mon Sep 17 00:00:00 2001 From: Luca Rood Date: Thu, 22 Dec 2016 02:13:03 -0200 Subject: [PATCH 510/590] Add 3d to 2d plane mapping functions to math lib This adds two functions to project 3d coordinates onto a 3d plane, to get 2d coordinates, essentially eliminating the plane's normal axis from the coordinates. Reviewed By: mont29 Differential Revision: https://developer.blender.org/D2460 --- source/blender/blenlib/BLI_math_geom.h | 2 ++ source/blender/blenlib/intern/math_geom.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index d33c2cb3279..e3635be671f 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -389,6 +389,8 @@ void box_minmax_bounds_m4(float min[3], float max[3], void map_to_tube(float *r_u, float *r_v, const float x, const float y, const float z); void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const float z); +void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3]); +void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const float axis[3], const float angle); /********************************** Normals **********************************/ diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 74ede1e7559..8f5d84dfa08 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -4048,6 +4048,26 @@ void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const f } } +void map_to_plane_v2_v3v3(float r_co[2], const float co[3], const float no[3]) +{ + float target[3] = {0.0f, 0.0f, 1.0f}; + float axis[3]; + + cross_v3_v3v3(axis, no, target); + normalize_v3(axis); + + map_to_plane_axis_angle_v2_v3v3fl(r_co, co, axis, angle_normalized_v3v3(no, target)); +} + +void map_to_plane_axis_angle_v2_v3v3fl(float r_co[2], const float co[3], const float axis[3], const float angle) +{ + float tmp[3]; + + rotate_normalized_v3_v3v3fl(tmp, co, axis, angle); + + copy_v2_v2(r_co, tmp); +} + /********************************* Normals **********************************/ void accumulate_vertex_normals_tri( From d3e4eecaa5f1c815e3ecfda5461a099efffc8b65 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 16 Jan 2017 17:54:39 +0100 Subject: [PATCH 511/590] Cycles: Cleanup, avoid shadowing --- intern/cycles/bvh/bvh_build.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 036500843c7..038070cba4c 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -130,12 +130,13 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, /* motion triangles */ if(attr_mP) { - size_t mesh_size = mesh->verts.size(); - size_t steps = mesh->motion_steps - 1; - float3 *vert_steps = attr_mP->data_float3(); + const size_t mesh_size = mesh->verts.size(); + const size_t num_steps = mesh->motion_steps - 1; + const float3 *vert_steps = attr_mP->data_float3(); - for(size_t i = 0; i < steps; i++) - t.bounds_grow(vert_steps + i*mesh_size, bounds); + for(size_t step = 0; step < num_steps; step++) { + t.bounds_grow(vert_steps + step*mesh_size, bounds); + } type = PRIMITIVE_MOTION_TRIANGLE; } From 92fbcbb4bf0ec613907ebf20c3874ce684243e86 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 16 Jan 2017 17:55:41 +0100 Subject: [PATCH 512/590] Cycles: Cleanup, spelling --- intern/cycles/bvh/bvh_build.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 038070cba4c..8cf1495b33d 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -925,7 +925,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, BVHNode *inner = new InnerNode(inner_bounds, leaves[1], leaves[2]); return new InnerNode(range.bounds(), leaves[0], inner); } else { - /* Shpuld be doing more branches if more primitive types added. */ + /* Should be doing more branches if more primitive types added. */ assert(num_leaves <= 5); BoundBox inner_bounds_a = merge(leaves[0]->m_bounds, leaves[1]->m_bounds); BoundBox inner_bounds_b = merge(leaves[2]->m_bounds, leaves[3]->m_bounds); From 702bc5ba26d5ff2a4da9e92cabb2fa34ed3f2312 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 16 Jan 2017 14:03:31 +0100 Subject: [PATCH 513/590] Fix T50393: Flip names working just on one side when both are selected. Just store bones that could not get renamed to desired flipped name on the first try into a temp list, and try to rename them a second time. This is rather simple solution, will induce 'over numbering' in case you flip a bone to another unselected bone's name (since number will be incremented in both rename attempts), but think this is acceptable minor glitch, for a corner case situation that does not have any good resolution anyway. Also, set `strip_numbers` option of `BKE_deform_flip_side_name` to false, otherwise chains of bones with same names would get their numbers completely messed up after name flipping. Based on work by @dfelinto in D2456 (https://developer.blender.org/D2456), thanks. --- .../editors/armature/armature_naming.c | 68 +++++++++++++++++-- source/blender/editors/armature/pose_edit.c | 16 +++-- source/blender/editors/include/ED_armature.h | 1 + 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 56dbdb3a639..4cffd99ce1b 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" +#include "BLI_utildefines.h" #include "BLT_translation.h" @@ -297,6 +298,55 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n } } +typedef struct BoneFlipNameData { + struct BoneFlipNameData *next, *prev; + char *name; + char name_flip[MAXBONENAME]; +} BoneFlipNameData; + +/** + * Renames (by flipping) all selected bones at once. + * + * This way if we are flipping related bones (e.g., Bone.L, Bone.R) at the same time + * all the bones are safely renamed, without conflicting with each other. + * + * \param arm Armature the bones belong to + * \param bones ListBase of BoneConflict elems, populated via ED_armature_bones_flip_names_add + */ +void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names) +{ + ListBase bones_names_conflicts = {NULL}; + BoneFlipNameData *bfn; + + /* First pass: generate flip names, and blindly rename. + * If rename did not yield expected result, store both bone's name and expected flipped one into temp list + * for second pass. */ + for (LinkData *link = bones_names->first; link; link = link->next) { + char name_flip[MAXBONENAME]; + char *name = link->data; + + /* Do not strip numbers, otherwise we'll end up with completely mismatched names in cases like + * Bone.R, Bone.R.001, Bone.R.002, etc. */ + BKE_deform_flip_side_name(name_flip, name, false); + + ED_armature_bone_rename(arm, name, name_flip); + + if (!STREQ(name, name_flip)) { + bfn = alloca(sizeof(BoneFlipNameData)); + bfn->name = name; + BLI_strncpy(bfn->name_flip, name_flip, sizeof(bfn->name_flip)); + BLI_addtail(&bones_names_conflicts, bfn); + } + } + + /* Second pass to handle the bones that have naming conflicts with other bones. + * Note that if the other bone was not selected, its name was not flipped, so conflict remains and that second + * rename simply generates a new numbered alternative name. */ + for (bfn = bones_names_conflicts.first; bfn; bfn = bfn->next) { + ED_armature_bone_rename(arm, bfn->name, bfn->name_flip); + } +} + /* ************************************************** */ /* Bone Renaming - EditMode */ @@ -304,20 +354,24 @@ static int armature_flip_names_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = CTX_data_edit_object(C); bArmature *arm; - + /* paranoia checks */ - if (ELEM(NULL, ob, ob->pose)) + if (ELEM(NULL, ob, ob->pose)) return OPERATOR_CANCELLED; + arm = ob->data; - - /* loop through selected bones, auto-naming them */ + + ListBase bones_names= {NULL}; + CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones) { - char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, ebone->name, true); - ED_armature_bone_rename(arm, ebone->name, name_flip); + BLI_addtail(&bones_names, BLI_genericNodeN(ebone->name)); } CTX_DATA_END; + + ED_armature_bones_flip_names(arm, &bones_names); + + BLI_freelistN(&bones_names); /* since we renamed stuff... */ DAG_id_tag_update(&ob->id, OB_RECALC_DATA); diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 322476dcca0..86b7271bfff 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -593,20 +593,24 @@ static int pose_flip_names_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); bArmature *arm; - + /* paranoia checks */ if (ELEM(NULL, ob, ob->pose)) return OPERATOR_CANCELLED; + arm = ob->data; - - /* loop through selected bones, auto-naming them */ + + ListBase bones_names = {NULL}; + CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) { - char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, pchan->name, true); - ED_armature_bone_rename(arm, pchan->name, name_flip); + BLI_addtail(&bones_names, BLI_genericNodeN(pchan->name)); } CTX_DATA_END; + + ED_armature_bones_flip_names(arm, &bones_names); + + BLI_freelistN(&bones_names); /* since we renamed stuff... */ DAG_id_tag_update(&ob->id, OB_RECALC_DATA); diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 904132b8876..7ad61671b1b 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -171,6 +171,7 @@ void create_vgroups_from_armature(struct ReportList *reports, struct Scene *scen /* if bone is already in list, pass it as param to ignore it */ void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone); void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep); +void ED_armature_bones_flip_names(struct bArmature *arm, struct ListBase *bones_names); void undo_push_armature(struct bContext *C, const char *name); From 3748defefe54ff63be2b755cabf70d934294137c Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 16 Jan 2017 14:06:26 +0100 Subject: [PATCH 514/590] Cleanup: remove unused & unimplemented `BLI_newname`. --- source/blender/blenlib/BLI_path_util.h | 1 - 1 file changed, 1 deletion(-) diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 1a626ff44bd..2eb7a8da951 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -94,7 +94,6 @@ bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename) AT bool BLI_uniquename(struct ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int len); bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name), void *arg, const char *defname, char delim, char *name, int name_len); -void BLI_newname(char *name, int add); int BLI_stringdec(const char *string, char *head, char *start, unsigned short *numlen); void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic); int BLI_split_name_num(char *left, int *nr, const char *name, const char delim); From b99798832300b40bcae87725d7e35321966e394c Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 16 Jan 2017 17:33:34 +0100 Subject: [PATCH 515/590] Cleanup/refactor: Add new BLI_string_util. Things like `BLI_uniquename` had nothing, but really nothing to do in BLI_path_util files! Also, got rid of length limitation in `BLI_uniquename_cb`, we can use alloca here to avoid overhead of malloc while keeping free size (within reasonable limits of course). --- source/blender/blenkernel/intern/action.c | 1 + source/blender/blenkernel/intern/anim_sys.c | 1 + source/blender/blenkernel/intern/constraint.c | 2 +- source/blender/blenkernel/intern/customdata.c | 3 +- source/blender/blenkernel/intern/deform.c | 2 +- .../blender/blenkernel/intern/dynamicpaint.c | 1 + source/blender/blenkernel/intern/fcurve.c | 1 + source/blender/blenkernel/intern/freestyle.c | 1 + source/blender/blenkernel/intern/gpencil.c | 1 + source/blender/blenkernel/intern/ipo.c | 1 + source/blender/blenkernel/intern/key.c | 1 + source/blender/blenkernel/intern/library.c | 1 + source/blender/blenkernel/intern/linestyle.c | 1 + source/blender/blenkernel/intern/mask.c | 2 +- source/blender/blenkernel/intern/mball.c | 1 + .../blenkernel/intern/mball_tessellate.c | 2 +- source/blender/blenkernel/intern/modifier.c | 3 +- source/blender/blenkernel/intern/nla.c | 2 +- source/blender/blenkernel/intern/node.c | 5 +- source/blender/blenkernel/intern/scene.c | 1 + .../blender/blenkernel/intern/seqmodifier.c | 2 +- source/blender/blenkernel/intern/tracking.c | 2 +- .../blender/blenkernel/intern/tracking_util.c | 2 +- source/blender/blenlib/BLI_path_util.h | 4 - source/blender/blenlib/BLI_string_utils.h | 58 +++++ source/blender/blenlib/CMakeLists.txt | 2 + source/blender/blenlib/intern/path_util.c | 159 -------------- source/blender/blenlib/intern/string_utils.c | 207 ++++++++++++++++++ .../blenloader/intern/versioning_260.c | 1 + source/blender/collada/AnimationImporter.cpp | 2 +- .../editors/armature/armature_naming.c | 1 + source/blender/editors/armature/pose_lib.c | 1 + source/blender/editors/gpencil/gpencil_data.c | 1 + source/blender/editors/object/object_edit.c | 1 + .../blender/editors/space_logic/logic_ops.c | 1 + .../editors/space_logic/logic_window.c | 2 +- .../editors/space_outliner/outliner_draw.c | 1 + .../transform/transform_orientations.c | 2 +- source/blender/makesrna/intern/rna_actuator.c | 3 +- .../blender/makesrna/intern/rna_controller.c | 1 + source/blender/makesrna/intern/rna_gpencil.c | 1 + source/blender/makesrna/intern/rna_key.c | 1 + .../blender/makesrna/intern/rna_linestyle.c | 3 + source/blender/makesrna/intern/rna_particle.c | 2 + source/blender/makesrna/intern/rna_pose.c | 1 + source/blender/makesrna/intern/rna_property.c | 1 + source/blender/makesrna/intern/rna_scene.c | 1 + source/blender/makesrna/intern/rna_sensor.c | 1 + .../nodes/node_composite_outputFile.c | 2 +- 49 files changed, 319 insertions(+), 180 deletions(-) create mode 100644 source/blender/blenlib/BLI_string_utils.h create mode 100644 source/blender/blenlib/intern/string_utils.c diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index dcbb667adca..2ade4cf08d5 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -44,6 +44,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 21279392392..0b637355ecf 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -43,6 +43,7 @@ #include "BLI_alloca.h" #include "BLI_dynstr.h" #include "BLI_listbase.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index cb74dbcd8d1..58ad171ee20 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -42,7 +42,7 @@ #include "BLI_math.h" #include "BLI_kdopbvh.h" #include "BLI_utildefines.h" - +#include "BLI_string_utils.h" #include "BLT_translation.h" #include "DNA_armature_types.h" diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 612f1f477e1..98d37fb07bf 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -45,8 +45,9 @@ #include "DNA_ID.h" #include "BLI_utildefines.h" -#include "BLI_string.h" #include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_math.h" #include "BLI_math_color_blend.h" #include "BLI_mempool.h" diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 7052e0a7d25..abc14c42d40 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -45,8 +45,8 @@ #include "BLI_listbase.h" #include "BLI_math.h" -#include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index de3dfd772f6..dc9f3b57f1f 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -32,6 +32,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_kdtree.h" +#include "BLI_string_utils.h" #include "BLI_task.h" #include "BLI_threads.h" #include "BLI_utildefines.h" diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index a89d423e7a6..c67a61a5aad 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -47,6 +47,7 @@ #include "BLI_math.h" #include "BLI_easing.h" #include "BLI_threads.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c index 21fc1674dc5..0a0b023df82 100644 --- a/source/blender/blenkernel/intern/freestyle.c +++ b/source/blender/blenkernel/intern/freestyle.c @@ -40,6 +40,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_string_utils.h" // function declarations static FreestyleLineSet *alloc_lineset(void); diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index cd2eac078cf..30fc8915d46 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -39,6 +39,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" #include "BLI_math_vector.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c index 730d5a93758..f3a85dcee2b 100644 --- a/source/blender/blenkernel/intern/ipo.c +++ b/source/blender/blenkernel/intern/ipo.c @@ -62,6 +62,7 @@ #include "BLI_blenlib.h" #include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 6cdeaf5e59b..8a7c1dd2833 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -38,6 +38,7 @@ #include "BLI_blenlib.h" #include "BLI_math_vector.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 64535f229a9..ea613795249 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -76,6 +76,7 @@ #include "BLI_ghash.h" #include "BLI_linklist.h" #include "BLI_memarena.h" +#include "BLI_string_utils.h" #include "BLI_threads.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index bd21215f91e..1eb909bd9f9 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -41,6 +41,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BKE_context.h" diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 21023d9f53c..6f23b82c6df 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -36,8 +36,8 @@ #include "BLI_utildefines.h" #include "BLI_ghash.h" -#include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_listbase.h" #include "BLI_math.h" diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index 8d024ea9aa5..97033a9555d 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -49,6 +49,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BKE_global.h" diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index 2068854421f..5c0b09f0ff0 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -41,8 +41,8 @@ #include "DNA_scene_types.h" #include "BLI_listbase.h" -#include "BLI_path_util.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLI_memarena.h" diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 41e4c21d814..2276d56b9c6 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -49,10 +49,11 @@ #include "DNA_object_types.h" #include "BLI_utildefines.h" -#include "BLI_path_util.h" #include "BLI_listbase.h" #include "BLI_linklist.h" +#include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index c321bc92a71..148fc3827e0 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -40,9 +40,9 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_path_util.h" #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_ghash.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index f16e8f328d4..3f3b4896653 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -46,10 +46,11 @@ #include "DNA_world_types.h" #include "DNA_linestyle_types.h" -#include "BLI_string.h" -#include "BLI_math.h" #include "BLI_listbase.h" +#include "BLI_math.h" #include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 091b8100d27..39a97b08df1 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -56,6 +56,7 @@ #include "BLI_utildefines.h" #include "BLI_callbacks.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_threads.h" #include "BLI_task.h" diff --git a/source/blender/blenkernel/intern/seqmodifier.c b/source/blender/blenkernel/intern/seqmodifier.c index 95c6b7736e1..89c2f76c661 100644 --- a/source/blender/blenkernel/intern/seqmodifier.c +++ b/source/blender/blenkernel/intern/seqmodifier.c @@ -34,8 +34,8 @@ #include "MEM_guardedalloc.h" #include "BLI_listbase.h" -#include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLI_math.h" diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index 96ab8693122..990d250b854 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -49,8 +49,8 @@ #include "BLI_math.h" #include "BLI_math_base.h" #include "BLI_listbase.h" -#include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_threads.h" #include "BLT_translation.h" diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index a90b1dee927..c34da4f6814 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -42,8 +42,8 @@ #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_ghash.h" -#include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 2eb7a8da951..baa1f792018 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -91,12 +91,8 @@ bool BLI_testextensie_glob(const char *str, const char *ext_fnmatch) ATTR_NONNUL bool BLI_replace_extension(char *path, size_t maxlen, const char *ext) ATTR_NONNULL(); bool BLI_ensure_extension(char *path, size_t maxlen, const char *ext) ATTR_NONNULL(); bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename) ATTR_NONNULL(); -bool BLI_uniquename(struct ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int len); -bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name), - void *arg, const char *defname, char delim, char *name, int name_len); int BLI_stringdec(const char *string, char *head, char *start, unsigned short *numlen); void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic); -int BLI_split_name_num(char *left, int *nr, const char *name, const char delim); /* removes trailing slash */ void BLI_cleanup_file(const char *relabase, char *path) ATTR_NONNULL(2); diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h new file mode 100644 index 00000000000..81c06fbc20d --- /dev/null +++ b/source/blender/blenlib/BLI_string_utils.h @@ -0,0 +1,58 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 by the Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_STRING_UTILS_H__ +#define __BLI_STRING_UTILS_H__ + +/** \file BLI_string_utils.h + * \ingroup bli + */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#include "BLI_compiler_attrs.h" + +struct ListBase; + +typedef bool (*UniquenameCheckCallback)(void *arg, const char *name); + +int BLI_split_name_num(char *left, int *nr, const char *name, const char delim); + +bool BLI_uniquename_cb( + UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len); +bool BLI_uniquename( + struct ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* __BLI_STRING_UTILS_H__ */ diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 6e717a3ae7e..3277519c66e 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -109,6 +109,7 @@ set(SRC intern/string.c intern/string_cursor_utf8.c intern/string_utf8.c + intern/string_utils.c intern/system.c intern/task.c intern/threads.c @@ -195,6 +196,7 @@ set(SRC BLI_string.h BLI_string_cursor_utf8.h BLI_string_utf8.h + BLI_string_utils.h BLI_sys_types.h BLI_system.h BLI_task.h diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index f0d0bd00dea..6644e6605a1 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -63,9 +63,6 @@ #include "MEM_guardedalloc.h" -/* local */ -#define UNIQUE_NAME_MAX 128 - /* Declarations */ #ifdef WIN32 @@ -147,162 +144,6 @@ void BLI_stringenc(char *string, const char *head, const char *tail, unsigned sh sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail); } -/** - * Looks for a numeric suffix preceded by delim character on the end of - * name, puts preceding part into *left and value of suffix into *nr. - * Returns the length of *left. - * - * Foo.001 -> "Foo", 1 - * Returning the length of "Foo" - * - * \param left Where to return copy of part preceding delim - * \param nr Where to return value of numeric suffix - * \param name String to split - * \param delim Delimiter character - * \return Length of \a left - */ -int BLI_split_name_num(char *left, int *nr, const char *name, const char delim) -{ - const int name_len = strlen(name); - - *nr = 0; - memcpy(left, name, (name_len + 1) * sizeof(char)); - - /* name doesn't end with a delimiter "foo." */ - if ((name_len > 1 && name[name_len - 1] == delim) == 0) { - int a = name_len; - while (a--) { - if (name[a] == delim) { - left[a] = '\0'; /* truncate left part here */ - *nr = atol(name + a + 1); - /* casting down to an int, can overflow for large numbers */ - if (*nr < 0) - *nr = 0; - return a; - } - else if (isdigit(name[a]) == 0) { - /* non-numeric suffix - give up */ - break; - } - } - } - - return name_len; -} - -/** - * Ensures name is unique (according to criteria specified by caller in unique_check callback), - * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted. - * - * \param unique_check Return true if name is not unique - * \param arg Additional arg to unique_check--meaning is up to caller - * \param defname To initialize name if latter is empty - * \param delim Delimits numeric suffix in name - * \param name Name to be ensured unique - * \param name_len Maximum length of name area - * \return true if there if the name was changed - */ -bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name), - void *arg, const char *defname, char delim, char *name, int name_len) -{ - if (name[0] == '\0') { - BLI_strncpy(name, defname, name_len); - } - - if (unique_check(arg, name)) { - char numstr[16]; - char tempname[UNIQUE_NAME_MAX]; - char left[UNIQUE_NAME_MAX]; - int number; - int len = BLI_split_name_num(left, &number, name, delim); - do { - /* add 1 to account for \0 */ - const int numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1; - - /* highly unlikely the string only has enough room for the number - * but support anyway */ - if ((len == 0) || (numlen >= name_len)) { - /* number is know not to be utf-8 */ - BLI_strncpy(tempname, numstr, name_len); - } - else { - char *tempname_buf; - tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen); - memcpy(tempname_buf, numstr, numlen); - } - } while (unique_check(arg, tempname)); - - BLI_strncpy(name, tempname, name_len); - - return true; - } - - return false; -} - -/* little helper macro for BLI_uniquename */ -#ifndef GIVE_STRADDR -# define GIVE_STRADDR(data, offset) ( ((char *)data) + offset) -#endif - -/* Generic function to set a unique name. It is only designed to be used in situations - * where the name is part of the struct, and also that the name is at most UNIQUE_NAME_MAX chars long. - * - * For places where this is used, see constraint.c for example... - * - * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h - * len: maximum length of string (to prevent overflows, etc.) - * defname: the name that should be used by default if none is specified already - * delim: the character which acts as a delimiter between parts of the name - */ -static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs) -{ - Link *link; - - for (link = list->first; link; link = link->next) { - if (link != vlink) { - if (STREQ(GIVE_STRADDR(link, name_offs), name)) { - return true; - } - } - } - - return false; -} - -static bool uniquename_unique_check(void *arg, const char *name) -{ - struct {ListBase *lb; void *vlink; int name_offs; } *data = arg; - return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs); -} - -/** - * Ensures that the specified block has a unique name within the containing list, - * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted. - * - * \param list List containing the block - * \param vlink The block to check the name for - * \param defname To initialize block name if latter is empty - * \param delim Delimits numeric suffix in name - * \param name_offs Offset of name within block structure - * \param name_len Maximum length of name area - */ -bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int name_len) -{ - struct {ListBase *lb; void *vlink; int name_offs; } data; - data.lb = list; - data.vlink = vlink; - data.name_offs = name_offs; - - assert((name_len > 1) && (name_len <= UNIQUE_NAME_MAX)); - - /* See if we are given an empty string */ - if (ELEM(NULL, vlink, defname)) - return false; - - return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len); -} - static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */ /* ******************** string encoding ***************** */ diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c new file mode 100644 index 00000000000..a7427b6848e --- /dev/null +++ b/source/blender/blenlib/intern/string_utils.c @@ -0,0 +1,207 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 by the Blender FOundation. + * All rights reserved. + * + * Contributor(s): none yet. + * + * ***** END GPL LICENSE BLOCK ***** + * + */ + +/** \file blender/blenlib/intern/string_utils.c + * \ingroup bli + */ + +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utf8.h" +#include "BLI_string_utils.h" +#include "BLI_utildefines.h" + +#include "DNA_listBase.h" + + +#ifdef __GNUC__ +# pragma GCC diagnostic error "-Wsign-conversion" +#endif + +/** + * Looks for a numeric suffix preceded by delim character on the end of + * name, puts preceding part into *left and value of suffix into *nr. + * Returns the length of *left. + * + * Foo.001 -> "Foo", 1 + * Returning the length of "Foo" + * + * \param left Where to return copy of part preceding delim + * \param nr Where to return value of numeric suffix + * \param name String to split + * \param delim Delimiter character + * \return Length of \a left + */ +int BLI_split_name_num(char *left, int *nr, const char *name, const char delim) +{ + const size_t name_len = strlen(name); + + *nr = 0; + memcpy(left, name, (name_len + 1) * sizeof(char)); + + /* name doesn't end with a delimiter "foo." */ + if ((name_len > 1 && name[name_len - 1] == delim) == 0) { + int a = name_len; + while (a--) { + if (name[a] == delim) { + left[a] = '\0'; /* truncate left part here */ + *nr = atol(name + a + 1); + /* casting down to an int, can overflow for large numbers */ + if (*nr < 0) + *nr = 0; + return a; + } + else if (isdigit(name[a]) == 0) { + /* non-numeric suffix - give up */ + break; + } + } + } + + return name_len; +} + + +/* Unique name utils. */ + +/** + * Ensures name is unique (according to criteria specified by caller in unique_check callback), + * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted. + * + * \param unique_check Return true if name is not unique + * \param arg Additional arg to unique_check--meaning is up to caller + * \param defname To initialize name if latter is empty + * \param delim Delimits numeric suffix in name + * \param name Name to be ensured unique + * \param name_len Maximum length of name area + * \return true if there if the name was changed + */ +bool BLI_uniquename_cb( + UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len) +{ + if (name[0] == '\0') { + BLI_strncpy(name, defname, name_len); + } + + if (unique_check(arg, name)) { + char numstr[16]; + char *tempname = alloca(name_len); + char *left = alloca(name_len); + int number; + int len = BLI_split_name_num(left, &number, name, delim); + do { + /* add 1 to account for \0 */ + const size_t numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1; + + /* highly unlikely the string only has enough room for the number + * but support anyway */ + if ((len == 0) || (numlen >= name_len)) { + /* number is know not to be utf-8 */ + BLI_strncpy(tempname, numstr, name_len); + } + else { + char *tempname_buf; + tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen); + memcpy(tempname_buf, numstr, numlen); + } + } while (unique_check(arg, tempname)); + + BLI_strncpy(name, tempname, name_len); + + return true; + } + + return false; +} + +/* little helper macro for BLI_uniquename */ +#ifndef GIVE_STRADDR +# define GIVE_STRADDR(data, offset) ( ((char *)data) + offset) +#endif + +/* Generic function to set a unique name. It is only designed to be used in situations + * where the name is part of the struct. + * + * For places where this is used, see constraint.c for example... + * + * name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h + * len: maximum length of string (to prevent overflows, etc.) + * defname: the name that should be used by default if none is specified already + * delim: the character which acts as a delimiter between parts of the name + */ +static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs) +{ + Link *link; + + for (link = list->first; link; link = link->next) { + if (link != vlink) { + if (STREQ(GIVE_STRADDR(link, name_offs), name)) { + return true; + } + } + } + + return false; +} + +static bool uniquename_unique_check(void *arg, const char *name) +{ + struct {ListBase *lb; void *vlink; int name_offs; } *data = arg; + return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs); +} + +/** + * Ensures that the specified block has a unique name within the containing list, + * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted. + * + * \param list List containing the block + * \param vlink The block to check the name for + * \param defname To initialize block name if latter is empty + * \param delim Delimits numeric suffix in name + * \param name_offs Offset of name within block structure + * \param name_len Maximum length of name area + */ +bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t name_len) +{ + struct {ListBase *lb; void *vlink; int name_offs; } data; + data.lb = list; + data.vlink = vlink; + data.name_offs = name_offs; + + BLI_assert(name_len > 1); + + /* See if we are given an empty string */ + if (ELEM(NULL, vlink, defname)) + return false; + + return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len); +} diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c index 907baab0aee..ab3d14af882 100644 --- a/source/blender/blenloader/intern/versioning_260.c +++ b/source/blender/blenloader/intern/versioning_260.c @@ -56,6 +56,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp index 5cd01eff263..3801c9300df 100644 --- a/source/blender/collada/AnimationImporter.cpp +++ b/source/blender/collada/AnimationImporter.cpp @@ -35,8 +35,8 @@ #include "BLI_listbase.h" #include "BLI_math.h" -#include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 4cffd99ce1b..c5cef632ffe 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 9309592bb46..e3c64b523b1 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -34,6 +34,7 @@ #include "BLI_blenlib.h" #include "BLI_dlrbTree.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index ae83e899649..6980ad46241 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -42,6 +42,7 @@ #include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 111afcdc7a7..edd7b5dd1be 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -41,6 +41,7 @@ #include "BLI_math.h" #include "BLI_utildefines.h" #include "BLI_ghash.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c index 074368a82c5..1559515221e 100644 --- a/source/blender/editors/space_logic/logic_ops.c +++ b/source/blender/editors/space_logic/logic_ops.c @@ -37,6 +37,7 @@ #include "DNA_scene_types.h" #include "BLI_blenlib.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c index 874e54ba5e7..3de44174d6a 100644 --- a/source/blender/editors/space_logic/logic_window.c +++ b/source/blender/editors/space_logic/logic_window.c @@ -47,8 +47,8 @@ #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" -#include "BLI_path_util.h" #include "BKE_action.h" #include "BKE_context.h" diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 33a5a7ca7b7..99242fd12f9 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -40,6 +40,7 @@ #include "BLI_math.h" #include "BLI_blenlib.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLI_mempool.h" diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 90a4aa3614d..058af768885 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -42,7 +42,7 @@ #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_string.h" -#include "BLI_path_util.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BKE_action.h" diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c index a09853eaddc..004acbe4dbd 100644 --- a/source/blender/makesrna/intern/rna_actuator.c +++ b/source/blender/makesrna/intern/rna_actuator.c @@ -32,8 +32,9 @@ #include "DNA_actuator_types.h" #include "DNA_scene_types.h" /* for MAXFRAME */ -#include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLI_string_utils.h" +#include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/makesrna/intern/rna_controller.c b/source/blender/makesrna/intern/rna_controller.c index ed700916584..3fa9d7ef270 100644 --- a/source/blender/makesrna/intern/rna_controller.c +++ b/source/blender/makesrna/intern/rna_controller.c @@ -29,6 +29,7 @@ #include "DNA_object_types.h" #include "DNA_controller_types.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 14da990278c..9c66a86dcee 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -31,6 +31,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c index 2d669986485..a5abc8a3be2 100644 --- a/source/blender/makesrna/intern/rna_key.c +++ b/source/blender/makesrna/intern/rna_key.c @@ -33,6 +33,7 @@ #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c index 622c61beaeb..1199cccc4e6 100644 --- a/source/blender/makesrna/intern/rna_linestyle.c +++ b/source/blender/makesrna/intern/rna_linestyle.c @@ -27,6 +27,9 @@ #include #include +#include "BLI_utildefines.h" +#include "BLI_string_utils.h" + #include "RNA_define.h" #include "RNA_enum_types.h" diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 362baed1e7c..95dab13571d 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -45,6 +45,8 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "BLI_string_utils.h" + #include "BLT_translation.h" #include "rna_internal.h" diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c index 99d57147248..28ce63a61bd 100644 --- a/source/blender/makesrna/intern/rna_pose.c +++ b/source/blender/makesrna/intern/rna_pose.c @@ -40,6 +40,7 @@ #include "DNA_scene_types.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/makesrna/intern/rna_property.c b/source/blender/makesrna/intern/rna_property.c index 07bdbb03357..fb70870f49b 100644 --- a/source/blender/makesrna/intern/rna_property.c +++ b/source/blender/makesrna/intern/rna_property.c @@ -31,6 +31,7 @@ #include "DNA_object_types.h" #include "BLI_path_util.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index ddfb5dc6d61..6947a4104c8 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -40,6 +40,7 @@ #include "IMB_imbuf_types.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c index ee24a434486..d0afab7a1e3 100644 --- a/source/blender/makesrna/intern/rna_sensor.c +++ b/source/blender/makesrna/intern/rna_sensor.c @@ -32,6 +32,7 @@ #include "BLI_utildefines.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BLT_translation.h" diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.c b/source/blender/nodes/composite/nodes/node_composite_outputFile.c index 7d1087435c2..6a96f1b30d8 100644 --- a/source/blender/nodes/composite/nodes/node_composite_outputFile.c +++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.c @@ -32,7 +32,7 @@ #include #include "BLI_utildefines.h" -#include "BLI_path_util.h" +#include "BLI_string_utils.h" #include "BKE_context.h" From 7ce833af5b08ca47c201aab33ab5d6b8fde69486 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 16 Jan 2017 20:08:46 +0100 Subject: [PATCH 516/590] Cleanup/refactor: get rid of fixed name limit in BKE_deform_flip_side_name & co. Those were forcing to use vgroup name define in bones area, or even mixing with maxbonename... ugly, and totally avoidable. --- source/blender/blenkernel/BKE_deform.h | 7 +- source/blender/blenkernel/intern/action.c | 2 +- source/blender/blenkernel/intern/deform.c | 95 +++++++++---------- .../blender/blenkernel/intern/object_deform.c | 2 +- .../editors/animation/keyframes_general.c | 2 +- .../blender/editors/armature/armature_add.c | 8 +- .../editors/armature/armature_naming.c | 2 +- .../editors/armature/armature_select.c | 20 ++-- .../editors/armature/armature_skinning.c | 2 +- .../blender/editors/armature/armature_utils.c | 2 +- .../blender/editors/armature/pose_transform.c | 2 +- source/blender/editors/object/object_select.c | 2 +- .../editors/sculpt_paint/paint_vertex.c | 2 +- 13 files changed, 73 insertions(+), 75 deletions(-) diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index 8756f73df72..a6d1139648d 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -119,10 +119,9 @@ void BKE_defvert_extract_vgroup_to_polyweights( /* utility function, note that MAX_VGROUP_NAME chars is the maximum string length since its only * used with defgroups currently */ -void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char base[MAX_VGROUP_NAME], char ext[MAX_VGROUP_NAME]); -void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char base[MAX_VGROUP_NAME], char ext[MAX_VGROUP_NAME]); +void BKE_deform_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len); +void BKE_deform_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len); -void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME], - const bool strip_number); +void BKE_deform_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len); #endif /* __BKE_DEFORM_H__ */ diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 2ade4cf08d5..d1b0306c27c 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -495,7 +495,7 @@ bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name) { char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, name, false); + BKE_deform_flip_side_name(name_flip, name, false, sizeof(name_flip)); if (!STREQ(name_flip, name)) { return BKE_pose_channel_find_name(pose, name_flip); diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index abc14c42d40..783455ef6f8 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -509,7 +509,7 @@ int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default) if (use_default) map[i] = i; - BKE_deform_flip_side_name(name_flip, dg->name, false); + BKE_deform_flip_side_name(name_flip, dg->name, false, sizeof(name_flip)); if (!STREQ(name_flip, dg->name)) { flip_num = defgroup_name_index(ob, name_flip); @@ -545,7 +545,7 @@ int *defgroup_flip_map_single(Object *ob, int *flip_map_len, const bool use_defa dg = BLI_findlink(&ob->defbase, defgroup); - BKE_deform_flip_side_name(name_flip, dg->name, false); + BKE_deform_flip_side_name(name_flip, dg->name, false, sizeof(name_flip)); if (!STREQ(name_flip, dg->name)) { flip_num = defgroup_name_index(ob, name_flip); @@ -566,7 +566,7 @@ int defgroup_flip_index(Object *ob, int index, const bool use_default) if (dg) { char name_flip[sizeof(dg->name)]; - BKE_deform_flip_side_name(name_flip, dg->name, false); + BKE_deform_flip_side_name(name_flip, dg->name, false, sizeof(name_flip)); if (!STREQ(name_flip, dg->name)) { flip_index = defgroup_name_index(ob, name_flip); @@ -615,91 +615,92 @@ static bool is_char_sep(const char c) * based on `BLI_split_dirfile()` / `os.path.splitext()`, * `"a.b.c"` -> (`"a.b"`, `".c"`). */ -void BKE_deform_split_suffix(const char string[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME], char suf[MAX_VGROUP_NAME]) +void BKE_deform_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len) { - size_t len = BLI_strnlen(string, MAX_VGROUP_NAME); + size_t len = BLI_strnlen(string, str_len); size_t i; - body[0] = suf[0] = '\0'; + r_body[0] = r_suf[0] = '\0'; for (i = len; i > 0; i--) { if (is_char_sep(string[i])) { - BLI_strncpy(body, string, i + 1); - BLI_strncpy(suf, string + i, (len + 1) - i); + BLI_strncpy(r_body, string, i + 1); + BLI_strncpy(r_suf, string + i, (len + 1) - i); return; } } - memcpy(body, string, len + 1); + memcpy(r_body, string, len + 1); } /** * `"a.b.c"` -> (`"a."`, `"b.c"`) */ -void BKE_deform_split_prefix(const char string[MAX_VGROUP_NAME], char pre[MAX_VGROUP_NAME], char body[MAX_VGROUP_NAME]) +void BKE_deform_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len) { - size_t len = BLI_strnlen(string, MAX_VGROUP_NAME); + size_t len = BLI_strnlen(string, str_len); size_t i; - body[0] = pre[0] = '\0'; + r_body[0] = r_pre[0] = '\0'; for (i = 1; i < len; i++) { if (is_char_sep(string[i])) { i++; - BLI_strncpy(pre, string, i + 1); - BLI_strncpy(body, string + i, (len + 1) - i); + BLI_strncpy(r_pre, string, i + 1); + BLI_strncpy(r_body, string + i, (len + 1) - i); return; } } - BLI_strncpy(body, string, len); + BLI_strncpy(r_body, string, len); } /** - * Finds the best possible flipped name. For renaming; check for unique names afterwards. + * Finds the best possible flipped (left/right) name. For renaming; check for unique names afterwards. * - * if strip_number: removes number extensions - * - * \note don't use sizeof() for 'name' or 'from_name'. + * \param r_name flipped name, assumed to be a pointer to a string of at least \a name_len size. + * \param from_name original name, assumed to be a pointer to a string of at least \a name_len size. + * \param strip_number If set, remove number extensions. */ -void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[MAX_VGROUP_NAME], - const bool strip_number) +void BKE_deform_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len) { - int len; - char prefix[MAX_VGROUP_NAME] = ""; /* The part before the facing */ - char suffix[MAX_VGROUP_NAME] = ""; /* The part after the facing */ - char replace[MAX_VGROUP_NAME] = ""; /* The replacement string */ - char number[MAX_VGROUP_NAME] = ""; /* The number extension string */ - char *index = NULL; + size_t len; + char *prefix = alloca(name_len); /* The part before the facing */ + char *suffix = alloca(name_len); /* The part after the facing */ + char *replace = alloca(name_len); /* The replacement string */ + char *number = alloca(name_len); /* The number extension string */ + char *index = NULL; bool is_set = false; - /* always copy the name, since this can be called with an uninitialized string */ - BLI_strncpy(name, from_name, MAX_VGROUP_NAME); + *prefix = *suffix = *replace = *number = '\0'; - len = BLI_strnlen(from_name, MAX_VGROUP_NAME); + /* always copy the name, since this can be called with an uninitialized string */ + BLI_strncpy(r_name, from_name, name_len); + + len = BLI_strnlen(from_name, name_len); if (len < 3) { /* we don't do names like .R or .L */ return; } /* We first check the case with a .### extension, let's find the last period */ - if (isdigit(name[len - 1])) { - index = strrchr(name, '.'); // last occurrence + if (isdigit(r_name[len - 1])) { + index = strrchr(r_name, '.'); // last occurrence if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever! if (strip_number == false) { - BLI_strncpy(number, index, sizeof(number)); + BLI_strncpy(number, index, name_len); } *index = 0; - len = BLI_strnlen(name, MAX_VGROUP_NAME); + len = BLI_strnlen(r_name, name_len); } } - BLI_strncpy(prefix, name, sizeof(prefix)); + BLI_strncpy(prefix, r_name, name_len); /* first case; separator . - _ with extensions r R l L */ - if ((len > 1) && is_char_sep(name[len - 2])) { + if ((len > 1) && is_char_sep(r_name[len - 2])) { is_set = true; - switch (name[len - 1]) { + switch (r_name[len - 1]) { case 'l': prefix[len - 1] = 0; strcpy(replace, "r"); @@ -722,27 +723,27 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[ } /* case; beginning with r R l L, with separator after it */ - if (!is_set && is_char_sep(name[1])) { + if (!is_set && is_char_sep(r_name[1])) { is_set = true; - switch (name[0]) { + switch (r_name[0]) { case 'l': strcpy(replace, "r"); - BLI_strncpy(suffix, name + 1, sizeof(suffix)); + BLI_strncpy(suffix, r_name + 1, name_len); prefix[0] = 0; break; case 'r': strcpy(replace, "l"); - BLI_strncpy(suffix, name + 1, sizeof(suffix)); + BLI_strncpy(suffix, r_name + 1, name_len); prefix[0] = 0; break; case 'L': strcpy(replace, "R"); - BLI_strncpy(suffix, name + 1, sizeof(suffix)); + BLI_strncpy(suffix, r_name + 1, name_len); prefix[0] = 0; break; case 'R': strcpy(replace, "L"); - BLI_strncpy(suffix, name + 1, sizeof(suffix)); + BLI_strncpy(suffix, r_name + 1, name_len); prefix[0] = 0; break; default: @@ -763,7 +764,7 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[ strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left"); } *index = 0; - BLI_strncpy(suffix, index + 5, sizeof(suffix)); + BLI_strncpy(suffix, index + 5, name_len); } else if (((index = BLI_strcasestr(prefix, "left")) == prefix) || (index == prefix + len - 4)) @@ -776,13 +777,11 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[ strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right"); } *index = 0; - BLI_strncpy(suffix, index + 4, sizeof(suffix)); + BLI_strncpy(suffix, index + 4, name_len); } } - (void)is_set; /* quiet warning */ - - BLI_snprintf(name, MAX_VGROUP_NAME, "%s%s%s%s", prefix, replace, suffix, number); + BLI_snprintf(r_name, name_len, "%s%s%s%s", prefix, replace, suffix, number); } float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup) diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index b5e1ded35bb..ce8c7919a22 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -623,7 +623,7 @@ void BKE_object_defgroup_mirror_selection( if (dg_selection[i]) { char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, defgroup->name, false); + BKE_deform_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip)); i_mirr = STREQ(name_flip, defgroup->name) ? i : defgroup_name_index(ob, name_flip); if ((i_mirr >= 0 && i_mirr < defbase_tot) && (dg_flags_sel[i_mirr] == false)) { diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index 1703210f0b6..ae1ca1c4d1e 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -668,7 +668,7 @@ static void flip_names(tAnimCopybufItem *aci, char **name) /* more ninja stuff, temporary substitute with NULL terminator */ str_start[length] = 0; - BKE_deform_flip_side_name(bname_new, str_start, false); + BKE_deform_flip_side_name(bname_new, str_start, false, sizeof(bname_new)); str_start[length] = '\"'; str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path"); diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 6228874343b..23c2739543c 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -619,9 +619,9 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) if (EBONE_VISIBLE(arm, ebone_iter) && (ebone_iter->flag & BONE_SELECTED)) { - char name_flip[MAX_VGROUP_NAME]; + char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, ebone_iter->name, false); + BKE_deform_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip)); if (STREQ(name_flip, ebone_iter->name)) { /* if the name matches, we don't have the potential to be mirrored, just skip */ @@ -679,9 +679,9 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) /* will be set if the mirror bone already exists (no need to make a new one) */ (ebone_iter->temp.ebone == NULL)) { - char name_flip[MAX_VGROUP_NAME]; + char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, ebone_iter->name, false); + BKE_deform_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip)); /* bones must have a side-suffix */ if (!STREQ(name_flip, ebone_iter->name)) { diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index c5cef632ffe..8d949fb8c3d 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -328,7 +328,7 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names) /* Do not strip numbers, otherwise we'll end up with completely mismatched names in cases like * Bone.R, Bone.R.001, Bone.R.002, etc. */ - BKE_deform_flip_side_name(name_flip, name, false); + BKE_deform_flip_side_name(name_flip, name, false, sizeof(name_flip)); ED_armature_bone_rename(arm, name, name_flip); diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 5a70a45fad4..a34615e4402 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -817,10 +817,10 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act) { EditBone *ebone; - char body_tmp[MAX_VGROUP_NAME]; - char prefix_act[MAX_VGROUP_NAME]; + char body_tmp[MAXBONENAME]; + char prefix_act[MAXBONENAME]; - BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp); + BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name)); if (prefix_act[0] == '\0') return; @@ -828,8 +828,8 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act) /* Find matches */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_SELECTABLE(arm, ebone)) { - char prefix_other[MAX_VGROUP_NAME]; - BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp); + char prefix_other[MAXBONENAME]; + BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name)); if (STREQ(prefix_act, prefix_other)) { ED_armature_ebone_select_set(ebone, true); } @@ -841,10 +841,10 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act) { EditBone *ebone; - char body_tmp[MAX_VGROUP_NAME]; - char suffix_act[MAX_VGROUP_NAME]; + char body_tmp[MAXBONENAME]; + char suffix_act[MAXBONENAME]; - BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act); + BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name)); if (suffix_act[0] == '\0') return; @@ -852,8 +852,8 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act) /* Find matches */ for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_SELECTABLE(arm, ebone)) { - char suffix_other[MAX_VGROUP_NAME]; - BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other); + char suffix_other[MAXBONENAME]; + BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name)); if (STREQ(suffix_act, suffix_other)) { ED_armature_ebone_select_set(ebone, true); } diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 28fddbab796..24146715f96 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -360,7 +360,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, if (dgroup && mirror) { char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, dgroup->name, false); + BKE_deform_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip)); dgroupflip[j] = defgroup_find_name(ob, name_flip); } } diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 6979a324b69..0f783dbad69 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -262,7 +262,7 @@ EditBone *ED_armature_bone_get_mirrored(const ListBase *edbo, EditBone *ebo) if (ebo == NULL) return NULL; - BKE_deform_flip_side_name(name_flip, ebo->name, false); + BKE_deform_flip_side_name(name_flip, ebo->name, false, sizeof(name_flip)); if (!STREQ(name_flip, ebo->name)) { return ED_armature_bone_find_name(edbo, name_flip); diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index b645f1fb2f3..a871a0e0966 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -286,7 +286,7 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo /* get the name - if flipping, we must flip this first */ if (flip) - BKE_deform_flip_side_name(name, chan->name, false); + BKE_deform_flip_side_name(name, chan->name, false, sizeof(name)); else BLI_strncpy(name, chan->name, sizeof(name)); diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index f1b7186f8a1..a81b6ef20fc 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -1131,7 +1131,7 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op) { char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, primbase->object->id.name + 2, true); + BKE_deform_flip_side_name(name_flip, primbase->object->id.name + 2, true, sizeof(name_flip)); if (!STREQ(name_flip, primbase->object->id.name + 2)) { Object *ob = (Object *)BKE_libblock_find_name(ID_OB, name_flip); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 991025a4d5d..3c3763fc013 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -275,7 +275,7 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) int mirrdef; char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, defgroup->name, false); + BKE_deform_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip)); mirrdef = defgroup_name_index(ob, name_flip); if (mirrdef == -1) { if (BKE_defgroup_new(ob, name_flip)) { From e0303d02974c914d4633e37d789e33b21689b5eb Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 16 Jan 2017 20:34:13 +0100 Subject: [PATCH 517/590] Cleanup/refactor: move BKE_deform_flip_side_name & co to BLI_string_utils Functions like that do not have anything to do in BKE really, even less when actually more used for bones than vgroups! --- source/blender/blenkernel/BKE_deform.h | 8 - source/blender/blenkernel/intern/action.c | 2 +- source/blender/blenkernel/intern/deform.c | 184 +----------------- .../blender/blenkernel/intern/object_deform.c | 3 +- source/blender/blenlib/BLI_string_utils.h | 5 + source/blender/blenlib/intern/string_utils.c | 178 +++++++++++++++++ .../editors/animation/keyframes_general.c | 3 +- .../blender/editors/armature/armature_add.c | 5 +- .../editors/armature/armature_naming.c | 2 +- .../editors/armature/armature_select.c | 11 +- .../editors/armature/armature_skinning.c | 3 +- .../blender/editors/armature/armature_utils.c | 3 +- .../blender/editors/armature/pose_transform.c | 3 +- source/blender/editors/object/object_select.c | 3 +- .../editors/sculpt_paint/paint_vertex.c | 3 +- 15 files changed, 211 insertions(+), 205 deletions(-) diff --git a/source/blender/blenkernel/BKE_deform.h b/source/blender/blenkernel/BKE_deform.h index a6d1139648d..3ce08a14177 100644 --- a/source/blender/blenkernel/BKE_deform.h +++ b/source/blender/blenkernel/BKE_deform.h @@ -116,12 +116,4 @@ void BKE_defvert_extract_vgroup_to_polyweights( struct MDeformVert *dvert, const int defgroup, const int num_verts, struct MLoop *loops, const int num_loops, struct MPoly *polys, const int num_polys, float *r_weights, const bool invert_vgroup); -/* utility function, note that MAX_VGROUP_NAME chars is the maximum string length since its only - * used with defgroups currently */ - -void BKE_deform_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len); -void BKE_deform_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len); - -void BKE_deform_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len); - #endif /* __BKE_DEFORM_H__ */ diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index d1b0306c27c..1e33fe4ab46 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -495,7 +495,7 @@ bPoseChannel *BKE_pose_channel_get_mirrored(const bPose *pose, const char *name) { char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip)); if (!STREQ(name_flip, name)) { return BKE_pose_channel_find_name(pose, name_flip); diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c index 783455ef6f8..13b1aab5e1c 100644 --- a/source/blender/blenkernel/intern/deform.c +++ b/source/blender/blenkernel/intern/deform.c @@ -509,7 +509,7 @@ int *defgroup_flip_map(Object *ob, int *flip_map_len, const bool use_default) if (use_default) map[i] = i; - BKE_deform_flip_side_name(name_flip, dg->name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip)); if (!STREQ(name_flip, dg->name)) { flip_num = defgroup_name_index(ob, name_flip); @@ -545,7 +545,7 @@ int *defgroup_flip_map_single(Object *ob, int *flip_map_len, const bool use_defa dg = BLI_findlink(&ob->defbase, defgroup); - BKE_deform_flip_side_name(name_flip, dg->name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip)); if (!STREQ(name_flip, dg->name)) { flip_num = defgroup_name_index(ob, name_flip); @@ -566,7 +566,7 @@ int defgroup_flip_index(Object *ob, int index, const bool use_default) if (dg) { char name_flip[sizeof(dg->name)]; - BKE_deform_flip_side_name(name_flip, dg->name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, dg->name, false, sizeof(name_flip)); if (!STREQ(name_flip, dg->name)) { flip_index = defgroup_name_index(ob, name_flip); @@ -606,184 +606,6 @@ void defgroup_unique_name(bDeformGroup *dg, Object *ob) BLI_uniquename_cb(defgroup_unique_check, &data, DATA_("Group"), '.', dg->name, sizeof(dg->name)); } -static bool is_char_sep(const char c) -{ - return ELEM(c, '.', ' ', '-', '_'); -} - -/** - * based on `BLI_split_dirfile()` / `os.path.splitext()`, - * `"a.b.c"` -> (`"a.b"`, `".c"`). - */ -void BKE_deform_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len) -{ - size_t len = BLI_strnlen(string, str_len); - size_t i; - - r_body[0] = r_suf[0] = '\0'; - - for (i = len; i > 0; i--) { - if (is_char_sep(string[i])) { - BLI_strncpy(r_body, string, i + 1); - BLI_strncpy(r_suf, string + i, (len + 1) - i); - return; - } - } - - memcpy(r_body, string, len + 1); -} - -/** - * `"a.b.c"` -> (`"a."`, `"b.c"`) - */ -void BKE_deform_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len) -{ - size_t len = BLI_strnlen(string, str_len); - size_t i; - - r_body[0] = r_pre[0] = '\0'; - - for (i = 1; i < len; i++) { - if (is_char_sep(string[i])) { - i++; - BLI_strncpy(r_pre, string, i + 1); - BLI_strncpy(r_body, string + i, (len + 1) - i); - return; - } - } - - BLI_strncpy(r_body, string, len); -} - -/** - * Finds the best possible flipped (left/right) name. For renaming; check for unique names afterwards. - * - * \param r_name flipped name, assumed to be a pointer to a string of at least \a name_len size. - * \param from_name original name, assumed to be a pointer to a string of at least \a name_len size. - * \param strip_number If set, remove number extensions. - */ -void BKE_deform_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len) -{ - size_t len; - char *prefix = alloca(name_len); /* The part before the facing */ - char *suffix = alloca(name_len); /* The part after the facing */ - char *replace = alloca(name_len); /* The replacement string */ - char *number = alloca(name_len); /* The number extension string */ - char *index = NULL; - bool is_set = false; - - *prefix = *suffix = *replace = *number = '\0'; - - /* always copy the name, since this can be called with an uninitialized string */ - BLI_strncpy(r_name, from_name, name_len); - - len = BLI_strnlen(from_name, name_len); - if (len < 3) { - /* we don't do names like .R or .L */ - return; - } - - /* We first check the case with a .### extension, let's find the last period */ - if (isdigit(r_name[len - 1])) { - index = strrchr(r_name, '.'); // last occurrence - if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever! - if (strip_number == false) { - BLI_strncpy(number, index, name_len); - } - *index = 0; - len = BLI_strnlen(r_name, name_len); - } - } - - BLI_strncpy(prefix, r_name, name_len); - - /* first case; separator . - _ with extensions r R l L */ - if ((len > 1) && is_char_sep(r_name[len - 2])) { - is_set = true; - switch (r_name[len - 1]) { - case 'l': - prefix[len - 1] = 0; - strcpy(replace, "r"); - break; - case 'r': - prefix[len - 1] = 0; - strcpy(replace, "l"); - break; - case 'L': - prefix[len - 1] = 0; - strcpy(replace, "R"); - break; - case 'R': - prefix[len - 1] = 0; - strcpy(replace, "L"); - break; - default: - is_set = false; - } - } - - /* case; beginning with r R l L, with separator after it */ - if (!is_set && is_char_sep(r_name[1])) { - is_set = true; - switch (r_name[0]) { - case 'l': - strcpy(replace, "r"); - BLI_strncpy(suffix, r_name + 1, name_len); - prefix[0] = 0; - break; - case 'r': - strcpy(replace, "l"); - BLI_strncpy(suffix, r_name + 1, name_len); - prefix[0] = 0; - break; - case 'L': - strcpy(replace, "R"); - BLI_strncpy(suffix, r_name + 1, name_len); - prefix[0] = 0; - break; - case 'R': - strcpy(replace, "L"); - BLI_strncpy(suffix, r_name + 1, name_len); - prefix[0] = 0; - break; - default: - is_set = false; - } - } - - if (!is_set && len > 5) { - /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */ - if (((index = BLI_strcasestr(prefix, "right")) == prefix) || - (index == prefix + len - 5)) - { - is_set = true; - if (index[0] == 'r') { - strcpy(replace, "left"); - } - else { - strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left"); - } - *index = 0; - BLI_strncpy(suffix, index + 5, name_len); - } - else if (((index = BLI_strcasestr(prefix, "left")) == prefix) || - (index == prefix + len - 4)) - { - is_set = true; - if (index[0] == 'l') { - strcpy(replace, "right"); - } - else { - strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right"); - } - *index = 0; - BLI_strncpy(suffix, index + 4, name_len); - } - } - - BLI_snprintf(r_name, name_len, "%s%s%s%s", prefix, replace, suffix, number); -} - float defvert_find_weight(const struct MDeformVert *dvert, const int defgroup) { MDeformWeight *dw = defvert_find_index(dvert, defgroup); diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index ce8c7919a22..ccf2aec5c7a 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -32,6 +32,7 @@ #include "BLI_utildefines.h" #include "BLI_ghash.h" #include "BLI_listbase.h" +#include "BLI_string_utils.h" #include "DNA_armature_types.h" #include "DNA_cloth_types.h" @@ -623,7 +624,7 @@ void BKE_object_defgroup_mirror_selection( if (dg_selection[i]) { char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip)); i_mirr = STREQ(name_flip, defgroup->name) ? i : defgroup_name_index(ob, name_flip); if ((i_mirr >= 0 && i_mirr < defbase_tot) && (dg_flags_sel[i_mirr] == false)) { diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h index 81c06fbc20d..719d6e3c57b 100644 --- a/source/blender/blenlib/BLI_string_utils.h +++ b/source/blender/blenlib/BLI_string_utils.h @@ -46,6 +46,11 @@ typedef bool (*UniquenameCheckCallback)(void *arg, const char *name); int BLI_split_name_num(char *left, int *nr, const char *name, const char delim); +void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len); +void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len); + +void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len); + bool BLI_uniquename_cb( UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len); bool BLI_uniquename( diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index a7427b6848e..435a88d6e21 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -90,6 +90,184 @@ int BLI_split_name_num(char *left, int *nr, const char *name, const char delim) return name_len; } +static bool is_char_sep(const char c) +{ + return ELEM(c, '.', ' ', '-', '_'); +} + +/** + * based on `BLI_split_dirfile()` / `os.path.splitext()`, + * `"a.b.c"` -> (`"a.b"`, `".c"`). + */ +void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len) +{ + size_t len = BLI_strnlen(string, str_len); + size_t i; + + r_body[0] = r_suf[0] = '\0'; + + for (i = len; i > 0; i--) { + if (is_char_sep(string[i])) { + BLI_strncpy(r_body, string, i + 1); + BLI_strncpy(r_suf, string + i, (len + 1) - i); + return; + } + } + + memcpy(r_body, string, len + 1); +} + +/** + * `"a.b.c"` -> (`"a."`, `"b.c"`) + */ +void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len) +{ + size_t len = BLI_strnlen(string, str_len); + size_t i; + + r_body[0] = r_pre[0] = '\0'; + + for (i = 1; i < len; i++) { + if (is_char_sep(string[i])) { + i++; + BLI_strncpy(r_pre, string, i + 1); + BLI_strncpy(r_body, string + i, (len + 1) - i); + return; + } + } + + BLI_strncpy(r_body, string, len); +} + +/** + * Finds the best possible flipped (left/right) name. For renaming; check for unique names afterwards. + * + * \param r_name flipped name, assumed to be a pointer to a string of at least \a name_len size. + * \param from_name original name, assumed to be a pointer to a string of at least \a name_len size. + * \param strip_number If set, remove number extensions. + */ +void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len) +{ + size_t len; + char *prefix = alloca(name_len); /* The part before the facing */ + char *suffix = alloca(name_len); /* The part after the facing */ + char *replace = alloca(name_len); /* The replacement string */ + char *number = alloca(name_len); /* The number extension string */ + char *index = NULL; + bool is_set = false; + + *prefix = *suffix = *replace = *number = '\0'; + + /* always copy the name, since this can be called with an uninitialized string */ + BLI_strncpy(r_name, from_name, name_len); + + len = BLI_strnlen(from_name, name_len); + if (len < 3) { + /* we don't do names like .R or .L */ + return; + } + + /* We first check the case with a .### extension, let's find the last period */ + if (isdigit(r_name[len - 1])) { + index = strrchr(r_name, '.'); // last occurrence + if (index && isdigit(index[1])) { // doesnt handle case bone.1abc2 correct..., whatever! + if (strip_number == false) { + BLI_strncpy(number, index, name_len); + } + *index = 0; + len = BLI_strnlen(r_name, name_len); + } + } + + BLI_strncpy(prefix, r_name, name_len); + + /* first case; separator . - _ with extensions r R l L */ + if ((len > 1) && is_char_sep(r_name[len - 2])) { + is_set = true; + switch (r_name[len - 1]) { + case 'l': + prefix[len - 1] = 0; + strcpy(replace, "r"); + break; + case 'r': + prefix[len - 1] = 0; + strcpy(replace, "l"); + break; + case 'L': + prefix[len - 1] = 0; + strcpy(replace, "R"); + break; + case 'R': + prefix[len - 1] = 0; + strcpy(replace, "L"); + break; + default: + is_set = false; + } + } + + /* case; beginning with r R l L, with separator after it */ + if (!is_set && is_char_sep(r_name[1])) { + is_set = true; + switch (r_name[0]) { + case 'l': + strcpy(replace, "r"); + BLI_strncpy(suffix, r_name + 1, name_len); + prefix[0] = 0; + break; + case 'r': + strcpy(replace, "l"); + BLI_strncpy(suffix, r_name + 1, name_len); + prefix[0] = 0; + break; + case 'L': + strcpy(replace, "R"); + BLI_strncpy(suffix, r_name + 1, name_len); + prefix[0] = 0; + break; + case 'R': + strcpy(replace, "L"); + BLI_strncpy(suffix, r_name + 1, name_len); + prefix[0] = 0; + break; + default: + is_set = false; + } + } + + if (!is_set && len > 5) { + /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */ + if (((index = BLI_strcasestr(prefix, "right")) == prefix) || + (index == prefix + len - 5)) + { + is_set = true; + if (index[0] == 'r') { + strcpy(replace, "left"); + } + else { + strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left"); + } + *index = 0; + BLI_strncpy(suffix, index + 5, name_len); + } + else if (((index = BLI_strcasestr(prefix, "left")) == prefix) || + (index == prefix + len - 4)) + { + is_set = true; + if (index[0] == 'l') { + strcpy(replace, "right"); + } + else { + strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right"); + } + *index = 0; + BLI_strncpy(suffix, index + 4, name_len); + } + } + + BLI_snprintf(r_name, name_len, "%s%s%s%s", prefix, replace, suffix, number); +} + /* Unique name utils. */ diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index ae1ca1c4d1e..c1e82583521 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -37,6 +37,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_string_utils.h" #include "DNA_anim_types.h" #include "DNA_object_types.h" @@ -668,7 +669,7 @@ static void flip_names(tAnimCopybufItem *aci, char **name) /* more ninja stuff, temporary substitute with NULL terminator */ str_start[length] = 0; - BKE_deform_flip_side_name(bname_new, str_start, false, sizeof(bname_new)); + BLI_string_flip_side_name(bname_new, str_start, false, sizeof(bname_new)); str_start[length] = '\"'; str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path"); diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c index 23c2739543c..bbc81f522fa 100644 --- a/source/blender/editors/armature/armature_add.c +++ b/source/blender/editors/armature/armature_add.c @@ -39,6 +39,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" #include "BLI_ghash.h" +#include "BLI_string_utils.h" #include "BKE_action.h" #include "BKE_constraint.h" @@ -621,7 +622,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) { char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip)); if (STREQ(name_flip, ebone_iter->name)) { /* if the name matches, we don't have the potential to be mirrored, just skip */ @@ -681,7 +682,7 @@ static int armature_symmetrize_exec(bContext *C, wmOperator *op) { char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, ebone_iter->name, false, sizeof(name_flip)); /* bones must have a side-suffix */ if (!STREQ(name_flip, ebone_iter->name)) { diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 8d949fb8c3d..fa192ed6f36 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -328,7 +328,7 @@ void ED_armature_bones_flip_names(bArmature *arm, ListBase *bones_names) /* Do not strip numbers, otherwise we'll end up with completely mismatched names in cases like * Bone.R, Bone.R.001, Bone.R.002, etc. */ - BKE_deform_flip_side_name(name_flip, name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, name, false, sizeof(name_flip)); ED_armature_bone_rename(arm, name, name_flip); diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index a34615e4402..e9946abba0b 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -35,9 +35,10 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BKE_context.h" -#include "BKE_deform.h" +//#include "BKE_deform.h" #include "BKE_report.h" #include "BIF_gl.h" @@ -820,7 +821,7 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act) char body_tmp[MAXBONENAME]; char prefix_act[MAXBONENAME]; - BKE_deform_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name)); + BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name)); if (prefix_act[0] == '\0') return; @@ -829,7 +830,7 @@ static void select_similar_prefix(bArmature *arm, EditBone *ebone_act) for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_SELECTABLE(arm, ebone)) { char prefix_other[MAXBONENAME]; - BKE_deform_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name)); + BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name)); if (STREQ(prefix_act, prefix_other)) { ED_armature_ebone_select_set(ebone, true); } @@ -844,7 +845,7 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act) char body_tmp[MAXBONENAME]; char suffix_act[MAXBONENAME]; - BKE_deform_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name)); + BLI_string_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name)); if (suffix_act[0] == '\0') return; @@ -853,7 +854,7 @@ static void select_similar_suffix(bArmature *arm, EditBone *ebone_act) for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_SELECTABLE(arm, ebone)) { char suffix_other[MAXBONENAME]; - BKE_deform_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name)); + BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name)); if (STREQ(suffix_act, suffix_other)) { ED_armature_ebone_select_set(ebone, true); } diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index 24146715f96..e8d41f722d7 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -39,6 +39,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BKE_action.h" #include "BKE_armature.h" @@ -360,7 +361,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, if (dgroup && mirror) { char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, dgroup->name, false, sizeof(name_flip)); dgroupflip[j] = defgroup_find_name(ob, name_flip); } } diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 0f783dbad69..a3b439536b7 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -34,6 +34,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BKE_armature.h" #include "BKE_context.h" @@ -262,7 +263,7 @@ EditBone *ED_armature_bone_get_mirrored(const ListBase *edbo, EditBone *ebo) if (ebo == NULL) return NULL; - BKE_deform_flip_side_name(name_flip, ebo->name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, ebo->name, false, sizeof(name_flip)); if (!STREQ(name_flip, ebo->name)) { return ED_armature_bone_find_name(edbo, name_flip); diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index a871a0e0966..063ba37f20d 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -36,6 +36,7 @@ #include "BLI_blenlib.h" #include "BLI_math.h" +#include "BLI_string_utils.h" #include "BKE_animsys.h" #include "BKE_action.h" @@ -286,7 +287,7 @@ static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bo /* get the name - if flipping, we must flip this first */ if (flip) - BKE_deform_flip_side_name(name, chan->name, false, sizeof(name)); + BLI_string_flip_side_name(name, chan->name, false, sizeof(name)); else BLI_strncpy(name, chan->name, sizeof(name)); diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index a81b6ef20fc..b5131df3eaa 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -45,6 +45,7 @@ #include "BLI_math.h" #include "BLI_listbase.h" #include "BLI_rand.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -1131,7 +1132,7 @@ static int object_select_mirror_exec(bContext *C, wmOperator *op) { char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, primbase->object->id.name + 2, true, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, primbase->object->id.name + 2, true, sizeof(name_flip)); if (!STREQ(name_flip, primbase->object->id.name + 2)) { Object *ob = (Object *)BKE_libblock_find_name(ID_OB, name_flip); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 3c3763fc013..729dd9dc57b 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -36,6 +36,7 @@ #include "BLI_array_utils.h" #include "BLI_bitmap.h" #include "BLI_stack.h" +#include "BLI_string_utils.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -275,7 +276,7 @@ static int wpaint_mirror_vgroup_ensure(Object *ob, const int vgroup_active) int mirrdef; char name_flip[MAXBONENAME]; - BKE_deform_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip)); + BLI_string_flip_side_name(name_flip, defgroup->name, false, sizeof(name_flip)); mirrdef = defgroup_name_index(ob, name_flip); if (mirrdef == -1) { if (BKE_defgroup_new(ob, name_flip)) { From d7b2093db34d3f68e8b98566ce4a728592dd3085 Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Tue, 17 Jan 2017 11:52:02 +0300 Subject: [PATCH 518/590] Return correct alpha for environment map in GLSL --- source/blender/gpu/shaders/gpu_shader_material.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 4416b6494f9..aa583c5ecf8 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1358,7 +1358,7 @@ void mtex_cube_map_refl_from_refldir( samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color) { color = textureCube(ima, reflecteddirection); - value = 1.0; + value = color.a; } void mtex_cube_map_refl( From af9f6fd57ecbab4fbacbeb18f8c0f2bfed19faac Mon Sep 17 00:00:00 2001 From: Alexander Romanov Date: Tue, 17 Jan 2017 12:02:05 +0300 Subject: [PATCH 519/590] Add 'Layer Weight' node to Blender internal node items --- release/scripts/startup/nodeitems_builtins.py | 1 + 1 file changed, 1 insertion(+) diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 69358302782..e915aa5bb72 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -145,6 +145,7 @@ shader_node_categories = [ NodeItem("ShaderNodeMaterial"), NodeItem("ShaderNodeCameraData"), NodeItem("ShaderNodeFresnel"), + NodeItem("ShaderNodeLayerWeight"), NodeItem("ShaderNodeLampData"), NodeItem("ShaderNodeValue"), NodeItem("ShaderNodeRGB"), From cd8cde1a6a4a8294c0c63cf4962a8292a2cda61d Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Tue, 3 Jan 2017 23:29:21 +1300 Subject: [PATCH 520/590] Code Cleanup: Move GPencil Interpolation operators into their own file The interpolation operators (and their associated code) occupied a significant portion of gpencil_edit.c (which was getting a bit heavy). So, it's best to split these out into a separate file to make things easier to handle, in preparation for some further dev work. --- source/blender/editors/gpencil/CMakeLists.txt | 1 + source/blender/editors/gpencil/gpencil_edit.c | 670 ---------------- .../editors/gpencil/gpencil_interpolate.c | 753 ++++++++++++++++++ 3 files changed, 754 insertions(+), 670 deletions(-) create mode 100644 source/blender/editors/gpencil/gpencil_interpolate.c diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt index 6604d595573..3d5317b2ebd 100644 --- a/source/blender/editors/gpencil/CMakeLists.txt +++ b/source/blender/editors/gpencil/CMakeLists.txt @@ -44,6 +44,7 @@ set(SRC gpencil_convert.c gpencil_data.c gpencil_edit.c + gpencil_interpolate.c gpencil_ops.c gpencil_paint.c gpencil_select.c diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 15f65b394a9..f01dfee494a 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -2098,673 +2098,3 @@ void GPENCIL_OT_stroke_subdivide(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } - -/* ========= Interpolation operators ========================== */ -/* Helper: Update point with interpolation */ -static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor) -{ - bGPDspoint *prev, *pt, *next; - - /* update points */ - for (int i = 0; i < new_stroke->totpoints; i++) { - prev = &gps_from->points[i]; - pt = &new_stroke->points[i]; - next = &gps_to->points[i]; - - /* Interpolate all values */ - interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor); - pt->pressure = interpf(prev->pressure, next->pressure, factor); - pt->strength = interpf(prev->strength, next->strength, factor); - CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); - } -} - -/* Helper: Update all strokes interpolated */ -static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) -{ - tGPDinterpolate_layer *tgpil; - bGPDstroke *new_stroke, *gps_from, *gps_to; - int cStroke; - float factor; - float shift = tgpi->shift; - - for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { - factor = tgpil->factor + shift; - for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) { - if (new_stroke->totpoints == 0) { - continue; - } - /* get strokes to interpolate */ - cStroke = BLI_findindex(&tgpil->interFrame->strokes, new_stroke); - gps_from = BLI_findlink(&tgpil->prevFrame->strokes, cStroke); - gps_to = BLI_findlink(&tgpil->nextFrame->strokes, cStroke); - /* update points position */ - if ((gps_from) && (gps_to)) { - gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); - } - } - } - - WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); -} - -/* Helper: Verify valid strokes for interpolation */ -static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - int flag = ts->gp_sculpt.flag; - - bGPDlayer *gpl; - bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); - bGPDstroke *gps_from, *gps_to; - int fFrame; - - /* get layers */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* all layers or only active */ - if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { - continue; - } - /* only editable and visible layers are considered */ - if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { - continue; - } - /* read strokes */ - for (gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) { - /* only selected */ - if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { - continue; - } - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps_from) == false) { - continue; - } - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { - continue; - } - /* get final stroke to interpolate */ - fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from); - gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame); - if (gps_to == NULL) { - continue; - } - return 1; - } - } - return 0; -} - -/* Helper: Create internal strokes interpolated */ -static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) -{ - bGPDlayer *gpl; - bGPdata *gpd = tgpi->gpd; - tGPDinterpolate_layer *tgpil; - bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); - bGPDstroke *gps_from, *gps_to, *new_stroke; - int fFrame; - - /* save initial factor for active layer to define shift limits */ - tgpi->init_factor = (float)(tgpi->cframe - active_gpl->actframe->framenum) / (active_gpl->actframe->next->framenum - active_gpl->actframe->framenum + 1); - /* limits are 100% below 0 and 100% over the 100% */ - tgpi->low_limit = -1.0f - tgpi->init_factor; - tgpi->high_limit = 2.0f - tgpi->init_factor; - - /* set layers */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* all layers or only active */ - if (((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { - continue; - } - /* only editable and visible layers are considered */ - if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { - continue; - } - /* create temp data for each layer */ - tgpil = NULL; - tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); - - tgpil->gpl = gpl; - tgpil->prevFrame = gpl->actframe; - tgpil->nextFrame = gpl->actframe->next; - - BLI_addtail(&tgpi->ilayers, tgpil); - /* create a new temporary frame */ - tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe"); - tgpil->interFrame->framenum = tgpi->cframe; - - /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */ - tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1); - /* create new strokes data with interpolated points reading original stroke */ - for (gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { - bool valid = true; - /* only selected */ - if ((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { - valid = false; - } - - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps_from) == false) { - valid = false; - } - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) { - valid = false; - } - /* get final stroke to interpolate */ - fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from); - gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame); - if (gps_to == NULL) { - valid = false; - } - /* create new stroke */ - new_stroke = MEM_dupallocN(gps_from); - new_stroke->points = MEM_dupallocN(gps_from->points); - new_stroke->triangles = MEM_dupallocN(gps_from->triangles); - if (valid) { - /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ - if (gps_from->totpoints > gps_to->totpoints) { - new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); - new_stroke->totpoints = gps_to->totpoints; - new_stroke->tot_triangles = 0; - new_stroke->flag |= GP_STROKE_RECALC_CACHES; - } - /* update points position */ - gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor); - } - else { - /* need an empty stroke to keep index correct for lookup, but resize to smallest size */ - new_stroke->totpoints = 0; - new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points)); - new_stroke->tot_triangles = 0; - new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles)); - } - /* add to strokes */ - BLI_addtail(&tgpil->interFrame->strokes, new_stroke); - } - } -} - -/* Helper: calculate shift based on position of mouse (we only use x-axis for now. -* since this is more convenient for users to do), and store new shift value -*/ -static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event) -{ - float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f; - float mpos = event->x - tgpi->ar->winrct.xmin; - if (mpos >= mid) { - tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid; - } - else { - tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid); - } - - CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); - RNA_float_set(op->ptr, "shift", tgpi->shift); -} - -/* Helper: Draw status message while the user is running the operator */ -static void gpencil_interpolate_status_indicators(tGPDinterpolate *p) -{ - Scene *scene = p->scene; - char status_str[UI_MAX_DRAW_STR]; - char msg_str[UI_MAX_DRAW_STR]; - BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust, Factor"), UI_MAX_DRAW_STR); - - if (hasNumInput(&p->num)) { - char str_offs[NUM_STR_REP_LEN]; - - outputNumInput(&p->num, str_offs, &scene->unit); - - BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs); - } - else { - BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f)); - } - - ED_area_headerprint(p->sa, status_str); -} - -/* Helper: Update screen and stroke */ -static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) -{ - /* update shift indicator in header */ - gpencil_interpolate_status_indicators(tgpi); - /* apply... */ - tgpi->shift = RNA_float_get(op->ptr, "shift"); - /* update points position */ - gp_interpolate_update_strokes(C, tgpi); -} - -/* init new temporary interpolation data */ -static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - bGPdata *gpd = CTX_data_gpencil_data(C); - - /* set current scene and window */ - tgpi->scene = CTX_data_scene(C); - tgpi->sa = CTX_wm_area(C); - tgpi->ar = CTX_wm_region(C); - tgpi->flag = ts->gp_sculpt.flag; - - /* set current frame number */ - tgpi->cframe = tgpi->scene->r.cfra; - - /* set GP datablock */ - tgpi->gpd = gpd; - - /* set interpolation weight */ - tgpi->shift = RNA_float_get(op->ptr, "shift"); - /* set layers */ - gp_interpolate_set_points(C, tgpi); - - return 1; -} - -/* Poll handler: check if context is suitable for interpolation */ -static int gpencil_interpolate_poll(bContext *C) -{ - bGPdata * gpd = CTX_data_gpencil_data(C); - bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); - /* only 3D view */ - if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) { - return 0; - } - /* need data to interpolate */ - if (ELEM(NULL, gpd, gpl)) { - return 0; - } - - return 1; -} - -/* Allocate memory and initialize values */ -static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op) -{ - tGPDinterpolate *tgpi = NULL; - - /* create new context data */ - tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data"); - - /* define initial values */ - gp_interpolate_set_init_values(C, op, tgpi); - - /* return context data for running operator */ - return tgpi; -} - -/* Exit and free memory */ -static void gpencil_interpolate_exit(bContext *C, wmOperator *op) -{ - tGPDinterpolate *tgpi = op->customdata; - tGPDinterpolate_layer *tgpil; - - /* don't assume that operator data exists at all */ - if (tgpi) { - /* remove drawing handler */ - if (tgpi->draw_handle_screen) { - ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen); - } - if (tgpi->draw_handle_3d) { - ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d); - } - /* clear status message area */ - ED_area_headerprint(tgpi->sa, NULL); - /* finally, free memory used by temp data */ - for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { - BKE_gpencil_free_strokes(tgpil->interFrame); - MEM_freeN(tgpil->interFrame); - } - - BLI_freelistN(&tgpi->ilayers); - MEM_freeN(tgpi); - } - WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - - /* clear pointer */ - op->customdata = NULL; -} - -/* Cancel handler */ -static void gpencil_interpolate_cancel(bContext *C, wmOperator *op) -{ - /* this is just a wrapper around exit() */ - gpencil_interpolate_exit(C, op); -} - -/* Init interpolation: Allocate memory and set init values */ -static int gpencil_interpolate_init(bContext *C, wmOperator *op) -{ - tGPDinterpolate *tgpi; - /* check context */ - tgpi = op->customdata = gp_session_init_interpolation(C, op); - if (tgpi == NULL) { - /* something wasn't set correctly in context */ - gpencil_interpolate_exit(C, op); - return 0; - } - - /* everything is now setup ok */ - return 1; -} - -/* ********************** custom drawcall api ***************** */ -/* Helper: drawing callback for modal operator in screen mode */ -static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) -{ - wmOperator *op = arg; - struct tGPDinterpolate *tgpi = op->customdata; - ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL); -} - -/* Helper: drawing callback for modal operator in 3d mode */ -static void gpencil_interpolate_draw_3d(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) -{ - wmOperator *op = arg; - struct tGPDinterpolate *tgpi = op->customdata; - ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW); -} - -/* Invoke handler: Initialize the operator */ -static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - wmWindow *win = CTX_wm_window(C); - Scene *scene = CTX_data_scene(C); - bGPdata * gpd = CTX_data_gpencil_data(C); - bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); - tGPDinterpolate *tgpi = NULL; - - /* cannot interpolate if not between 2 frames */ - if ((gpl->actframe == NULL) || (gpl->actframe->next == NULL)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer"); - return OPERATOR_CANCELLED; - } - - /* cannot interpolate in extremes */ - if ((gpl->actframe->framenum == scene->r.cfra) || (gpl->actframe->next->framenum == scene->r.cfra)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer"); - return OPERATOR_CANCELLED; - } - - /* need editable strokes */ - if (!gp_interpolate_check_todo(C, gpd)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable stroke"); - return OPERATOR_CANCELLED; - } - - /* try to initialize context data needed */ - if (!gpencil_interpolate_init(C, op)) { - if (op->customdata) - MEM_freeN(op->customdata); - return OPERATOR_CANCELLED; - } - else - tgpi = op->customdata; - - /* enable custom drawing handlers. It needs 2 handlers because can be strokes in 3d space and screen space and each handler use different - coord system */ - tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, op, REGION_DRAW_POST_PIXEL); - tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, op, REGION_DRAW_POST_VIEW); - /* set cursor to indicate modal */ - WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR); - /* update shift indicator in header */ - gpencil_interpolate_status_indicators(tgpi); - WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - - /* add a modal handler for this operator */ - WM_event_add_modal_handler(C, op); - - return OPERATOR_RUNNING_MODAL; -} - -/* Modal handler: Events handling during interactive part */ -static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - tGPDinterpolate *tgpi = op->customdata; - wmWindow *win = CTX_wm_window(C); - bGPDframe *gpf_dst; - bGPDstroke *gps_src, *gps_dst; - tGPDinterpolate_layer *tgpil; - const bool has_numinput = hasNumInput(&tgpi->num); - - switch (event->type) { - case LEFTMOUSE: /* confirm */ - case RETKEY: - { - /* return to normal cursor and header status */ - ED_area_headerprint(tgpi->sa, NULL); - WM_cursor_modal_restore(win); - - /* insert keyframes as required... */ - for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { - gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW); - gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN; - - /* copy strokes */ - BLI_listbase_clear(&gpf_dst->strokes); - for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) { - if (gps_src->totpoints == 0) { - continue; - } - /* make copy of source stroke, then adjust pointer to points too */ - gps_dst = MEM_dupallocN(gps_src); - gps_dst->points = MEM_dupallocN(gps_src->points); - gps_dst->triangles = MEM_dupallocN(gps_src->triangles); - gps_dst->flag |= GP_STROKE_RECALC_CACHES; - BLI_addtail(&gpf_dst->strokes, gps_dst); - } - } - /* clean up temp data */ - gpencil_interpolate_exit(C, op); - - /* done! */ - return OPERATOR_FINISHED; - } - - case ESCKEY: /* cancel */ - case RIGHTMOUSE: - { - /* return to normal cursor and header status */ - ED_area_headerprint(tgpi->sa, NULL); - WM_cursor_modal_restore(win); - - /* clean up temp data */ - gpencil_interpolate_exit(C, op); - - /* canceled! */ - return OPERATOR_CANCELLED; - } - case WHEELUPMOUSE: - { - tgpi->shift = tgpi->shift + 0.01f; - CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); - RNA_float_set(op->ptr, "shift", tgpi->shift); - /* update screen */ - gpencil_interpolate_update(C, op, tgpi); - break; - } - case WHEELDOWNMOUSE: - { - tgpi->shift = tgpi->shift - 0.01f; - CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); - RNA_float_set(op->ptr, "shift", tgpi->shift); - /* update screen */ - gpencil_interpolate_update(C, op, tgpi); - break; - } - case MOUSEMOVE: /* calculate new position */ - { - /* only handle mousemove if not doing numinput */ - if (has_numinput == false) { - /* update shift based on position of mouse */ - gpencil_mouse_update_shift(tgpi, op, event); - /* update screen */ - gpencil_interpolate_update(C, op, tgpi); - } - break; - } - default: - if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) { - float value; - float factor = tgpi->init_factor; - - /* Grab shift from numeric input, and store this new value (the user see an int) */ - value = (factor + tgpi->shift) * 100.0f; - applyNumInput(&tgpi->num, &value); - tgpi->shift = value / 100.0f; - /* recalculate the shift to get the right value in the frame scale */ - tgpi->shift = tgpi->shift - factor; - - CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); - RNA_float_set(op->ptr, "shift", tgpi->shift); - - /* update screen */ - gpencil_interpolate_update(C, op, tgpi); - - break; - } - else { - /* unhandled event - allow to pass through */ - return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; - } - } - - /* still running... */ - return OPERATOR_RUNNING_MODAL; -} - -/* Define modal operator for interpolation */ -void GPENCIL_OT_interpolate(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Grease Pencil Interpolation"; - ot->idname = "GPENCIL_OT_interpolate"; - ot->description = "Interpolate grease pencil strokes between frames"; - - /* api callbacks */ - ot->invoke = gpencil_interpolate_invoke; - ot->modal = gpencil_interpolate_modal; - ot->cancel = gpencil_interpolate_cancel; - ot->poll = gpencil_interpolate_poll; - - /* flags */ - ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; - - RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Displacement factor for the interpolate operation", -0.9f, 0.9f); -} - -/* =============== Interpolate sequence ===============*/ -/* Create Sequence Interpolation */ -static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = CTX_data_tool_settings(C); - bGPdata * gpd = CTX_data_gpencil_data(C); - bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); - bGPDlayer *gpl; - bGPDframe *prevFrame, *nextFrame, *interFrame; - bGPDstroke *gps_from, *gps_to, *new_stroke; - float factor; - int cframe, fFrame; - int flag = ts->gp_sculpt.flag; - - /* cannot interpolate if not between 2 frames */ - if ((active_gpl->actframe == NULL) || (active_gpl->actframe->next == NULL)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames"); - return OPERATOR_CANCELLED; - } - /* cannot interpolate in extremes */ - if ((active_gpl->actframe->framenum == scene->r.cfra) || (active_gpl->actframe->next->framenum == scene->r.cfra)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames"); - return OPERATOR_CANCELLED; - } - - /* loop all layer to check if need interpolation */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { - /* all layers or only active */ - if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { - continue; - } - /* only editable and visible layers are considered */ - if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { - continue; - } - /* store extremes */ - prevFrame = gpl->actframe; - nextFrame = gpl->actframe->next; - /* Loop over intermediary frames and create the interpolation */ - for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) { - interFrame = NULL; - - /* get interpolation factor */ - factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1); - - /* create new strokes data with interpolated points reading original stroke */ - for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { - /* only selected */ - if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { - continue; - } - /* skip strokes that are invalid for current view */ - if (ED_gpencil_stroke_can_use(C, gps_from) == false) { - continue; - } - /* check if the color is editable */ - if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { - continue; - } - /* get final stroke to interpolate */ - fFrame = BLI_findindex(&prevFrame->strokes, gps_from); - gps_to = BLI_findlink(&nextFrame->strokes, fFrame); - if (gps_to == NULL) { - continue; - } - /* create a new frame if needed */ - if (interFrame == NULL) { - interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW); - interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; - } - /* create new stroke */ - new_stroke = MEM_dupallocN(gps_from); - new_stroke->points = MEM_dupallocN(gps_from->points); - new_stroke->triangles = MEM_dupallocN(gps_from->triangles); - /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ - if (gps_from->totpoints > gps_to->totpoints) { - new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); - new_stroke->totpoints = gps_to->totpoints; - new_stroke->tot_triangles = 0; - new_stroke->flag |= GP_STROKE_RECALC_CACHES; - } - /* update points position */ - gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); - - /* add to strokes */ - BLI_addtail(&interFrame->strokes, new_stroke); - } - } - } - - /* notifiers */ - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - - return OPERATOR_FINISHED; -} - -/* Define sequence interpolation */ -void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Grease Pencil Sequence Interpolation"; - ot->idname = "GPENCIL_OT_interpolate_sequence"; - ot->description = "Interpolate full grease pencil strokes sequence between frames"; - - /* api callbacks */ - ot->exec = gpencil_interpolate_seq_exec; - ot->poll = gpencil_interpolate_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} -/* ========= End Interpolation operators ========================== */ diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c new file mode 100644 index 00000000000..154776dbb5c --- /dev/null +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -0,0 +1,753 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2016, Blender Foundation + * This is a new part of Blender + * + * Contributor(s): Antonio Vazquez, Joshua Leung + * + * ***** END GPL LICENSE BLOCK ***** + * + * Operators for interpolating new Grease Pencil frames from existing strokes + */ + +/** \file blender/editors/gpencil/gpencil_interpolate.c + * \ingroup edgpencil + */ + + +#include +#include +#include +#include +#include + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_view3d_types.h" +#include "DNA_gpencil_types.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_gpencil.h" +#include "BKE_library.h" +#include "BKE_report.h" +#include "BKE_screen.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "UI_view2d.h" + +#include "ED_gpencil.h" +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_view3d.h" +#include "ED_screen.h" +#include "ED_space_api.h" + +#include "gpencil_intern.h" + +/* ************************************************ */ + +/* ========= Interpolation operators ========================== */ +/* Helper: Update point with interpolation */ +static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor) +{ + bGPDspoint *prev, *pt, *next; + + /* update points */ + for (int i = 0; i < new_stroke->totpoints; i++) { + prev = &gps_from->points[i]; + pt = &new_stroke->points[i]; + next = &gps_to->points[i]; + + /* Interpolate all values */ + interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor); + pt->pressure = interpf(prev->pressure, next->pressure, factor); + pt->strength = interpf(prev->strength, next->strength, factor); + CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + } +} + +/* Helper: Update all strokes interpolated */ +static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) +{ + tGPDinterpolate_layer *tgpil; + bGPDstroke *new_stroke, *gps_from, *gps_to; + int cStroke; + float factor; + float shift = tgpi->shift; + + for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { + factor = tgpil->factor + shift; + for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) { + if (new_stroke->totpoints == 0) { + continue; + } + /* get strokes to interpolate */ + cStroke = BLI_findindex(&tgpil->interFrame->strokes, new_stroke); + gps_from = BLI_findlink(&tgpil->prevFrame->strokes, cStroke); + gps_to = BLI_findlink(&tgpil->nextFrame->strokes, cStroke); + /* update points position */ + if ((gps_from) && (gps_to)) { + gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); + } + } + } + + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); +} + +/* Helper: Verify valid strokes for interpolation */ +static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + int flag = ts->gp_sculpt.flag; + + bGPDlayer *gpl; + bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); + bGPDstroke *gps_from, *gps_to; + int fFrame; + + /* get layers */ + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* all layers or only active */ + if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { + continue; + } + /* only editable and visible layers are considered */ + if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { + continue; + } + /* read strokes */ + for (gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) { + /* only selected */ + if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { + continue; + } + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps_from) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { + continue; + } + /* get final stroke to interpolate */ + fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from); + gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame); + if (gps_to == NULL) { + continue; + } + return 1; + } + } + return 0; +} + +/* Helper: Create internal strokes interpolated */ +static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) +{ + bGPDlayer *gpl; + bGPdata *gpd = tgpi->gpd; + tGPDinterpolate_layer *tgpil; + bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); + bGPDstroke *gps_from, *gps_to, *new_stroke; + int fFrame; + + /* save initial factor for active layer to define shift limits */ + tgpi->init_factor = (float)(tgpi->cframe - active_gpl->actframe->framenum) / (active_gpl->actframe->next->framenum - active_gpl->actframe->framenum + 1); + /* limits are 100% below 0 and 100% over the 100% */ + tgpi->low_limit = -1.0f - tgpi->init_factor; + tgpi->high_limit = 2.0f - tgpi->init_factor; + + /* set layers */ + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* all layers or only active */ + if (((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { + continue; + } + /* only editable and visible layers are considered */ + if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { + continue; + } + /* create temp data for each layer */ + tgpil = NULL; + tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); + + tgpil->gpl = gpl; + tgpil->prevFrame = gpl->actframe; + tgpil->nextFrame = gpl->actframe->next; + + BLI_addtail(&tgpi->ilayers, tgpil); + /* create a new temporary frame */ + tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe"); + tgpil->interFrame->framenum = tgpi->cframe; + + /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */ + tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1); + /* create new strokes data with interpolated points reading original stroke */ + for (gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { + bool valid = true; + /* only selected */ + if ((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { + valid = false; + } + + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps_from) == false) { + valid = false; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) { + valid = false; + } + /* get final stroke to interpolate */ + fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from); + gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame); + if (gps_to == NULL) { + valid = false; + } + /* create new stroke */ + new_stroke = MEM_dupallocN(gps_from); + new_stroke->points = MEM_dupallocN(gps_from->points); + new_stroke->triangles = MEM_dupallocN(gps_from->triangles); + if (valid) { + /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ + if (gps_from->totpoints > gps_to->totpoints) { + new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); + new_stroke->totpoints = gps_to->totpoints; + new_stroke->tot_triangles = 0; + new_stroke->flag |= GP_STROKE_RECALC_CACHES; + } + /* update points position */ + gp_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor); + } + else { + /* need an empty stroke to keep index correct for lookup, but resize to smallest size */ + new_stroke->totpoints = 0; + new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points)); + new_stroke->tot_triangles = 0; + new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles)); + } + /* add to strokes */ + BLI_addtail(&tgpil->interFrame->strokes, new_stroke); + } + } +} + +/* Helper: calculate shift based on position of mouse (we only use x-axis for now. +* since this is more convenient for users to do), and store new shift value +*/ +static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event) +{ + float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f; + float mpos = event->x - tgpi->ar->winrct.xmin; + if (mpos >= mid) { + tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid; + } + else { + tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid); + } + + CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); + RNA_float_set(op->ptr, "shift", tgpi->shift); +} + +/* Helper: Draw status message while the user is running the operator */ +static void gpencil_interpolate_status_indicators(tGPDinterpolate *p) +{ + Scene *scene = p->scene; + char status_str[UI_MAX_DRAW_STR]; + char msg_str[UI_MAX_DRAW_STR]; + BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust, Factor"), UI_MAX_DRAW_STR); + + if (hasNumInput(&p->num)) { + char str_offs[NUM_STR_REP_LEN]; + + outputNumInput(&p->num, str_offs, &scene->unit); + + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs); + } + else { + BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f)); + } + + ED_area_headerprint(p->sa, status_str); +} + +/* Helper: Update screen and stroke */ +static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) +{ + /* update shift indicator in header */ + gpencil_interpolate_status_indicators(tgpi); + /* apply... */ + tgpi->shift = RNA_float_get(op->ptr, "shift"); + /* update points position */ + gp_interpolate_update_strokes(C, tgpi); +} + +/* init new temporary interpolation data */ +static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) +{ + ToolSettings *ts = CTX_data_tool_settings(C); + bGPdata *gpd = CTX_data_gpencil_data(C); + + /* set current scene and window */ + tgpi->scene = CTX_data_scene(C); + tgpi->sa = CTX_wm_area(C); + tgpi->ar = CTX_wm_region(C); + tgpi->flag = ts->gp_sculpt.flag; + + /* set current frame number */ + tgpi->cframe = tgpi->scene->r.cfra; + + /* set GP datablock */ + tgpi->gpd = gpd; + + /* set interpolation weight */ + tgpi->shift = RNA_float_get(op->ptr, "shift"); + /* set layers */ + gp_interpolate_set_points(C, tgpi); + + return 1; +} + +/* Poll handler: check if context is suitable for interpolation */ +static int gpencil_interpolate_poll(bContext *C) +{ + bGPdata * gpd = CTX_data_gpencil_data(C); + bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + /* only 3D view */ + if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) { + return 0; + } + /* need data to interpolate */ + if (ELEM(NULL, gpd, gpl)) { + return 0; + } + + return 1; +} + +/* Allocate memory and initialize values */ +static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op) +{ + tGPDinterpolate *tgpi = NULL; + + /* create new context data */ + tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data"); + + /* define initial values */ + gp_interpolate_set_init_values(C, op, tgpi); + + /* return context data for running operator */ + return tgpi; +} + +/* Exit and free memory */ +static void gpencil_interpolate_exit(bContext *C, wmOperator *op) +{ + tGPDinterpolate *tgpi = op->customdata; + tGPDinterpolate_layer *tgpil; + + /* don't assume that operator data exists at all */ + if (tgpi) { + /* remove drawing handler */ + if (tgpi->draw_handle_screen) { + ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_screen); + } + if (tgpi->draw_handle_3d) { + ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d); + } + /* clear status message area */ + ED_area_headerprint(tgpi->sa, NULL); + /* finally, free memory used by temp data */ + for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { + BKE_gpencil_free_strokes(tgpil->interFrame); + MEM_freeN(tgpil->interFrame); + } + + BLI_freelistN(&tgpi->ilayers); + MEM_freeN(tgpi); + } + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + + /* clear pointer */ + op->customdata = NULL; +} + +/* Cancel handler */ +static void gpencil_interpolate_cancel(bContext *C, wmOperator *op) +{ + /* this is just a wrapper around exit() */ + gpencil_interpolate_exit(C, op); +} + +/* Init interpolation: Allocate memory and set init values */ +static int gpencil_interpolate_init(bContext *C, wmOperator *op) +{ + tGPDinterpolate *tgpi; + /* check context */ + tgpi = op->customdata = gp_session_init_interpolation(C, op); + if (tgpi == NULL) { + /* something wasn't set correctly in context */ + gpencil_interpolate_exit(C, op); + return 0; + } + + /* everything is now setup ok */ + return 1; +} + +/* ********************** custom drawcall api ***************** */ +/* Helper: drawing callback for modal operator in screen mode */ +static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) +{ + wmOperator *op = arg; + struct tGPDinterpolate *tgpi = op->customdata; + ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL); +} + +/* Helper: drawing callback for modal operator in 3d mode */ +static void gpencil_interpolate_draw_3d(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) +{ + wmOperator *op = arg; + struct tGPDinterpolate *tgpi = op->customdata; + ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW); +} + +/* Invoke handler: Initialize the operator */ +static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + wmWindow *win = CTX_wm_window(C); + Scene *scene = CTX_data_scene(C); + bGPdata * gpd = CTX_data_gpencil_data(C); + bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + tGPDinterpolate *tgpi = NULL; + + /* cannot interpolate if not between 2 frames */ + if ((gpl->actframe == NULL) || (gpl->actframe->next == NULL)) { + BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer"); + return OPERATOR_CANCELLED; + } + + /* cannot interpolate in extremes */ + if ((gpl->actframe->framenum == scene->r.cfra) || (gpl->actframe->next->framenum == scene->r.cfra)) { + BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer"); + return OPERATOR_CANCELLED; + } + + /* need editable strokes */ + if (!gp_interpolate_check_todo(C, gpd)) { + BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable stroke"); + return OPERATOR_CANCELLED; + } + + /* try to initialize context data needed */ + if (!gpencil_interpolate_init(C, op)) { + if (op->customdata) + MEM_freeN(op->customdata); + return OPERATOR_CANCELLED; + } + else + tgpi = op->customdata; + + /* enable custom drawing handlers. It needs 2 handlers because can be strokes in 3d space and screen space and each handler use different + coord system */ + tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, op, REGION_DRAW_POST_PIXEL); + tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, op, REGION_DRAW_POST_VIEW); + /* set cursor to indicate modal */ + WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR); + /* update shift indicator in header */ + gpencil_interpolate_status_indicators(tgpi); + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); + + /* add a modal handler for this operator */ + WM_event_add_modal_handler(C, op); + + return OPERATOR_RUNNING_MODAL; +} + +/* Modal handler: Events handling during interactive part */ +static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + tGPDinterpolate *tgpi = op->customdata; + wmWindow *win = CTX_wm_window(C); + bGPDframe *gpf_dst; + bGPDstroke *gps_src, *gps_dst; + tGPDinterpolate_layer *tgpil; + const bool has_numinput = hasNumInput(&tgpi->num); + + switch (event->type) { + case LEFTMOUSE: /* confirm */ + case RETKEY: + { + /* return to normal cursor and header status */ + ED_area_headerprint(tgpi->sa, NULL); + WM_cursor_modal_restore(win); + + /* insert keyframes as required... */ + for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { + gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW); + gpf_dst->key_type = BEZT_KEYTYPE_BREAKDOWN; + + /* copy strokes */ + BLI_listbase_clear(&gpf_dst->strokes); + for (gps_src = tgpil->interFrame->strokes.first; gps_src; gps_src = gps_src->next) { + if (gps_src->totpoints == 0) { + continue; + } + /* make copy of source stroke, then adjust pointer to points too */ + gps_dst = MEM_dupallocN(gps_src); + gps_dst->points = MEM_dupallocN(gps_src->points); + gps_dst->triangles = MEM_dupallocN(gps_src->triangles); + gps_dst->flag |= GP_STROKE_RECALC_CACHES; + BLI_addtail(&gpf_dst->strokes, gps_dst); + } + } + /* clean up temp data */ + gpencil_interpolate_exit(C, op); + + /* done! */ + return OPERATOR_FINISHED; + } + + case ESCKEY: /* cancel */ + case RIGHTMOUSE: + { + /* return to normal cursor and header status */ + ED_area_headerprint(tgpi->sa, NULL); + WM_cursor_modal_restore(win); + + /* clean up temp data */ + gpencil_interpolate_exit(C, op); + + /* canceled! */ + return OPERATOR_CANCELLED; + } + case WHEELUPMOUSE: + { + tgpi->shift = tgpi->shift + 0.01f; + CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); + RNA_float_set(op->ptr, "shift", tgpi->shift); + /* update screen */ + gpencil_interpolate_update(C, op, tgpi); + break; + } + case WHEELDOWNMOUSE: + { + tgpi->shift = tgpi->shift - 0.01f; + CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); + RNA_float_set(op->ptr, "shift", tgpi->shift); + /* update screen */ + gpencil_interpolate_update(C, op, tgpi); + break; + } + case MOUSEMOVE: /* calculate new position */ + { + /* only handle mousemove if not doing numinput */ + if (has_numinput == false) { + /* update shift based on position of mouse */ + gpencil_mouse_update_shift(tgpi, op, event); + /* update screen */ + gpencil_interpolate_update(C, op, tgpi); + } + break; + } + default: + if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) { + float value; + float factor = tgpi->init_factor; + + /* Grab shift from numeric input, and store this new value (the user see an int) */ + value = (factor + tgpi->shift) * 100.0f; + applyNumInput(&tgpi->num, &value); + tgpi->shift = value / 100.0f; + /* recalculate the shift to get the right value in the frame scale */ + tgpi->shift = tgpi->shift - factor; + + CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); + RNA_float_set(op->ptr, "shift", tgpi->shift); + + /* update screen */ + gpencil_interpolate_update(C, op, tgpi); + + break; + } + else { + /* unhandled event - allow to pass through */ + return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; + } + } + + /* still running... */ + return OPERATOR_RUNNING_MODAL; +} + +/* Define modal operator for interpolation */ +void GPENCIL_OT_interpolate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Grease Pencil Interpolation"; + ot->idname = "GPENCIL_OT_interpolate"; + ot->description = "Interpolate grease pencil strokes between frames"; + + /* api callbacks */ + ot->invoke = gpencil_interpolate_invoke; + ot->modal = gpencil_interpolate_modal; + ot->cancel = gpencil_interpolate_cancel; + ot->poll = gpencil_interpolate_poll; + + /* flags */ + ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; + + RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Displacement factor for the interpolate operation", -0.9f, 0.9f); +} + +/* =============== Interpolate sequence ===============*/ +/* Create Sequence Interpolation */ +static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = CTX_data_tool_settings(C); + bGPdata * gpd = CTX_data_gpencil_data(C); + bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); + bGPDlayer *gpl; + bGPDframe *prevFrame, *nextFrame, *interFrame; + bGPDstroke *gps_from, *gps_to, *new_stroke; + float factor; + int cframe, fFrame; + int flag = ts->gp_sculpt.flag; + + /* cannot interpolate if not between 2 frames */ + if ((active_gpl->actframe == NULL) || (active_gpl->actframe->next == NULL)) { + BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames"); + return OPERATOR_CANCELLED; + } + /* cannot interpolate in extremes */ + if ((active_gpl->actframe->framenum == scene->r.cfra) || (active_gpl->actframe->next->framenum == scene->r.cfra)) { + BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames"); + return OPERATOR_CANCELLED; + } + + /* loop all layer to check if need interpolation */ + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* all layers or only active */ + if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { + continue; + } + /* only editable and visible layers are considered */ + if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { + continue; + } + /* store extremes */ + prevFrame = gpl->actframe; + nextFrame = gpl->actframe->next; + /* Loop over intermediary frames and create the interpolation */ + for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) { + interFrame = NULL; + + /* get interpolation factor */ + factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1); + + /* create new strokes data with interpolated points reading original stroke */ + for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { + /* only selected */ + if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { + continue; + } + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps_from) == false) { + continue; + } + /* check if the color is editable */ + if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { + continue; + } + /* get final stroke to interpolate */ + fFrame = BLI_findindex(&prevFrame->strokes, gps_from); + gps_to = BLI_findlink(&nextFrame->strokes, fFrame); + if (gps_to == NULL) { + continue; + } + /* create a new frame if needed */ + if (interFrame == NULL) { + interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW); + interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; + } + /* create new stroke */ + new_stroke = MEM_dupallocN(gps_from); + new_stroke->points = MEM_dupallocN(gps_from->points); + new_stroke->triangles = MEM_dupallocN(gps_from->triangles); + /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ + if (gps_from->totpoints > gps_to->totpoints) { + new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); + new_stroke->totpoints = gps_to->totpoints; + new_stroke->tot_triangles = 0; + new_stroke->flag |= GP_STROKE_RECALC_CACHES; + } + /* update points position */ + gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); + + /* add to strokes */ + BLI_addtail(&interFrame->strokes, new_stroke); + } + } + } + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +/* Define sequence interpolation */ +void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Grease Pencil Sequence Interpolation"; + ot->idname = "GPENCIL_OT_interpolate_sequence"; + ot->description = "Interpolate full grease pencil strokes sequence between frames"; + + /* api callbacks */ + ot->exec = gpencil_interpolate_seq_exec; + ot->poll = gpencil_interpolate_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ========= End Interpolation operators ========================== */ From fd119a3723f0a17e86214257867aa92bb99f3c0a Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 18 Jan 2017 00:48:15 +1300 Subject: [PATCH 521/590] Code Cleanup for GP Interpolation ops (first pass) * Reshuffled some blocks of code for better ease of navigation/flow in the file * Improved some tooltips * Removed "Helper" tag from some functions that serve bigger roles * Fixed some errant formatting --- source/blender/editors/gpencil/gpencil_edit.c | 1 + .../editors/gpencil/gpencil_interpolate.c | 367 ++++++++++-------- 2 files changed, 208 insertions(+), 160 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index f01dfee494a..36c7ef78d96 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1981,6 +1981,7 @@ void GPENCIL_OT_reproject(wmOperatorType *ot) } /* ******************* Stroke subdivide ************************** */ + /* helper: Count how many points need to be inserted */ static int gp_count_subdivision_cuts(bGPDstroke *gps) { diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 154776dbb5c..703bacf8554 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -80,19 +80,38 @@ #include "gpencil_intern.h" /* ************************************************ */ +/* Core/Shared Utilities */ -/* ========= Interpolation operators ========================== */ -/* Helper: Update point with interpolation */ +/* Poll callback for interpolation operators */ +static int gpencil_interpolate_poll(bContext *C) +{ + bGPdata *gpd = CTX_data_gpencil_data(C); + bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + + /* only 3D view */ + if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) { + return 0; + } + + /* need data to interpolate */ + if (ELEM(NULL, gpd, gpl)) { + return 0; + } + + return 1; +} + +/* Perform interpolation */ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_to, bGPDstroke *new_stroke, float factor) { bGPDspoint *prev, *pt, *next; - + /* update points */ for (int i = 0; i < new_stroke->totpoints; i++) { prev = &gps_from->points[i]; pt = &new_stroke->points[i]; next = &gps_to->points[i]; - + /* Interpolate all values */ interp_v3_v3v3(&pt->x, &prev->x, &next->x, factor); pt->pressure = interpf(prev->pressure, next->pressure, factor); @@ -101,32 +120,39 @@ static void gp_interpolate_update_points(bGPDstroke *gps_from, bGPDstroke *gps_t } } +/* ****************** Interpolate Interactive *********************** */ + /* Helper: Update all strokes interpolated */ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) { tGPDinterpolate_layer *tgpil; - bGPDstroke *new_stroke, *gps_from, *gps_to; - int cStroke; - float factor; - float shift = tgpi->shift; - + const float shift = tgpi->shift; + for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { - factor = tgpil->factor + shift; + bGPDstroke *new_stroke; + const float factor = tgpil->factor + shift; + for (new_stroke = tgpil->interFrame->strokes.first; new_stroke; new_stroke = new_stroke->next) { + bGPDstroke *gps_from, *gps_to; + int stroke_idx; + if (new_stroke->totpoints == 0) { continue; } + /* get strokes to interpolate */ - cStroke = BLI_findindex(&tgpil->interFrame->strokes, new_stroke); - gps_from = BLI_findlink(&tgpil->prevFrame->strokes, cStroke); - gps_to = BLI_findlink(&tgpil->nextFrame->strokes, cStroke); + stroke_idx = BLI_findindex(&tgpil->interFrame->strokes, new_stroke); + + gps_from = BLI_findlink(&tgpil->prevFrame->strokes, stroke_idx); + gps_to = BLI_findlink(&tgpil->nextFrame->strokes, stroke_idx); + /* update points position */ if ((gps_from) && (gps_to)) { gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); } } } - + WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); } @@ -135,12 +161,12 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) { ToolSettings *ts = CTX_data_tool_settings(C); int flag = ts->gp_sculpt.flag; - + bGPDlayer *gpl; bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); bGPDstroke *gps_from, *gps_to; int fFrame; - + /* get layers */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* all layers or only active */ @@ -151,6 +177,7 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } + /* read strokes */ for (gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) { /* only selected */ @@ -165,12 +192,14 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { continue; } + /* get final stroke to interpolate */ fFrame = BLI_findindex(&gpl->actframe->strokes, gps_from); gps_to = BLI_findlink(&gpl->actframe->next->strokes, fFrame); if (gps_to == NULL) { continue; } + return 1; } } @@ -186,13 +215,14 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); bGPDstroke *gps_from, *gps_to, *new_stroke; int fFrame; - + /* save initial factor for active layer to define shift limits */ tgpi->init_factor = (float)(tgpi->cframe - active_gpl->actframe->framenum) / (active_gpl->actframe->next->framenum - active_gpl->actframe->framenum + 1); + /* limits are 100% below 0 and 100% over the 100% */ tgpi->low_limit = -1.0f - tgpi->init_factor; tgpi->high_limit = 2.0f - tgpi->init_factor; - + /* set layers */ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* all layers or only active */ @@ -203,47 +233,54 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } + /* create temp data for each layer */ tgpil = NULL; tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); - + tgpil->gpl = gpl; tgpil->prevFrame = gpl->actframe; tgpil->nextFrame = gpl->actframe->next; - + BLI_addtail(&tgpi->ilayers, tgpil); + /* create a new temporary frame */ tgpil->interFrame = MEM_callocN(sizeof(bGPDframe), "bGPDframe"); tgpil->interFrame->framenum = tgpi->cframe; - + /* get interpolation factor by layer (usually must be equal for all layers, but not sure) */ tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1); + /* create new strokes data with interpolated points reading original stroke */ for (gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { bool valid = true; + /* only selected */ if ((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { valid = false; } - /* skip strokes that are invalid for current view */ if (ED_gpencil_stroke_can_use(C, gps_from) == false) { valid = false; } + /* check if the color is editable */ if (ED_gpencil_stroke_color_use(tgpil->gpl, gps_from) == false) { valid = false; } + /* get final stroke to interpolate */ fFrame = BLI_findindex(&tgpil->prevFrame->strokes, gps_from); gps_to = BLI_findlink(&tgpil->nextFrame->strokes, fFrame); if (gps_to == NULL) { valid = false; } + /* create new stroke */ new_stroke = MEM_dupallocN(gps_from); new_stroke->points = MEM_dupallocN(gps_from->points); new_stroke->triangles = MEM_dupallocN(gps_from->triangles); + if (valid) { /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { @@ -262,26 +299,47 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) new_stroke->tot_triangles = 0; new_stroke->triangles = MEM_recallocN(new_stroke->triangles, sizeof(*new_stroke->triangles)); } + /* add to strokes */ BLI_addtail(&tgpil->interFrame->strokes, new_stroke); } } } +/* ----------------------- */ +/* Drawing Callbacks */ + +/* Drawing callback for modal operator in screen mode */ +static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) +{ + tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; + ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL); +} + +/* Drawing callback for modal operator in 3d mode */ +static void gpencil_interpolate_draw_3d(const bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) +{ + tGPDinterpolate *tgpi = (tGPDinterpolate *)arg; + ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW); +} + +/* ----------------------- */ + /* Helper: calculate shift based on position of mouse (we only use x-axis for now. -* since this is more convenient for users to do), and store new shift value -*/ + * since this is more convenient for users to do), and store new shift value + */ static void gpencil_mouse_update_shift(tGPDinterpolate *tgpi, wmOperator *op, const wmEvent *event) { float mid = (float)(tgpi->ar->winx - tgpi->ar->winrct.xmin) / 2.0f; float mpos = event->x - tgpi->ar->winrct.xmin; + if (mpos >= mid) { tgpi->shift = ((mpos - mid) * tgpi->high_limit) / mid; } else { tgpi->shift = tgpi->low_limit - ((mpos * tgpi->low_limit) / mid); } - + CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); } @@ -292,23 +350,24 @@ static void gpencil_interpolate_status_indicators(tGPDinterpolate *p) Scene *scene = p->scene; char status_str[UI_MAX_DRAW_STR]; char msg_str[UI_MAX_DRAW_STR]; - BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust, Factor"), UI_MAX_DRAW_STR); - + + BLI_strncpy(msg_str, IFACE_("GPencil Interpolation: ESC/RMB to cancel, Enter/LMB to confirm, WHEEL/MOVE to adjust factor"), UI_MAX_DRAW_STR); + if (hasNumInput(&p->num)) { char str_offs[NUM_STR_REP_LEN]; - + outputNumInput(&p->num, str_offs, &scene->unit); - + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs); } else { BLI_snprintf(status_str, sizeof(status_str), "%s: %d %%", msg_str, (int)((p->init_factor + p->shift) * 100.0f)); } - + ED_area_headerprint(p->sa, status_str); } -/* Helper: Update screen and stroke */ +/* Update screen and stroke */ static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) { /* update shift indicator in header */ @@ -319,70 +378,14 @@ static void gpencil_interpolate_update(bContext *C, wmOperator *op, tGPDinterpol gp_interpolate_update_strokes(C, tgpi); } -/* init new temporary interpolation data */ -static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) -{ - ToolSettings *ts = CTX_data_tool_settings(C); - bGPdata *gpd = CTX_data_gpencil_data(C); - - /* set current scene and window */ - tgpi->scene = CTX_data_scene(C); - tgpi->sa = CTX_wm_area(C); - tgpi->ar = CTX_wm_region(C); - tgpi->flag = ts->gp_sculpt.flag; - - /* set current frame number */ - tgpi->cframe = tgpi->scene->r.cfra; - - /* set GP datablock */ - tgpi->gpd = gpd; - - /* set interpolation weight */ - tgpi->shift = RNA_float_get(op->ptr, "shift"); - /* set layers */ - gp_interpolate_set_points(C, tgpi); - - return 1; -} - -/* Poll handler: check if context is suitable for interpolation */ -static int gpencil_interpolate_poll(bContext *C) -{ - bGPdata * gpd = CTX_data_gpencil_data(C); - bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); - /* only 3D view */ - if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) { - return 0; - } - /* need data to interpolate */ - if (ELEM(NULL, gpd, gpl)) { - return 0; - } - - return 1; -} - -/* Allocate memory and initialize values */ -static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op) -{ - tGPDinterpolate *tgpi = NULL; - - /* create new context data */ - tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data"); - - /* define initial values */ - gp_interpolate_set_init_values(C, op, tgpi); - - /* return context data for running operator */ - return tgpi; -} +/* ----------------------- */ /* Exit and free memory */ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) { tGPDinterpolate *tgpi = op->customdata; tGPDinterpolate_layer *tgpil; - + /* don't assume that operator data exists at all */ if (tgpi) { /* remove drawing handler */ @@ -392,34 +395,68 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) if (tgpi->draw_handle_3d) { ED_region_draw_cb_exit(tgpi->ar->type, tgpi->draw_handle_3d); } + /* clear status message area */ ED_area_headerprint(tgpi->sa, NULL); + /* finally, free memory used by temp data */ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { BKE_gpencil_free_strokes(tgpil->interFrame); MEM_freeN(tgpil->interFrame); } - + BLI_freelistN(&tgpi->ilayers); MEM_freeN(tgpi); } WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - + /* clear pointer */ op->customdata = NULL; } -/* Cancel handler */ -static void gpencil_interpolate_cancel(bContext *C, wmOperator *op) +/* Init new temporary interpolation data */ +static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinterpolate *tgpi) { - /* this is just a wrapper around exit() */ - gpencil_interpolate_exit(C, op); + ToolSettings *ts = CTX_data_tool_settings(C); + bGPdata *gpd = CTX_data_gpencil_data(C); + + /* set current scene and window */ + tgpi->scene = CTX_data_scene(C); + tgpi->sa = CTX_wm_area(C); + tgpi->ar = CTX_wm_region(C); + tgpi->flag = ts->gp_sculpt.flag; + + /* set current frame number */ + tgpi->cframe = tgpi->scene->r.cfra; + + /* set GP datablock */ + tgpi->gpd = gpd; + + /* set interpolation weight */ + tgpi->shift = RNA_float_get(op->ptr, "shift"); + /* set layers */ + gp_interpolate_set_points(C, tgpi); + + return 1; } -/* Init interpolation: Allocate memory and set init values */ +/* Allocate memory and initialize values */ +static tGPDinterpolate *gp_session_init_interpolation(bContext *C, wmOperator *op) +{ + tGPDinterpolate *tgpi = MEM_callocN(sizeof(tGPDinterpolate), "GPencil Interpolate Data"); + + /* define initial values */ + gp_interpolate_set_init_values(C, op, tgpi); + + /* return context data for running operator */ + return tgpi; +} + +/* Init interpolation: Allocate memory and set init values */ static int gpencil_interpolate_init(bContext *C, wmOperator *op) { tGPDinterpolate *tgpi; + /* check context */ tgpi = op->customdata = gp_session_init_interpolation(C, op); if (tgpi == NULL) { @@ -427,34 +464,19 @@ static int gpencil_interpolate_init(bContext *C, wmOperator *op) gpencil_interpolate_exit(C, op); return 0; } - + /* everything is now setup ok */ return 1; } -/* ********************** custom drawcall api ***************** */ -/* Helper: drawing callback for modal operator in screen mode */ -static void gpencil_interpolate_draw_screen(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) -{ - wmOperator *op = arg; - struct tGPDinterpolate *tgpi = op->customdata; - ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_PIXEL); -} - -/* Helper: drawing callback for modal operator in 3d mode */ -static void gpencil_interpolate_draw_3d(const struct bContext *UNUSED(C), ARegion *UNUSED(ar), void *arg) -{ - wmOperator *op = arg; - struct tGPDinterpolate *tgpi = op->customdata; - ED_gp_draw_interpolation(tgpi, REGION_DRAW_POST_VIEW); -} +/* ----------------------- */ /* Invoke handler: Initialize the operator */ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { wmWindow *win = CTX_wm_window(C); Scene *scene = CTX_data_scene(C); - bGPdata * gpd = CTX_data_gpencil_data(C); + bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); tGPDinterpolate *tgpi = NULL; @@ -463,41 +485,46 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer"); return OPERATOR_CANCELLED; } - + /* cannot interpolate in extremes */ if ((gpl->actframe->framenum == scene->r.cfra) || (gpl->actframe->next->framenum == scene->r.cfra)) { BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer"); return OPERATOR_CANCELLED; } - + /* need editable strokes */ if (!gp_interpolate_check_todo(C, gpd)) { BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable stroke"); return OPERATOR_CANCELLED; } - + /* try to initialize context data needed */ if (!gpencil_interpolate_init(C, op)) { if (op->customdata) MEM_freeN(op->customdata); return OPERATOR_CANCELLED; } - else + else { tgpi = op->customdata; - - /* enable custom drawing handlers. It needs 2 handlers because can be strokes in 3d space and screen space and each handler use different - coord system */ - tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, op, REGION_DRAW_POST_PIXEL); - tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, op, REGION_DRAW_POST_VIEW); + } + + /* Enable custom drawing handlers + * It needs 2 handlers because strokes can in 3d space and screen space + * and each handler use different coord system + */ + tgpi->draw_handle_screen = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_screen, tgpi, REGION_DRAW_POST_PIXEL); + tgpi->draw_handle_3d = ED_region_draw_cb_activate(tgpi->ar->type, gpencil_interpolate_draw_3d, tgpi, REGION_DRAW_POST_VIEW); + /* set cursor to indicate modal */ WM_cursor_modal_set(win, BC_EW_SCROLLCURSOR); + /* update shift indicator in header */ gpencil_interpolate_status_indicators(tgpi); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); - + /* add a modal handler for this operator */ WM_event_add_modal_handler(C, op); - + return OPERATOR_RUNNING_MODAL; } @@ -510,7 +537,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent bGPDstroke *gps_src, *gps_dst; tGPDinterpolate_layer *tgpil; const bool has_numinput = hasNumInput(&tgpi->num); - + switch (event->type) { case LEFTMOUSE: /* confirm */ case RETKEY: @@ -518,7 +545,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent /* return to normal cursor and header status */ ED_area_headerprint(tgpi->sa, NULL); WM_cursor_modal_restore(win); - + /* insert keyframes as required... */ for (tgpil = tgpi->ilayers.first; tgpil; tgpil = tgpil->next) { gpf_dst = BKE_gpencil_layer_getframe(tgpil->gpl, tgpi->cframe, GP_GETFRAME_ADD_NEW); @@ -530,6 +557,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent if (gps_src->totpoints == 0) { continue; } + /* make copy of source stroke, then adjust pointer to points too */ gps_dst = MEM_dupallocN(gps_src); gps_dst->points = MEM_dupallocN(gps_src->points); @@ -538,31 +566,34 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent BLI_addtail(&gpf_dst->strokes, gps_dst); } } + /* clean up temp data */ gpencil_interpolate_exit(C, op); - + /* done! */ return OPERATOR_FINISHED; } - + case ESCKEY: /* cancel */ case RIGHTMOUSE: { /* return to normal cursor and header status */ ED_area_headerprint(tgpi->sa, NULL); WM_cursor_modal_restore(win); - + /* clean up temp data */ gpencil_interpolate_exit(C, op); - + /* canceled! */ return OPERATOR_CANCELLED; } + case WHEELUPMOUSE: { tgpi->shift = tgpi->shift + 0.01f; CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); + /* update screen */ gpencil_interpolate_update(C, op, tgpi); break; @@ -572,6 +603,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent tgpi->shift = tgpi->shift - 0.01f; CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); + /* update screen */ gpencil_interpolate_update(C, op, tgpi); break; @@ -582,6 +614,7 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent if (has_numinput == false) { /* update shift based on position of mouse */ gpencil_mouse_update_shift(tgpi, op, event); + /* update screen */ gpencil_interpolate_update(C, op, tgpi); } @@ -589,22 +622,23 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent } default: if ((event->val == KM_PRESS) && handleNumInput(C, &tgpi->num, event)) { + const float factor = tgpi->init_factor; float value; - float factor = tgpi->init_factor; - + /* Grab shift from numeric input, and store this new value (the user see an int) */ value = (factor + tgpi->shift) * 100.0f; applyNumInput(&tgpi->num, &value); tgpi->shift = value / 100.0f; + /* recalculate the shift to get the right value in the frame scale */ tgpi->shift = tgpi->shift - factor; - + CLAMP(tgpi->shift, tgpi->low_limit, tgpi->high_limit); RNA_float_set(op->ptr, "shift", tgpi->shift); - + /* update screen */ gpencil_interpolate_update(C, op, tgpi); - + break; } else { @@ -612,38 +646,45 @@ static int gpencil_interpolate_modal(bContext *C, wmOperator *op, const wmEvent return OPERATOR_RUNNING_MODAL | OPERATOR_PASS_THROUGH; } } - + /* still running... */ return OPERATOR_RUNNING_MODAL; } -/* Define modal operator for interpolation */ +/* Cancel handler */ +static void gpencil_interpolate_cancel(bContext *C, wmOperator *op) +{ + /* this is just a wrapper around exit() */ + gpencil_interpolate_exit(C, op); +} + void GPENCIL_OT_interpolate(wmOperatorType *ot) { /* identifiers */ ot->name = "Grease Pencil Interpolation"; ot->idname = "GPENCIL_OT_interpolate"; ot->description = "Interpolate grease pencil strokes between frames"; - - /* api callbacks */ + + /* callbacks */ ot->invoke = gpencil_interpolate_invoke; ot->modal = gpencil_interpolate_modal; ot->cancel = gpencil_interpolate_cancel; ot->poll = gpencil_interpolate_poll; - + /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING; - - RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Displacement factor for the interpolate operation", -0.9f, 0.9f); + + /* properties */ + RNA_def_float_percentage(ot->srna, "shift", 0.0f, -1.0f, 1.0f, "Shift", "Bias factor for which frame has more influence on the interpolated strokes", -0.9f, 0.9f); } -/* =============== Interpolate sequence ===============*/ -/* Create Sequence Interpolation */ +/* ****************** Interpolate Sequence *********************** */ + static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); - bGPdata * gpd = CTX_data_gpencil_data(C); + bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); bGPDlayer *gpl; bGPDframe *prevFrame, *nextFrame, *interFrame; @@ -651,15 +692,15 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) float factor; int cframe, fFrame; int flag = ts->gp_sculpt.flag; - + /* cannot interpolate if not between 2 frames */ if ((active_gpl->actframe == NULL) || (active_gpl->actframe->next == NULL)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames"); + BKE_report(op->reports, RPT_ERROR, "Could not find a pair of grease pencil frames to interpolate between"); return OPERATOR_CANCELLED; } /* cannot interpolate in extremes */ if ((active_gpl->actframe->framenum == scene->r.cfra) || (active_gpl->actframe->next->framenum == scene->r.cfra)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames"); + BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has strokes"); return OPERATOR_CANCELLED; } @@ -673,16 +714,18 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) if (!gpencil_layer_is_editable(gpl) || (gpl->actframe == NULL)) { continue; } + /* store extremes */ prevFrame = gpl->actframe; nextFrame = gpl->actframe->next; + /* Loop over intermediary frames and create the interpolation */ for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) { interFrame = NULL; - + /* get interpolation factor */ factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1); - + /* create new strokes data with interpolated points reading original stroke */ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { /* only selected */ @@ -697,21 +740,25 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) if (ED_gpencil_stroke_color_use(gpl, gps_from) == false) { continue; } + /* get final stroke to interpolate */ fFrame = BLI_findindex(&prevFrame->strokes, gps_from); gps_to = BLI_findlink(&nextFrame->strokes, fFrame); if (gps_to == NULL) { continue; } + /* create a new frame if needed */ if (interFrame == NULL) { interFrame = BKE_gpencil_layer_getframe(gpl, cframe, GP_GETFRAME_ADD_NEW); interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; } + /* create new stroke */ new_stroke = MEM_dupallocN(gps_from); new_stroke->points = MEM_dupallocN(gps_from->points); new_stroke->triangles = MEM_dupallocN(gps_from->triangles); + /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points) * gps_to->totpoints); @@ -719,35 +766,35 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) new_stroke->tot_triangles = 0; new_stroke->flag |= GP_STROKE_RECALC_CACHES; } + /* update points position */ gp_interpolate_update_points(gps_from, gps_to, new_stroke, factor); - + /* add to strokes */ BLI_addtail(&interFrame->strokes, new_stroke); } } } - + /* notifiers */ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); - + return OPERATOR_FINISHED; } -/* Define sequence interpolation */ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) { /* identifiers */ - ot->name = "Grease Pencil Sequence Interpolation"; + ot->name = "Interpolate Sequence"; ot->idname = "GPENCIL_OT_interpolate_sequence"; - ot->description = "Interpolate full grease pencil strokes sequence between frames"; - + ot->description = "Generate 'in-betweens' to smoothly interpolate between Grease Pencil frames"; + /* api callbacks */ ot->exec = gpencil_interpolate_seq_exec; ot->poll = gpencil_interpolate_poll; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ========= End Interpolation operators ========================== */ +/* *************************************************************** */ From 4903a83235524d852dec52d189c6744d4794d613 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 18 Jan 2017 01:29:40 +1300 Subject: [PATCH 522/590] GP Interpolate Code Cleanup (Second Round) * Reduce scope of variables * Simplify a lot of the active_gpl->actframe->...->framenum stuff * Missed some error messages --- .../editors/gpencil/gpencil_interpolate.c | 81 ++++++++++--------- 1 file changed, 43 insertions(+), 38 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 703bacf8554..0b04e863630 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -162,15 +162,10 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) ToolSettings *ts = CTX_data_tool_settings(C); int flag = ts->gp_sculpt.flag; - bGPDlayer *gpl; - bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); - bGPDstroke *gps_from, *gps_to; - int fFrame; - /* get layers */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* all layers or only active */ - if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { + if (!(flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) { continue; } /* only editable and visible layers are considered */ @@ -179,7 +174,10 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) } /* read strokes */ - for (gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) { + for (bGPDstroke *gps_from = gpl->actframe->strokes.first; gps_from; gps_from = gps_from->next) { + bGPDstroke *gps_to; + int fFrame; + /* only selected */ if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { continue; @@ -200,33 +198,32 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) continue; } - return 1; + return true; } } - return 0; + return false; } /* Helper: Create internal strokes interpolated */ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) { - bGPDlayer *gpl; bGPdata *gpd = tgpi->gpd; - tGPDinterpolate_layer *tgpil; bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); - bGPDstroke *gps_from, *gps_to, *new_stroke; - int fFrame; + bGPDframe *actframe = active_gpl->actframe; /* save initial factor for active layer to define shift limits */ - tgpi->init_factor = (float)(tgpi->cframe - active_gpl->actframe->framenum) / (active_gpl->actframe->next->framenum - active_gpl->actframe->framenum + 1); + tgpi->init_factor = (float)(tgpi->cframe - actframe->framenum) / (actframe->next->framenum - actframe->framenum + 1); /* limits are 100% below 0 and 100% over the 100% */ tgpi->low_limit = -1.0f - tgpi->init_factor; tgpi->high_limit = 2.0f - tgpi->init_factor; /* set layers */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + tGPDinterpolate_layer *tgpil; + /* all layers or only active */ - if (((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { + if (!(tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) && (gpl != active_gpl)) { continue; } /* only editable and visible layers are considered */ @@ -235,7 +232,6 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) } /* create temp data for each layer */ - tgpil = NULL; tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); tgpil->gpl = gpl; @@ -252,9 +248,14 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) tgpil->factor = (float)(tgpi->cframe - tgpil->prevFrame->framenum) / (tgpil->nextFrame->framenum - tgpil->prevFrame->framenum + 1); /* create new strokes data with interpolated points reading original stroke */ - for (gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { + for (bGPDstroke *gps_from = tgpil->prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { + bGPDstroke *gps_to; + int fFrame; + + bGPDstroke *new_stroke; bool valid = true; + /* only selected */ if ((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { valid = false; @@ -357,7 +358,6 @@ static void gpencil_interpolate_status_indicators(tGPDinterpolate *p) char str_offs[NUM_STR_REP_LEN]; outputNumInput(&p->num, str_offs, &scene->unit); - BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs); } else { @@ -478,23 +478,24 @@ static int gpencil_interpolate_invoke(bContext *C, wmOperator *op, const wmEvent Scene *scene = CTX_data_scene(C); bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + bGPDframe *actframe = gpl->actframe; tGPDinterpolate *tgpi = NULL; /* cannot interpolate if not between 2 frames */ - if ((gpl->actframe == NULL) || (gpl->actframe->next == NULL)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer"); + if (ELEM(NULL, actframe, actframe->next)) { + BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer"); return OPERATOR_CANCELLED; } /* cannot interpolate in extremes */ - if ((gpl->actframe->framenum == scene->r.cfra) || (gpl->actframe->next->framenum == scene->r.cfra)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires to be between two grease pencil frames in active layer"); + if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) { + BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames"); return OPERATOR_CANCELLED; } /* need editable strokes */ if (!gp_interpolate_check_todo(C, gpd)) { - BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable stroke"); + BKE_report(op->reports, RPT_ERROR, "Interpolation requires some editable strokes"); return OPERATOR_CANCELLED; } @@ -682,30 +683,31 @@ void GPENCIL_OT_interpolate(wmOperatorType *ot) static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) { - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = CTX_data_tool_settings(C); bGPdata *gpd = CTX_data_gpencil_data(C); bGPDlayer *active_gpl = CTX_data_active_gpencil_layer(C); - bGPDlayer *gpl; - bGPDframe *prevFrame, *nextFrame, *interFrame; - bGPDstroke *gps_from, *gps_to, *new_stroke; - float factor; - int cframe, fFrame; + bGPDframe *actframe = active_gpl->actframe; + + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = CTX_data_tool_settings(C); int flag = ts->gp_sculpt.flag; /* cannot interpolate if not between 2 frames */ - if ((active_gpl->actframe == NULL) || (active_gpl->actframe->next == NULL)) { - BKE_report(op->reports, RPT_ERROR, "Could not find a pair of grease pencil frames to interpolate between"); + if (ELEM(NULL, actframe, actframe->next)) { + BKE_report(op->reports, RPT_ERROR, "Cannot find a pair of grease pencil frames to interpolate between in active layer"); return OPERATOR_CANCELLED; } /* cannot interpolate in extremes */ - if ((active_gpl->actframe->framenum == scene->r.cfra) || (active_gpl->actframe->next->framenum == scene->r.cfra)) { - BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has strokes"); + if (ELEM(CFRA, actframe->framenum, actframe->next->framenum)) { + BKE_report(op->reports, RPT_ERROR, "Cannot interpolate as current frame already has existing grease pencil frames"); return OPERATOR_CANCELLED; } /* loop all layer to check if need interpolation */ - for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + bGPDframe *prevFrame, *nextFrame; + bGPDstroke *gps_from, *gps_to; + int cframe, fFrame; + /* all layers or only active */ if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { continue; @@ -721,13 +723,16 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) /* Loop over intermediary frames and create the interpolation */ for (cframe = prevFrame->framenum + 1; cframe < nextFrame->framenum; cframe++) { - interFrame = NULL; + bGPDframe *interFrame = NULL; + float factor; /* get interpolation factor */ factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1); /* create new strokes data with interpolated points reading original stroke */ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { + bGPDstroke *new_stroke; + /* only selected */ if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { continue; From 224ae234439727628ec5c260d1fd4e22e6566e29 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 18 Jan 2017 16:43:17 +1300 Subject: [PATCH 523/590] GP Interpolate: Move settings from "gp_sculpt" to a new toolsettings struct - "gp_interpolate" The "gp_sculpt" settings should be strictly for stroke sculpting, and not abused by other tools. (Similarly, if other general GP tools need one-off options, those should go into the normal toolsettings->gpencil_flag) Furthermore, this paves the way for introducing new settings for controlling the way that GP interpolation takes place (e.g. with easing equations, or a custom curvemap) --- .../bl_ui/properties_grease_pencil_common.py | 36 ++++++++++++++--- .../editors/gpencil/gpencil_interpolate.c | 19 ++++----- source/blender/makesdna/DNA_scene_types.h | 25 +++++++++--- source/blender/makesrna/RNA_access.h | 1 + source/blender/makesrna/intern/rna_scene.c | 40 ++++++++++++++++++- .../makesrna/intern/rna_sculpt_paint.c | 9 ----- 6 files changed, 99 insertions(+), 31 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index f8ee7c9a851..c43f56acb37 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -227,12 +227,7 @@ class GreasePencilStrokeEditPanel: if is_3d_view: layout.separator() - col = layout.column(align=True) - col.operator("gpencil.interpolate", text="Interpolate") - col.operator("gpencil.interpolate_sequence", text="Sequence") - settings = context.tool_settings.gpencil_sculpt - col.prop(settings, "interpolate_all_layers") - col.prop(settings, "interpolate_selected_only") + layout.separator() col = layout.column(align=True) @@ -249,6 +244,35 @@ class GreasePencilStrokeEditPanel: layout.separator() layout.operator("gpencil.reproject") +class GreasePencilInterpolatePanel: + # subclass must set + bl_space_type = 'VIEW_3D' + bl_label = "Interpolate..." + bl_category = "Grease Pencil" + bl_region_type = 'TOOLS' + bl_options = {'DEFAULT_CLOSED'} + + @classmethod + def poll(cls, context): + if context.gpencil_data is None: + return False + elif context.space_data.type != 'VIEW_3D': + return False + + gpd = context.gpencil_data + return bool(context.editable_gpencil_strokes) and bool(gpd.use_stroke_edit_mode) + + @staticmethod + def draw(self, context): + layout = self.layout + settings = context.tool_settings.gpencil_interpolate + + col = layout.column(align=True) + col.operator("gpencil.interpolate", text="Interpolate") + col.operator("gpencil.interpolate_sequence", text="Sequence") + col.prop(settings, "interpolate_all_layers") + col.prop(settings, "interpolate_selected_only") + class GreasePencilBrushPanel: # subclass must set diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 0b04e863630..ca511493536 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -160,12 +160,12 @@ static void gp_interpolate_update_strokes(bContext *C, tGPDinterpolate *tgpi) static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) { ToolSettings *ts = CTX_data_tool_settings(C); - int flag = ts->gp_sculpt.flag; + eGP_Interpolate_SettingsFlag flag = ts->gp_interpolate.flag; /* get layers */ for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { /* all layers or only active */ - if (!(flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) { + if (!(flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && !(gpl->flag & GP_LAYER_ACTIVE)) { continue; } /* only editable and visible layers are considered */ @@ -179,7 +179,7 @@ static bool gp_interpolate_check_todo(bContext *C, bGPdata *gpd) int fFrame; /* only selected */ - if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { + if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { continue; } /* skip strokes that are invalid for current view */ @@ -223,7 +223,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) tGPDinterpolate_layer *tgpil; /* all layers or only active */ - if (!(tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) && (gpl != active_gpl)) { + if (!(tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) && (gpl != active_gpl)) { continue; } /* only editable and visible layers are considered */ @@ -257,7 +257,7 @@ static void gp_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) /* only selected */ - if ((tgpi->flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { + if ((tgpi->flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { valid = false; } /* skip strokes that are invalid for current view */ @@ -424,7 +424,7 @@ static bool gp_interpolate_set_init_values(bContext *C, wmOperator *op, tGPDinte tgpi->scene = CTX_data_scene(C); tgpi->sa = CTX_wm_area(C); tgpi->ar = CTX_wm_region(C); - tgpi->flag = ts->gp_sculpt.flag; + tgpi->flag = ts->gp_interpolate.flag; /* set current frame number */ tgpi->cframe = tgpi->scene->r.cfra; @@ -689,7 +689,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ToolSettings *ts = CTX_data_tool_settings(C); - int flag = ts->gp_sculpt.flag; + GP_Interpolate_Settings *ipo_settings = &ts->gp_interpolate; + eGP_Interpolate_SettingsFlag flag = ipo_settings->flag; /* cannot interpolate if not between 2 frames */ if (ELEM(NULL, actframe, actframe->next)) { @@ -709,7 +710,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) int cframe, fFrame; /* all layers or only active */ - if (((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { + if (((flag & GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS) == 0) && (gpl != active_gpl)) { continue; } /* only editable and visible layers are considered */ @@ -734,7 +735,7 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) bGPDstroke *new_stroke; /* only selected */ - if ((flag & GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { + if ((flag & GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED) && ((gps_from->flag & GP_STROKE_SELECT) == 0)) { continue; } /* skip strokes that are invalid for current view */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index f5e71ae59a9..4d09457b3cc 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1212,13 +1212,23 @@ typedef enum eGP_BrushEdit_SettingsFlag { GP_BRUSHEDIT_FLAG_APPLY_STRENGTH = (1 << 2), /* apply brush to thickness */ GP_BRUSHEDIT_FLAG_APPLY_THICKNESS = (1 << 3), - /* apply interpolation to all layers */ - GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS = (1 << 4), - /* apply interpolation to only selected */ - GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED = (1 << 5) - } eGP_BrushEdit_SettingsFlag; + +/* Settings for GP Interpolation Operators */ +typedef struct GP_Interpolate_Settings { + short flag; /* eGP_Interpolate_SettingsFlag */ +} GP_Interpolate_Settings; + +/* GP_Interpolate_Settings.flag */ +typedef enum eGP_Interpolate_SettingsFlag { + /* apply interpolation to all layers */ + GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS = (1 << 0), + /* apply interpolation to only selected */ + GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED = (1 << 1), +} eGP_Interpolate_SettingsFlag; + + /* *************************************************************** */ /* Transform Orientations */ @@ -1435,7 +1445,10 @@ typedef struct ToolSettings { /* Grease Pencil Sculpt */ struct GP_BrushEdit_Settings gp_sculpt; - + + /* Grease Pencil Interpolation Tool(s) */ + struct GP_Interpolate_Settings gp_interpolate; + /* Grease Pencil Drawing Brushes (bGPDbrush) */ ListBase gp_brushes; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index f97a5735c94..66e6f30feeb 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -262,6 +262,7 @@ extern StructRNA RNA_GPencilLayer; extern StructRNA RNA_GPencilPalette; extern StructRNA RNA_GPencilPaletteColor; extern StructRNA RNA_GPencilBrush; +extern StructRNA RNA_GPencilInterpolateSettings; extern StructRNA RNA_GPencilStroke; extern StructRNA RNA_GPencilStrokePoint; extern StructRNA RNA_GPencilSculptSettings; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 6947a4104c8..8f5304c8f0c 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -447,6 +447,12 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = { #include "FRS_freestyle.h" #endif +/* Grease Pencil Interpolation settings */ +static char *rna_GPencilInterpolateSettings_path(PointerRNA *UNUSED(ptr)) +{ + return BLI_strdup("tool_settings.gpencil_interpolate"); +} + /* Grease pencil Drawing Brushes */ static bGPDbrush *rna_GPencil_brush_new(ToolSettings *ts, const char *name, int setactive) { @@ -2138,6 +2144,30 @@ static int rna_gpu_is_hq_supported_get(PointerRNA *UNUSED(ptr)) #else +/* Grease Pencil Interpolation tool settings */ +static void rna_def_gpencil_interpolate(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "GPencilInterpolateSettings", NULL); + RNA_def_struct_sdna(srna, "GP_Interpolate_Settings"); + RNA_def_struct_path_func(srna, "rna_GPencilInterpolateSettings_path"); + RNA_def_struct_ui_text(srna, "Grease Pencil Interpolate Settings", + "Settings for Grease Pencil interpolation tools"); + + /* flags */ + prop = RNA_def_property(srna, "interpolate_all_layers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TOOLFLAG_INTERPOLATE_ALL_LAYERS); + RNA_def_property_ui_text(prop, "Interpolate All Layers", "Interpolate all layers, not only active"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "interpolate_selected_only", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED); + RNA_def_property_ui_text(prop, "Interpolate Selected Strokes", "Interpolate only selected strokes in the original frame"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); +} + /* Grease Pencil Drawing Brushes */ static void rna_def_gpencil_brush(BlenderRNA *brna) { @@ -2673,7 +2703,14 @@ static void rna_def_tool_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt"); RNA_def_property_struct_type(prop, "GPencilSculptSettings"); - RNA_def_property_ui_text(prop, "Grease Pencil Sculpt", ""); + RNA_def_property_ui_text(prop, "Grease Pencil Sculpt", + "Settings for stroke sculpting tools and brushes"); + + prop = RNA_def_property(srna, "gpencil_interpolate", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "gp_interpolate"); + RNA_def_property_struct_type(prop, "GPencilInterpolateSettings"); + RNA_def_property_ui_text(prop, "Grease Pencil Interpolate", + "Settings for Grease Pencil Interpolation tools"); /* Grease Pencil - Drawing brushes */ prop = RNA_def_property(srna, "gpencil_brushes", PROP_COLLECTION, PROP_NONE); @@ -7267,6 +7304,7 @@ void RNA_def_scene(BlenderRNA *brna) RNA_define_animate_sdna(false); rna_def_tool_settings(brna); rna_def_gpencil_brush(brna); + rna_def_gpencil_interpolate(brna); rna_def_unified_paint_settings(brna); rna_def_curve_paint_settings(brna); rna_def_statvis(brna); diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index 7f405f0fb1f..40aea37d9d2 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -1047,15 +1047,6 @@ static void rna_def_gpencil_sculpt(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Affect Thickness", "The brush affects the thickness of the point"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - prop = RNA_def_property(srna, "interpolate_all_layers", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_INTERPOLATE_ALL_LAYERS); - RNA_def_property_ui_text(prop, "Interpolate All Layers", "Interpolate all layers, not only active"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); - - prop = RNA_def_property(srna, "interpolate_selected_only", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSHEDIT_FLAG_INTERPOLATE_ONLY_SELECTED); - RNA_def_property_ui_text(prop, "Interpolate Selected Strokes", "Interpolate only selected strokes in the original frame"); - RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "selection_alpha", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "alpha"); From 65ec429d1176404fcedd0dc29c03476972ab303f Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 18 Jan 2017 19:00:17 +1300 Subject: [PATCH 524/590] GP Interpolate Sequence: Tool settings for controlling the shape of interpolation This commit introduces the ability to use the Robert Penner easing equations or a Custom Curve to control the way that the "Interpolate Sequence" operator interpolates between keyframes. Previously, it was only possible to get linear interpolation between the gp frames. Workflow: 1) Place current frame between a pair of GP keyframes 2) Open the "Interpolate" panel in the Toolshelf 3) Choose the interpolation type (under "Sequence Options") 4) Adjust settings (e.g. if you're using "Custom Curve", use the curvemap widget to define the way that the interpolation proceeds) 5) Click "Sequence" to interpolate 6) Play back/scrub the animation to see if you've got the result you want 7) If you need to make some tweaks, undo, or delete the generated keyframes, then repeat the process again from step 4 until you've got the desired result. --- .../bl_ui/properties_grease_pencil_common.py | 19 +- .../startup/bl_ui/space_view3d_toolbar.py | 6 + source/blender/blenkernel/intern/scene.c | 16 +- source/blender/blenloader/intern/readfile.c | 7 + source/blender/blenloader/intern/writefile.c | 4 + .../editors/gpencil/gpencil_interpolate.c | 224 +++++++++++++++++- source/blender/makesdna/DNA_scene_types.h | 29 +++ source/blender/makesrna/intern/rna_scene.c | 86 +++++++ 8 files changed, 384 insertions(+), 7 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index c43f56acb37..1f06b202adc 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -244,8 +244,8 @@ class GreasePencilStrokeEditPanel: layout.separator() layout.operator("gpencil.reproject") + class GreasePencilInterpolatePanel: - # subclass must set bl_space_type = 'VIEW_3D' bl_label = "Interpolate..." bl_category = "Grease Pencil" @@ -273,6 +273,23 @@ class GreasePencilInterpolatePanel: col.prop(settings, "interpolate_all_layers") col.prop(settings, "interpolate_selected_only") + col = layout.column(align=True) + col.label(text="Sequence Options:") + col.prop(settings, "type") + if settings.type == 'CUSTOM': + box = layout.box() + # TODO: Options for loading/saving curve presets? + box.template_curve_mapping(settings, "interpolation_curve", brush=True) + elif settings.type != 'LINEAR': + col.prop(settings, "easing") + + if settings.type == 'BACK': + layout.prop(settings, "back") + elif setting.type == 'ELASTIC': + sub = layout.column(align=True) + sub.prop(settings, "amplitude") + sub.prop(settings, "period") + class GreasePencilBrushPanel: # subclass must set diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 3eb76a3b0f9..60e86d7544d 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -22,6 +22,7 @@ from bpy.types import Menu, Panel, UIList from bl_ui.properties_grease_pencil_common import ( GreasePencilDrawingToolsPanel, GreasePencilStrokeEditPanel, + GreasePencilInterpolatePanel, GreasePencilStrokeSculptPanel, GreasePencilBrushPanel, GreasePencilBrushCurvesPanel @@ -1963,6 +1964,11 @@ class VIEW3D_PT_tools_grease_pencil_edit(GreasePencilStrokeEditPanel, Panel): bl_space_type = 'VIEW_3D' +# Grease Pencil stroke interpolation tools +class VIEW3D_PT_tools_grease_pencil_interpolate(GreasePencilInterpolatePanel, Panel): + bl_space_type = 'VIEW_3D' + + # Grease Pencil stroke sculpting tools class VIEW3D_PT_tools_grease_pencil_sculpt(GreasePencilStrokeSculptPanel, Panel): bl_space_type = 'VIEW_3D' diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 39a97b08df1..69d3b4db54c 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -287,13 +287,16 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) ts->imapaint.paintcursor = NULL; id_us_plus((ID *)ts->imapaint.stencil); ts->particle.paintcursor = NULL; + /* duplicate Grease Pencil Drawing Brushes */ BLI_listbase_clear(&ts->gp_brushes); for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) { bGPDbrush *newbrush = BKE_gpencil_brush_duplicate(brush); BLI_addtail(&ts->gp_brushes, newbrush); } - + + /* duplicate Grease Pencil interpolation curve */ + ts->gp_interpolate.custom_ipo = curvemapping_copy(ts->gp_interpolate.custom_ipo); } /* make a private copy of the avicodecdata */ @@ -440,12 +443,17 @@ void BKE_scene_free(Scene *sce) BKE_paint_free(&sce->toolsettings->uvsculpt->paint); MEM_freeN(sce->toolsettings->uvsculpt); } + BKE_paint_free(&sce->toolsettings->imapaint.paint); + /* free Grease Pencil Drawing Brushes */ BKE_gpencil_free_brushes(&sce->toolsettings->gp_brushes); BLI_freelistN(&sce->toolsettings->gp_brushes); - - BKE_paint_free(&sce->toolsettings->imapaint.paint); - + + /* free Grease Pencil interpolation curve */ + if (sce->toolsettings->gp_interpolate.custom_ipo) { + curvemapping_free(sce->toolsettings->gp_interpolate.custom_ipo); + } + MEM_freeN(sce->toolsettings); sce->toolsettings = NULL; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a63b9ed7d19..61f19657349 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -5932,6 +5932,7 @@ static void direct_link_scene(FileData *fd, Scene *sce) sce->toolsettings->wpaint->wpaint_prev = NULL; sce->toolsettings->wpaint->tot = 0; } + /* relink grease pencil drawing brushes */ link_list(fd, &sce->toolsettings->gp_brushes); for (bGPDbrush *brush = sce->toolsettings->gp_brushes.first; brush; brush = brush->next) { @@ -5948,6 +5949,12 @@ static void direct_link_scene(FileData *fd, Scene *sce) direct_link_curvemapping(fd, brush->cur_jitter); } } + + /* relink grease pencil interpolation curves */ + sce->toolsettings->gp_interpolate.custom_ipo = newdataadr(fd, sce->toolsettings->gp_interpolate.custom_ipo); + if (sce->toolsettings->gp_interpolate.custom_ipo) { + direct_link_curvemapping(fd, sce->toolsettings->gp_interpolate.custom_ipo); + } } if (sce->ed) { diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index ad1999c0bc7..7b8b95f0005 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2691,6 +2691,10 @@ static void write_scenes(WriteData *wd, ListBase *scebase) write_curvemapping(wd, brush->cur_jitter); } } + /* write grease-pencil custom ipo curve to file */ + if (tos->gp_interpolate.custom_ipo) { + write_curvemapping(wd, tos->gp_interpolate.custom_ipo); + } write_paint(wd, &tos->imapaint.paint); diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index ca511493536..287a6f214c0 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -38,19 +38,22 @@ #include "MEM_guardedalloc.h" -#include "BLI_math.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_easing.h" +#include "BLI_math.h" #include "BLT_translation.h" +#include "DNA_color_types.h" +#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "DNA_view3d_types.h" -#include "DNA_gpencil_types.h" +#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_gpencil.h" @@ -681,6 +684,209 @@ void GPENCIL_OT_interpolate(wmOperatorType *ot) /* ****************** Interpolate Sequence *********************** */ +/* Helper: Perform easing equation calculations for GP interpolation operator */ +static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_settings, float time) +{ + const float begin = 0.0f; + const float change = 1.0f; + const float duration = 1.0f; + + const float back = ipo_settings->back; + const float amplitude = ipo_settings->amplitude; + const float period = ipo_settings->period; + + eBezTriple_Easing easing = ipo_settings->easing; + float result = time; + + switch (ipo_settings->type) { + case GP_IPO_BACK: + switch (easing) { + case BEZT_IPO_EASE_IN: + result = BLI_easing_back_ease_in(time, begin, change, duration, back); + break; + case BEZT_IPO_EASE_OUT: + result = BLI_easing_back_ease_out(time, begin, change, duration, back); + break; + case BEZT_IPO_EASE_IN_OUT: + result = BLI_easing_back_ease_in_out(time, begin, change, duration, back); + break; + + default: /* default/auto: same as ease out */ + result = BLI_easing_back_ease_out(time, begin, change, duration, back); + break; + } + break; + + case GP_IPO_BOUNCE: + switch (easing) { + case BEZT_IPO_EASE_IN: + result = BLI_easing_bounce_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + result = BLI_easing_bounce_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + result = BLI_easing_bounce_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease out */ + result = BLI_easing_bounce_ease_out(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_CIRC: + switch (easing) { + case BEZT_IPO_EASE_IN: + result = BLI_easing_circ_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + result = BLI_easing_circ_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + result = BLI_easing_circ_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + result = BLI_easing_circ_ease_in(time, begin, change, duration); + break; + } + break; + + case BEZT_IPO_CUBIC: + switch (easing) { + case BEZT_IPO_EASE_IN: + result = BLI_easing_cubic_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + result = BLI_easing_cubic_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + result = BLI_easing_cubic_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + result = BLI_easing_cubic_ease_in(time, begin, change, duration); + break; + } + break; + + case GP_IPO_ELASTIC: + switch (easing) { + case BEZT_IPO_EASE_IN: + result = BLI_easing_elastic_ease_in(time, begin, change, duration, amplitude, period); + break; + case BEZT_IPO_EASE_OUT: + result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period); + break; + case BEZT_IPO_EASE_IN_OUT: + result = BLI_easing_elastic_ease_in_out(time, begin, change, duration, amplitude, period); + break; + + default: /* default/auto: same as ease out */ + result = BLI_easing_elastic_ease_out(time, begin, change, duration, amplitude, period); + break; + } + break; + + case GP_IPO_EXPO: + switch (easing) { + case BEZT_IPO_EASE_IN: + result = BLI_easing_expo_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + result = BLI_easing_expo_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + result = BLI_easing_expo_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + result = BLI_easing_expo_ease_in(time, begin, change, duration); + break; + } + break; + + case GP_IPO_QUAD: + switch (easing) { + case BEZT_IPO_EASE_IN: + result = BLI_easing_quad_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + result = BLI_easing_quad_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + result = BLI_easing_quad_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + result = BLI_easing_quad_ease_in(time, begin, change, duration); + break; + } + break; + + case GP_IPO_QUART: + switch (easing) { + case BEZT_IPO_EASE_IN: + result = BLI_easing_quart_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + result = BLI_easing_quart_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + result = BLI_easing_quart_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + result = BLI_easing_quart_ease_in(time, begin, change, duration); + break; + } + break; + + case GP_IPO_QUINT: + switch (easing) { + case BEZT_IPO_EASE_IN: + result = BLI_easing_quint_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + result = BLI_easing_quint_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + result = BLI_easing_quint_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + result = BLI_easing_quint_ease_in(time, begin, change, duration); + break; + } + break; + + case GP_IPO_SINE: + switch (easing) { + case BEZT_IPO_EASE_IN: + result = BLI_easing_sine_ease_in(time, begin, change, duration); + break; + case BEZT_IPO_EASE_OUT: + result = BLI_easing_sine_ease_out(time, begin, change, duration); + break; + case BEZT_IPO_EASE_IN_OUT: + result = BLI_easing_sine_ease_in_out(time, begin, change, duration); + break; + + default: /* default/auto: same as ease in */ + result = BLI_easing_sine_ease_in(time, begin, change, duration); + break; + } + break; + + default: + printf("%s: Unknown interpolation type - %d\n", __func__, ipo_settings->type); + break; + } + + return result; +} + static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) { bGPdata *gpd = CTX_data_gpencil_data(C); @@ -730,6 +936,20 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) /* get interpolation factor */ factor = (float)(cframe - prevFrame->framenum) / (nextFrame->framenum - prevFrame->framenum + 1); + if (ipo_settings->type == GP_IPO_CURVEMAP) { + /* custom curvemap */ + if (ipo_settings->custom_ipo) { + factor = curvemapping_evaluateF(ipo_settings->custom_ipo, 0, factor); + } + else { + BKE_report(op->reports, RPT_ERROR, "Custom interpolation curve does not exist"); + } + } + else if (ipo_settings->type >= GP_IPO_BACK) { + /* easing equation... */ + factor = gp_interpolate_seq_easing_calc(ipo_settings, factor); + } + /* create new strokes data with interpolated points reading original stroke */ for (gps_from = prevFrame->strokes.first; gps_from; gps_from = gps_from->next) { bGPDstroke *new_stroke; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 4d09457b3cc..8ee15ef21a3 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1218,6 +1218,14 @@ typedef enum eGP_BrushEdit_SettingsFlag { /* Settings for GP Interpolation Operators */ typedef struct GP_Interpolate_Settings { short flag; /* eGP_Interpolate_SettingsFlag */ + + char type; /* eGP_Interpolate_Type - Interpolation Mode */ + char easing; /* eBezTriple_Easing - Easing mode (if easing equation used) */ + + float back; /* BEZT_IPO_BACK */ + float amplitude, period; /* BEZT_IPO_ELASTIC */ + + struct CurveMapping *custom_ipo; /* custom interpolation curve (for use with GP_IPO_CURVEMAP) */ } GP_Interpolate_Settings; /* GP_Interpolate_Settings.flag */ @@ -1228,6 +1236,27 @@ typedef enum eGP_Interpolate_SettingsFlag { GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED = (1 << 1), } eGP_Interpolate_SettingsFlag; +/* GP_Interpolate_Settings.type */ +typedef enum eGP_Interpolate_Type { + /* Traditional Linear Interpolation */ + GP_IPO_LINEAR = 0, + + /* CurveMap Defined Interpolation */ + GP_IPO_CURVEMAP = 1, + + /* Easing Equations */ + GP_IPO_BACK = 3, + GP_IPO_BOUNCE = 4, + GP_IPO_CIRC = 5, + GP_IPO_CUBIC = 6, + GP_IPO_ELASTIC = 7, + GP_IPO_EXPO = 8, + GP_IPO_QUAD = 9, + GP_IPO_QUART = 10, + GP_IPO_QUINT = 11, + GP_IPO_SINE = 12, +} eGP_Interpolate_Type; + /* *************************************************************** */ /* Transform Orientations */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 8f5304c8f0c..1166fb89a0a 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -407,9 +407,34 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = { {0, NULL, 0, NULL, NULL} }; +EnumPropertyItem rna_enum_gpencil_interpolation_mode_items[] = { + /* interpolation */ + {0, "", 0, N_("Interpolation"), "Standard transitions between keyframes"}, + {GP_IPO_LINEAR, "LINEAR", ICON_IPO_LINEAR, "Linear", "Straight-line interpolation between A and B (i.e. no ease in/out)"}, + {GP_IPO_CURVEMAP, "CUSTOM", ICON_IPO_BEZIER, "Custom", "Custom interpolation defined using a curvemap"}, + + /* easing */ + {0, "", 0, N_("Easing (by strength)"), "Predefined inertial transitions, useful for motion graphics (from least to most ''dramatic'')"}, + {GP_IPO_SINE, "SINE", ICON_IPO_SINE, "Sinusoidal", "Sinusoidal easing (weakest, almost linear but with a slight curvature)"}, + {GP_IPO_QUAD, "QUAD", ICON_IPO_QUAD, "Quadratic", "Quadratic easing"}, + {GP_IPO_CUBIC, "CUBIC", ICON_IPO_CUBIC, "Cubic", "Cubic easing"}, + {GP_IPO_QUART, "QUART", ICON_IPO_QUART, "Quartic", "Quartic easing"}, + {GP_IPO_QUINT, "QUINT", ICON_IPO_QUINT, "Quintic", "Quintic easing"}, + {GP_IPO_EXPO, "EXPO", ICON_IPO_EXPO, "Exponential", "Exponential easing (dramatic)"}, + {GP_IPO_CIRC, "CIRC", ICON_IPO_CIRC, "Circular", "Circular easing (strongest and most dynamic)"}, + + {0, "", 0, N_("Dynamic Effects"), "Simple physics-inspired easing effects"}, + {GP_IPO_BACK, "BACK", ICON_IPO_BACK, "Back", "Cubic easing with overshoot and settle"}, + {GP_IPO_BOUNCE, "BOUNCE", ICON_IPO_BOUNCE, "Bounce", "Exponentially decaying parabolic bounce, like when objects collide"}, + {GP_IPO_ELASTIC, "ELASTIC", ICON_IPO_ELASTIC, "Elastic", "Exponentially decaying sine wave, like an elastic band"}, + + {0, NULL, 0, NULL, NULL} +}; + #ifdef RNA_RUNTIME #include "DNA_anim_types.h" +#include "DNA_color_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_mesh_types.h" @@ -420,6 +445,7 @@ EnumPropertyItem rna_enum_bake_pass_filter_type_items[] = { #include "MEM_guardedalloc.h" #include "BKE_brush.h" +#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_image.h" @@ -453,6 +479,23 @@ static char *rna_GPencilInterpolateSettings_path(PointerRNA *UNUSED(ptr)) return BLI_strdup("tool_settings.gpencil_interpolate"); } +static void rna_GPencilInterpolateSettings_type_set(PointerRNA *ptr, int value) +{ + GP_Interpolate_Settings *settings = (GP_Interpolate_Settings *)ptr->data; + + /* NOTE: This cast should be fine, as we have a small + finite set of values (eGP_Interpolate_Type) + * that should fit well within a char + */ + settings->type = (char)value; + + /* init custom interpolation curve here now the first time it's used */ + if ((settings->type == GP_IPO_CURVEMAP) && + (settings->custom_ipo == NULL)) + { + settings->custom_ipo = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f); + } +} + /* Grease pencil Drawing Brushes */ static bGPDbrush *rna_GPencil_brush_new(ToolSettings *ts, const char *name, int setactive) { @@ -2166,6 +2209,49 @@ static void rna_def_gpencil_interpolate(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_TOOLFLAG_INTERPOLATE_ONLY_SELECTED); RNA_def_property_ui_text(prop, "Interpolate Selected Strokes", "Interpolate only selected strokes in the original frame"); RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* interpolation type */ + prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "type"); + RNA_def_property_enum_items(prop, rna_enum_gpencil_interpolation_mode_items); + RNA_def_property_enum_funcs(prop, NULL, "rna_GPencilInterpolateSettings_type_set", NULL); + RNA_def_property_ui_text(prop, "Type", + "Interpolation method to use the next time 'Interpolate Sequence' is run"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* easing */ + prop = RNA_def_property(srna, "easing", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "easing"); + RNA_def_property_enum_items(prop, rna_enum_beztriple_interpolation_easing_items); + RNA_def_property_ui_text(prop, "Easing", + "Which ends of the segment between the preceding and following grease pencil frames " + "easing interpolation is applied to"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* easing options */ + prop = RNA_def_property(srna, "back", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "back"); + RNA_def_property_ui_text(prop, "Back", "Amount of overshoot for 'back' easing"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "amplitude"); + RNA_def_property_range(prop, 0.0f, FLT_MAX); /* only positive values... */ + RNA_def_property_ui_text(prop, "Amplitude", "Amount to boost elastic bounces for 'elastic' easing"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + prop = RNA_def_property(srna, "period", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "period"); + RNA_def_property_ui_text(prop, "Period", "Time between bounces for elastic easing"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); + + /* custom curvemap */ + prop = RNA_def_property(srna, "interpolation_curve", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "custom_ipo"); + RNA_def_property_struct_type(prop, "CurveMapping"); + RNA_def_property_ui_text(prop, "Interpolation Curve", + "Custom curve to control 'sequence' interpolation between Grease Pencil frames"); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); } /* Grease Pencil Drawing Brushes */ From 8d4b31ce03523b80c82a2de43cd53120a3089c46 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Wed, 18 Jan 2017 19:40:48 +1300 Subject: [PATCH 525/590] GP Interpolation: "Remove Breakdowns" operator To make it faster to try different interpolation curves, there's a new operator "Remove Breakdowns" which will delete all breakdowns sandwiched by normal keyframes (i.e. all the ones that the previous run of the Interpolation op created) --- .../bl_ui/properties_grease_pencil_common.py | 6 +- .../blender/editors/gpencil/gpencil_intern.h | 1 + .../editors/gpencil/gpencil_interpolate.c | 119 ++++++++++++++++++ source/blender/editors/gpencil/gpencil_ops.c | 1 + 4 files changed, 126 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 1f06b202adc..3d68930e632 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -247,7 +247,7 @@ class GreasePencilStrokeEditPanel: class GreasePencilInterpolatePanel: bl_space_type = 'VIEW_3D' - bl_label = "Interpolate..." + bl_label = "Interpolate" bl_category = "Grease Pencil" bl_region_type = 'TOOLS' bl_options = {'DEFAULT_CLOSED'} @@ -270,6 +270,10 @@ class GreasePencilInterpolatePanel: col = layout.column(align=True) col.operator("gpencil.interpolate", text="Interpolate") col.operator("gpencil.interpolate_sequence", text="Sequence") + col.operator("gpencil.interpolate_reverse", text="Remove Breakdowns") + + col = layout.column(align=True) + col.label(text="Options:") col.prop(settings, "interpolate_all_layers") col.prop(settings, "interpolate_selected_only") diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index e2e5fc28710..cb293dda1ea 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -340,6 +340,7 @@ void gpencil_undo_finish(void); void GPENCIL_OT_interpolate(struct wmOperatorType *ot); void GPENCIL_OT_interpolate_sequence(struct wmOperatorType *ot); +void GPENCIL_OT_interpolate_reverse(struct wmOperatorType *ot); /* ****************************************************** */ /* FILTERED ACTION DATA - TYPES ---> XXX DEPRECEATED OLD ANIM SYSTEM CODE! */ diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 287a6f214c0..22aa92e6d72 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -1023,4 +1023,123 @@ void GPENCIL_OT_interpolate_sequence(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/* ******************** Remove Breakdowns ************************ */ + +/* Same as gpencil_interpolate_poll(), + * except we ALSO need to have an active frame that is a breakdown + */ +static int gpencil_interpolate_reverse_poll(bContext *C) +{ + bGPdata *gpd = CTX_data_gpencil_data(C); + bGPDlayer *gpl = CTX_data_active_gpencil_layer(C); + + /* only 3D view */ + if (CTX_wm_area(C)->spacetype != SPACE_VIEW3D) { + return 0; + } + + /* need data to interpolate */ + if (ELEM(NULL, gpd, gpl)) { + return 0; + } + + /* need to be on a breakdown frame */ + if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) { + CTX_wm_operator_poll_msg_set(C, "Expected current frame to be a breakdown"); + return 0; + } + + return 1; +} + +static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *op) +{ + /* Go through each layer, deleting the breakdowns around the current frame, + * but only if there is a keyframe nearby to stop at + */ + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + bGPDframe *start_key = NULL; + bGPDframe *end_key = NULL; + bGPDframe *gpf, *gpfn; + + /* Only continue if we're currently on a breakdown keyframe */ + if ((gpl->actframe == NULL) || (gpl->actframe->key_type != BEZT_KEYTYPE_BREAKDOWN)) + continue; + + /* Search left for "start_key" (i.e. the first breakdown to remove) */ + gpf = gpl->actframe; + while (gpf) { + if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) { + /* A breakdown... keep going left */ + start_key = gpf; + gpf = gpf->prev; + } + else { + /* Not a breakdown (may be a key, or an extreme, or something else that wasn't generated)... stop */ + break; + } + } + + /* Search right for "end_key" (i.e. the last breakdown to remove) */ + gpf = gpl->actframe; + while (gpf) { + if (gpf->key_type == BEZT_KEYTYPE_BREAKDOWN) { + /* A breakdown... keep going right */ + end_key = gpf; + gpf = gpf->next; + } + else { + /* Not a breakdown... stop */ + break; + } + } + + /* Did we find anything? */ + /* NOTE: We should only proceed if there's something before/after these extents... + * Otherwise, there's just an extent of breakdowns with no keys to interpolate between + */ + if ((start_key && end_key) && + ELEM(NULL, start_key->prev, end_key->next) == false) + { + /* Set actframe to the key before start_key, since the keys have been removed now */ + gpl->actframe = start_key->prev; + + /* Free each frame we're removing (except the last one) */ + for (gpf = start_key; gpf && gpf != end_key; gpf = gpfn) { + gpfn = gpf->next; + + /* free strokes and their associated memory */ + BKE_gpencil_free_strokes(gpf); + BLI_freelinkN(&gpl->frames, gpf); + } + + /* Now free the last one... */ + BKE_gpencil_free_strokes(end_key); + BLI_freelinkN(&gpl->frames, end_key); + } + } + CTX_DATA_END; + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_interpolate_reverse(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Breakdowns"; + ot->idname = "GPENCIL_OT_interpolate_reverse"; + ot->description = "Remove breakdown frames generated by interpolating between two Grease Pencil frames"; + + /* callbacks */ + ot->exec = gpencil_interpolate_reverse_exec; + ot->poll = gpencil_interpolate_reverse_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* *************************************************************** */ diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 057d53ea458..82bbc476c2a 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -443,6 +443,7 @@ void ED_operatortypes_gpencil(void) /* Interpolation */ WM_operatortype_append(GPENCIL_OT_interpolate); WM_operatortype_append(GPENCIL_OT_interpolate_sequence); + WM_operatortype_append(GPENCIL_OT_interpolate_reverse); } void ED_operatormacros_gpencil(void) From e138cdeeb637bb63f2a66728db1c3281ac1fca09 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 15 Dec 2016 11:12:43 +0100 Subject: [PATCH 526/590] Transform manipulator: Allow first clicking Shift before selecting axis Avoids possible jumps when one is trying to do some really preciese tweak. Quite striaghtforward change for mouse input initialization: take Shift state into account. However, this will interfere with the axis exclusion which is currently also uses Shift (the feature to move something in a plane which doesn't have selected axis). This is probably not so commonly used feature (nobody in the studio even knew of it) and the only downside now would be that such a constrainted movement will become accurate by default. That's easy to deal from user side by just unholding Shift key. Reviewers: brecht, mont29, Severin Differential Revision: https://developer.blender.org/D2418 --- source/blender/editors/transform/transform.c | 4 ++-- source/blender/editors/transform/transform.h | 2 +- source/blender/editors/transform/transform_input.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 20c62e91d01..31ffa019e4e 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -2176,7 +2176,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve calculateCenter(t); if (event) { - initMouseInput(t, &t->mouse, t->center2d, event->mval); + initMouseInput(t, &t->mouse, t->center2d, event->mval, event->shift); } switch (mode) { @@ -8495,7 +8495,7 @@ static void initTimeScale(TransInfo *t) center[1] = t->mouse.imval[1]; /* force a reinit with the center2d used here */ - initMouseInput(t, &t->mouse, center, t->mouse.imval); + initMouseInput(t, &t->mouse, center, t->mouse.imval, false); initMouseInputMode(t, &t->mouse, INPUT_SPRING_FLIP); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index a59f9dc43dd..7ea4448a44e 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -728,7 +728,7 @@ typedef enum { INPUT_CUSTOM_RATIO_FLIP, } MouseInputMode; -void initMouseInput(TransInfo *t, MouseInput *mi, const float center[2], const int mval[2]); +void initMouseInput(TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision); void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode); eRedrawFlag handleMouseInput(struct TransInfo *t, struct MouseInput *mi, const struct wmEvent *event); void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, const int mval[2], float output[3]); diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c index 9b7d19eacd5..42cc918ec8c 100644 --- a/source/blender/editors/transform/transform_input.c +++ b/source/blender/editors/transform/transform_input.c @@ -234,10 +234,10 @@ static void InputAngleSpring(TransInfo *t, MouseInput *mi, const double mval[2], output[1] = toutput[0]; } -void initMouseInput(TransInfo *UNUSED(t), MouseInput *mi, const float center[2], const int mval[2]) +void initMouseInput(TransInfo *UNUSED(t), MouseInput *mi, const float center[2], const int mval[2], const bool precision) { mi->factor = 0; - mi->precision = 0; + mi->precision = precision; mi->center[0] = center[0]; mi->center[1] = center[1]; From d216313732e69317a77de2a9368483f5c922c32c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 18 Jan 2017 12:20:53 +0100 Subject: [PATCH 527/590] Cleanup: Strict compiler flags Also seems the new file forced trailing whitespace, which goes against https://wiki.blender.org/index.php/Dev:Doc/Code_Style#Trailing_Space --- source/blender/editors/gpencil/gpencil_interpolate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 22aa92e6d72..0d3fa1fc90c 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -1052,7 +1052,7 @@ static int gpencil_interpolate_reverse_poll(bContext *C) return 1; } -static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *op) +static int gpencil_interpolate_reverse_exec(bContext *C, wmOperator *UNUSED(op)) { /* Go through each layer, deleting the breakdowns around the current frame, * but only if there is a keyframe nearby to stop at From 196520fe7d813996193423f896c5aa38c084cac2 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Wed, 18 Jan 2017 12:25:49 +0100 Subject: [PATCH 528/590] GPencil: Fix unreported error in animation after rename items If the layers or the colors were renamed, the animation data was wrong because the data path was not updated. I also have fixed a possible stroke color name update if the name was duplicated moving the rename function call after checking unique name. --- source/blender/makesrna/intern/rna_gpencil.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 9c66a86dcee..95d567698d8 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -31,6 +31,8 @@ #include "MEM_guardedalloc.h" +#include "BKE_animsys.h" + #include "BLI_string_utils.h" #include "BLI_utildefines.h" @@ -353,10 +355,16 @@ static void rna_GPencilLayer_info_set(PointerRNA *ptr, const char *value) bGPdata *gpd = ptr->id.data; bGPDlayer *gpl = ptr->data; + char oldname[128] = ""; + BLI_strncpy(oldname, gpl->info, sizeof(oldname)); + /* copy the new name into the name slot */ BLI_strncpy_utf8(gpl->info, value, sizeof(gpl->info)); BLI_uniquename(&gpd->layers, gpl, DATA_("GP_Layer"), '.', offsetof(bGPDlayer, info), sizeof(gpl->info)); + + /* now fix animation paths */ + BKE_animdata_fix_paths_rename_all(&gpd->id, "layers", oldname, gpl->info); } static void rna_GPencil_use_onion_skinning_set(PointerRNA *ptr, const int value) @@ -814,14 +822,20 @@ static void rna_GPencilPaletteColor_info_set(PointerRNA *ptr, const char *value) bGPdata *gpd = ptr->id.data; bGPDpalette *palette = BKE_gpencil_palette_getactive(gpd); bGPDpalettecolor *palcolor = ptr->data; - - /* rename all strokes */ - BKE_gpencil_palettecolor_changename(gpd, palcolor->info, value); + + char oldname[64] = ""; + BLI_strncpy(oldname, palcolor->info, sizeof(oldname)); /* copy the new name into the name slot */ BLI_strncpy_utf8(palcolor->info, value, sizeof(palcolor->info)); BLI_uniquename(&palette->colors, palcolor, DATA_("Color"), '.', offsetof(bGPDpalettecolor, info), sizeof(palcolor->info)); + + /* rename all strokes */ + BKE_gpencil_palettecolor_changename(gpd, oldname, palcolor->info); + + /* now fix animation paths */ + BKE_animdata_fix_paths_rename_all(&gpd->id, "colors", oldname, palcolor->info); } static void rna_GPencilStrokeColor_info_set(PointerRNA *ptr, const char *value) From 86b6006ef8461149e37c868b1ef2e6c9f2957a39 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Wed, 18 Jan 2017 13:00:09 +0100 Subject: [PATCH 529/590] GPencil: Cleanup - move include line to correct scope --- source/blender/makesrna/intern/rna_gpencil.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 95d567698d8..25cd7265c3e 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -31,8 +31,6 @@ #include "MEM_guardedalloc.h" -#include "BKE_animsys.h" - #include "BLI_string_utils.h" #include "BLI_utildefines.h" @@ -62,6 +60,7 @@ static EnumPropertyItem parent_type_items[] = { #include "WM_api.h" +#include "BKE_animsys.h" #include "BKE_gpencil.h" #include "BKE_action.h" From 259447300f67e66169211950137b862e8a018d0e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 19 Jan 2017 02:11:51 +1300 Subject: [PATCH 530/590] GPencil: "Add Blank Frame" operator (D+B) This operator adds a new frame with nothing in it on the current frame. If there is already a frame there, all existing frames are shifted one frame later. Quite often when animating, you may want a quick way to get a blank frame, ready to start drawing something new. Or maybe you just need a quick way to add a "placeholder" frame so that a suddenly-appearing element does not show up before its time. --- .../bl_ui/properties_grease_pencil_common.py | 6 ++ source/blender/editors/gpencil/gpencil_edit.c | 74 +++++++++++++++++++ .../blender/editors/gpencil/gpencil_intern.h | 2 + source/blender/editors/gpencil/gpencil_ops.c | 6 ++ 4 files changed, 88 insertions(+) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 3d68930e632..3df60584d3b 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -115,6 +115,12 @@ class GreasePencilDrawingToolsPanel: row.operator("gpencil.draw", icon='LINE_DATA', text="Line").mode = 'DRAW_STRAIGHT' row.operator("gpencil.draw", icon='MESH_DATA', text="Poly").mode = 'DRAW_POLY' + col.separator() + + sub = col.column(align=True) + sub.operator("gpencil.blank_frame_add", icon='NEW') + sub.operator("gpencil.active_frames_delete_all", icon='X', text="Delete Frame(s)") + sub = col.column(align=True) sub.prop(context.tool_settings, "use_gpencil_additive_drawing", text="Additive Drawing") sub.prop(context.tool_settings, "use_gpencil_continuous_drawing", text="Continuous Drawing") diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 36c7ef78d96..1f351657c20 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -682,6 +682,80 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot) RNA_def_enum_funcs(ot->prop, ED_gpencil_layers_with_new_enum_itemf); } +/* ********************* Add Blank Frame *************************** */ + +/* Basically the same as the drawing op */ +static int gp_blank_frame_add_poll(bContext *C) +{ + if (ED_operator_regionactive(C)) { + /* check if current context can support GPencil data */ + if (ED_gpencil_data_get_pointers(C, NULL) != NULL) { + return 1; + } + else { + CTX_wm_operator_poll_msg_set(C, "Failed to find Grease Pencil data to draw into"); + } + } + else { + CTX_wm_operator_poll_msg_set(C, "Active region not set"); + } + + return 0; +} + +static int gp_blank_frame_add_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Scene *scene = CTX_data_scene(C); + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + + /* Initialise datablock and an active layer if nothing exists yet */ + if (ELEM(NULL, gpd, gpl)) { + /* let's just be lazy, and call the "Add New Layer" operator, which sets everything up as required */ + WM_operator_name_call(C, "GPENCIL_OT_layer_add", WM_OP_EXEC_DEFAULT, NULL); + } + + /* Go through each layer, adding a frame after the active one + * and/or shunting all the others out of the way + */ + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + /* 1) Check for an existing frame on the current frame */ + bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, CFRA); + if (gpf) { + /* Shunt all frames after (and including) the existing one later by 1-frame */ + for (; gpf; gpf = gpf->next) { + gpf->framenum += 1; + } + } + + /* 2) Now add a new frame, with nothing in it */ + gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_NEW); + } + CTX_DATA_END; + + /* notifiers */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_blank_frame_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Blank Frame"; + ot->idname = "GPENCIL_OT_blank_frame_add"; + ot->description = "Add a new frame with nothing in it on the current frame. " + "If there is already a frame, all existing frames are shifted one frame later"; + + /* callbacks */ + ot->exec = gp_blank_frame_add_exec; + ot->poll = gp_add_poll; + + /* properties */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + /* ******************* Delete Active Frame ************************ */ static int gp_actframe_delete_poll(bContext *C) diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index cb293dda1ea..5c7c9b84adb 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -287,6 +287,8 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot); void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot); void GPENCIL_OT_layer_merge(struct wmOperatorType *ot); +void GPENCIL_OT_blank_frame_add(struct wmOperatorType *ot); + void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot); void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 82bbc476c2a..78e1a0dda36 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -102,6 +102,10 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_tool_palette", QKEY, KM_PRESS, 0, DKEY); WM_keymap_add_menu_pie(keymap, "GPENCIL_PIE_settings_palette", WKEY, KM_PRESS, 0, DKEY); + /* Add Blank Frame */ + /* XXX: BKEY or NKEY? BKEY is easier to reach from DKEY, so we'll use that for now */ + WM_keymap_add_item(keymap, "GPENCIL_OT_blank_frame_add", BKEY, KM_PRESS, 0, DKEY); + /* Delete Active Frame - For easier video tutorials/review sessions */ /* NOTE: This works even when not in EditMode */ WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY); @@ -401,6 +405,8 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_layer_isolate); WM_operatortype_append(GPENCIL_OT_layer_merge); + WM_operatortype_append(GPENCIL_OT_blank_frame_add); + WM_operatortype_append(GPENCIL_OT_active_frame_delete); WM_operatortype_append(GPENCIL_OT_active_frames_delete_all); From a93881d70433853c2f77a13bb176a9758316811b Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 19 Jan 2017 02:24:41 +1300 Subject: [PATCH 531/590] GPencil: Pressing 'B' while in 'Continuous Drawing' mode will create a blank frame This is a hardcoded keymapping that just calls the "Add Blank Frame" operator introduced in the previous commit. --- source/blender/editors/gpencil/gpencil_paint.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index c23bfb1ff60..c2228a932fe 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -2432,6 +2432,14 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) /* enable continuous if release D key in mid drawing */ p->scene->toolsettings->gpencil_flags |= GP_TOOL_FLAG_PAINTSESSIONS_ON; } + else if ((event->type == BKEY) && (event->val == KM_RELEASE)) { + /* Add Blank Frame + * - Since this operator is non-modal, we can just call it here, and keep going... + * - This operator is especially useful when animating + */ + WM_operator_name_call(C, "GPENCIL_OT_blank_frame_add", WM_OP_EXEC_DEFAULT, NULL); + estate = OPERATOR_RUNNING_MODAL; + } else { estate = OPERATOR_RUNNING_MODAL; } From 7452af0f868b061a63648e9c351090462d7b01e8 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 19 Jan 2017 02:57:08 +1300 Subject: [PATCH 532/590] Fix: Avoid creating redundant frames when erasing Now the eraser checks if there's an active frame with some strokes in it before creating a new frame. There's no point in creating a new frame if there are no strokes in the active frame (if one exists). This still doesn't help much if there were strokes but they weren't touched though... --- source/blender/editors/gpencil/gpencil_paint.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index c2228a932fe..74c7a45a24e 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1631,8 +1631,14 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) /* Add a new frame if needed (and based off the active frame, * as we need some existing strokes to erase) + * + * Note: We don't add a new frame if there's nothing there now, so + * -> If there are no frames at all, don't add one + * -> If there are no strokes in that frame, don't add a new empty frame */ - gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY); + if (gpl->actframe && gpl->actframe->strokes.first) { + gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY); + } /* XXX: we omit GP_FRAME_PAINT here for now, * as it is only really useful for doing @@ -1655,7 +1661,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; //if (G.debug & G_DEBUG) - printf("Error: No frame created (gpencil_paint_init)\n"); + printf("Error: No frame created for eraser on active layer (gpencil_paint_init)\n"); return; } } @@ -2602,7 +2608,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } else if (p->status != GP_STATUS_ERROR) { /* User clicked outside bounds of window while idling, so exit paintmode - * NOTE: Don't eter this case if an error occurred while finding the + * NOTE: Don't enter this case if an error occurred while finding the * region (as above) */ /* if drawing polygon and enable on back, must move stroke */ From 00edc600b0319fc239ae4cb9c0a98452b2d6c74e Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 19 Jan 2017 03:00:33 +1300 Subject: [PATCH 533/590] Fix: Make it possible to erase strokes (on other layers) even if the active layer doesn't have any frames --- source/blender/editors/gpencil/gpencil_paint.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 74c7a45a24e..5879306b06c 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1623,8 +1623,9 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) * 2) Ensure that p->gpf refers to the frame used for the active layer * (to avoid problems with other tools which expect it to exist) */ - bGPDlayer *gpl; - for (gpl = p->gpd->layers.first; gpl; gpl = gpl->next) { + bool has_layer_to_erase = false; + + for (bGPDlayer *gpl = p->gpd->layers.first; gpl; gpl = gpl->next) { /* Skip if layer not editable */ if (gpencil_layer_is_editable(gpl) == false) continue; @@ -1638,6 +1639,7 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) */ if (gpl->actframe && gpl->actframe->strokes.first) { gpl->actframe = BKE_gpencil_layer_getframe(gpl, CFRA, GP_GETFRAME_ADD_COPY); + has_layer_to_erase = true; } /* XXX: we omit GP_FRAME_PAINT here for now, @@ -1658,10 +1660,10 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) } } - if (p->gpf == NULL) { + if (has_layer_to_erase == false) { p->status = GP_STATUS_ERROR; //if (G.debug & G_DEBUG) - printf("Error: No frame created for eraser on active layer (gpencil_paint_init)\n"); + printf("Error: Eraser will not be affecting anything (gpencil_paint_init)\n"); return; } } From 6d868d9f48a35a0576e9e4e7b6442bdc0fc8d282 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Thu, 19 Jan 2017 03:20:44 +1300 Subject: [PATCH 534/590] Reproject Strokes - To Surface/Geometry Experimental option for the Reproject Strokes operator to project strokes on to geometry, instead of only doing this in a planar (i.e. parallel to viewplane) way. The current implementation is quite rough, and may need to be improved before it is really ready for use. Potential issues: * Loss of precision (i.e. stairstepping artifacts) from the 3D -> 2D -> 3D conversion as we don't have float version of one of the projection funcs * Jagged depth if there are gaps, since it will default back to the 3d-cursor plane if no geometry was found (instead of doing some fancy interpolation scheme) * I'm not sure if it's that useful for adapting GP strokes to deforming geometry yet... --- .../bl_ui/properties_grease_pencil_common.py | 2 +- source/blender/editors/gpencil/gpencil_edit.c | 58 +++++++++++++++++-- 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 3df60584d3b..4529c127839 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -248,7 +248,7 @@ class GreasePencilStrokeEditPanel: if is_3d_view: layout.separator() - layout.operator("gpencil.reproject") + layout.operator_menu_enum("gpencil.reproject", text="Reproject Strokes...", property="type") class GreasePencilInterpolatePanel: diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 1f351657c20..8470cd78d91 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -1971,6 +1971,13 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot) /* ***************** Reproject Strokes ********************** */ +typedef enum eGP_ReprojectModes { + /* On same plane, parallel to viewplane */ + GP_REPROJECT_PLANAR = 0, + /* Reprojected on to the scene geometry */ + GP_REPROJECT_SURFACE, +} eGP_ReprojectModes; + static int gp_strokes_reproject_poll(bContext *C) { /* 2 Requirements: @@ -1980,14 +1987,23 @@ static int gp_strokes_reproject_poll(bContext *C) return (gp_stroke_edit_poll(C) && ED_operator_view3d_active(C)); } -static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op)) +static int gp_strokes_reproject_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); GP_SpaceConversion gsc = {NULL}; + eGP_ReprojectModes mode = RNA_boolean_get(op->ptr, "type"); /* init space conversion stuff */ gp_point_conversion_init(C, &gsc); + /* init autodist for geometry projection */ + if (mode == GP_REPROJECT_SURFACE) { + view3d_region_operator_needs_opengl(CTX_wm_window(C), gsc.ar); + ED_view3d_autodist_init(scene, gsc.ar, CTX_wm_view3d(C), 0); + } + + // TODO: For deforming geometry workflow, create new frames? + /* Go through each editable + selected stroke, adjusting each of its points one by one... */ GP_EDITABLE_STROKES_BEGIN(C, gpl, gps) { @@ -2023,7 +2039,27 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op)) /* 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); + if (mode == GP_REPROJECT_PLANAR) { + /* Planar - All on same plane parallel to the viewplane */ + gp_point_xy_to_3d(&gsc, scene, xy, &pt->x); + } + else { + /* Geometry - Snap to surfaces of visible geometry */ + /* XXX: There will be precision loss (possible stairstep artifacts) from this conversion to satisfy the API's */ + const int screen_co[2] = {(int)xy[0], (int)xy[1]}; + + int depth_margin = 0; // XXX: 4 for strokes, 0 for normal + float depth; + + /* XXX: The proper procedure computes the depths into an array, to have smooth transitions when all else fails... */ + if (ED_view3d_autodist_depth(gsc.ar, screen_co, depth_margin, &depth)) { + ED_view3d_autodist_simple(gsc.ar, screen_co, &pt->x, 0, &depth); + } + else { + /* Default to planar */ + gp_point_xy_to_3d(&gsc, scene, xy, &pt->x); + } + } /* Unapply parent corrections */ if (gpl->parent) { @@ -2040,18 +2076,32 @@ static int gp_strokes_reproject_exec(bContext *C, wmOperator *UNUSED(op)) void GPENCIL_OT_reproject(wmOperatorType *ot) { + static EnumPropertyItem reproject_type[] = { + {GP_REPROJECT_PLANAR, "PLANAR", 0, "Planar", + "Reproject the strokes to end up on the same plane, as if drawn from the current viewpoint " + "using 'Cursor' Stroke Placement"}, + {GP_REPROJECT_SURFACE, "SURFACE", 0, "Surface", + "Reproject the strokes on to the scene geometry, as if drawn using 'Surface' placement"}, + {0, NULL, 0, NULL, NULL} + }; + /* 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)"; + ot->description = "Reproject the selected strokes from the current viewpoint as if they had been newly drawn " + "(e.g. to fix problems from accidental 3D cursor movement or accidental viewport changes, " + "or for matching deforming geometry)"; /* callbacks */ + ot->invoke = WM_menu_invoke; ot->exec = gp_strokes_reproject_exec; ot->poll = gp_strokes_reproject_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_enum(ot->srna, "type", reproject_type, GP_REPROJECT_PLANAR, "Projection Type", ""); } /* ******************* Stroke subdivide ************************** */ From b059a7165549893f629ed189622745e675659d53 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 18 Jan 2017 15:56:04 +0100 Subject: [PATCH 535/590] GPencil: Avoid variable shadowing --- source/blender/editors/gpencil/gpencil_edit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 8470cd78d91..3ac085e23d7 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -707,10 +707,10 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl = BKE_gpencil_layer_getactive(gpd); + bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd); /* Initialise datablock and an active layer if nothing exists yet */ - if (ELEM(NULL, gpd, gpl)) { + if (ELEM(NULL, gpd, active_gpl)) { /* let's just be lazy, and call the "Add New Layer" operator, which sets everything up as required */ WM_operator_name_call(C, "GPENCIL_OT_layer_add", WM_OP_EXEC_DEFAULT, NULL); } From a48d3417b566236ad48a107e6d0b98687f96c4fd Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 18 Jan 2017 15:56:40 +0100 Subject: [PATCH 536/590] Fix strict compiler warning message --- source/blender/editors/gpencil/gpencil_edit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 3ac085e23d7..ccccd6381b2 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -685,7 +685,7 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot) /* ********************* Add Blank Frame *************************** */ /* Basically the same as the drawing op */ -static int gp_blank_frame_add_poll(bContext *C) +static int UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C) { if (ED_operator_regionactive(C)) { /* check if current context can support GPencil data */ From fd4728c85a6e3a7041f6ff62d73b15e432b84f92 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Jan 2017 07:59:32 +1100 Subject: [PATCH 537/590] BMesh: Use angle_signed_on_axis_v3v3v3_v3 --- source/blender/bmesh/intern/bmesh_construct.c | 20 +------------------ 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index 132a7ccd4fa..af7ef01da73 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -470,25 +470,7 @@ BMFace *BM_face_create_ngon_vcloud( /* now calculate every points angle around the normal (signed) */ for (i = 0; i < len; i++) { - float co[3]; - float proj_vec[3]; - float angle; - - /* center relative vec */ - sub_v3_v3v3(co, vert_arr[i]->co, cent); - - /* align to plane */ - project_v3_v3v3(proj_vec, co, nor); - sub_v3_v3(co, proj_vec); - - /* now 'co' is valid - we can compare its angle against the far vec */ - angle = angle_v3v3(far_vec, co); - - if (dot_v3v3(co, sign_vec) < 0.0f) { - angle = -angle; - } - - vang[i].sort_value = angle; + vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor); vang[i].data = i; } From 11187e86283a2bada088f718dd6012e0c7d6d19e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Jan 2017 09:04:50 +1100 Subject: [PATCH 538/590] Fix face-creation with existing hidden geometry - face-create-extend option could add hidden verts and edges into the selection history (invalid state). - faces could be created that included existing hidden edges that remained hidden (invalid state too). - newly created faces could copy hidden flag from surrounding faces, giving very confusing results (looks as if face creation failed). Surprising nobody noticed these years old bugs! --- source/blender/editors/mesh/editmesh_tools.c | 33 +++++++++++++++----- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index c57b0215d46..8f004bcf72b 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -684,27 +684,38 @@ static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_ /* now we need to find the edge that isnt connected to this element */ BM_select_history_clear(bm); + /* Notes on hidden geometry: + * - un-hide the face since its possible hidden was copied when copying surrounding face attributes. + * - un-hide before adding to select history + * since we may extend into an existing, hidden vert/edge. + */ + + BM_elem_flag_disable(f, BM_ELEM_HIDDEN); + BM_face_select_set(bm, f, false); + if (ele_desel->head.htype == BM_VERT) { BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel); BLI_assert(f->len == 3); - BM_face_select_set(bm, f, false); BM_vert_select_set(bm, (BMVert *)ele_desel, false); - BM_edge_select_set(bm, l->next->e, true); BM_select_history_store(bm, l->next->e); } else { BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel); BLI_assert(f->len == 4 || f->len == 3); - BM_face_select_set(bm, f, false); + BM_edge_select_set(bm, (BMEdge *)ele_desel, false); if (f->len == 4) { - BM_edge_select_set(bm, l->next->next->e, true); - BM_select_history_store(bm, l->next->next->e); + BMEdge *e_active = l->next->next->e; + BM_elem_flag_disable(e_active, BM_ELEM_HIDDEN); + BM_edge_select_set(bm, e_active, true); + BM_select_history_store(bm, e_active); } else { - BM_vert_select_set(bm, l->next->next->v, true); - BM_select_history_store(bm, l->next->next->v); + BMVert *v_active = l->next->next->v; + BM_elem_flag_disable(v_active, BM_ELEM_HIDDEN); + BM_vert_select_set(bm, v_active, true); + BM_select_history_store(bm, v_active); } } } @@ -758,6 +769,14 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op) else #endif { + /* Newly created faces may include existing hidden edges, + * copying face data from surrounding, may have copied hidden face flag too. + * + * Important that faces use flushing since 'edges.out' wont include hidden edges that already existed. + */ + BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_HIDDEN, true); + BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_HIDDEN, false); + BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true); BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true); } From 1455023e643044a6d1d220a0a27a67e344c699a9 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Jan 2017 10:35:10 +1100 Subject: [PATCH 539/590] Fix T49807: Inset faces edge rail bug --- source/blender/bmesh/operators/bmo_inset.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index c52c608e671..e2ff09669d7 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -647,6 +647,10 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) } (void)0 #define VERT_ORIG_GET(_v) \ (const float *)BLI_ghash_lookup_default(vert_coords, (_v), (_v)->co) + /* memory for the coords isn't given back to the arena, + * acceptable in this case since it runs a fixed number of times. */ +#define VERT_ORIG_REMOVE(_v) \ + BLI_ghash_remove(vert_coords, (_v), NULL, NULL) for (i = 0, es = edge_info; i < edge_info_len; i++, es++) { @@ -972,7 +976,11 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) v_glue = v_split; } else { - BM_vert_splice(bm, v_glue, v_split); + if (BM_vert_splice(bm, v_glue, v_split)) { + if (use_vert_coords_orig) { + VERT_ORIG_REMOVE(v_split); + } + } } } } From 4a1911227798e067c09f101d552112724b999a3d Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Thu, 19 Jan 2017 00:39:52 +0100 Subject: [PATCH 540/590] Cycles: Fix amount of rendered samples not being shown while rendering the last tile on CPU --- intern/cycles/render/session.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 73caf93ea00..7c01934cfd8 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -458,6 +458,8 @@ void Session::release_tile(RenderTile& rtile) { thread_scoped_lock tile_lock(tile_mutex); + progress.add_finished_tile(); + if(write_render_tile_cb) { if(params.progressive_refine == false) { /* todo: optimize this by making it thread safe and removing lock */ From b76dbf5e65b89b1f276a6c007c6c9541910c3f5c Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Wed, 18 Jan 2017 19:38:55 -0500 Subject: [PATCH 541/590] UI: Fix capitalization inconsistency --- release/scripts/startup/bl_ui/properties_game.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index 98b7a76e541..4d54817a21c 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -714,7 +714,7 @@ class WORLD_PT_game_physics(WorldButtonsPanel, Panel): class WORLD_PT_game_physics_obstacles(WorldButtonsPanel, Panel): - bl_label = "Obstacle simulation" + bl_label = "Obstacle Simulation" COMPAT_ENGINES = {'BLENDER_GAME'} @classmethod From e2d02fee3010771abd88bba5481a5867f4f4197f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Jan 2017 22:45:15 +1100 Subject: [PATCH 542/590] BMesh: improve hide-flush internal logic - flushing hidden state ran when it didn't need to. - flushing checks didn't early exit when first visible element found. - low level BM_*_hide API calls like this can use skip iterators can loop over struct members directly. No user-visible changes. --- source/blender/bmesh/intern/bmesh_marking.c | 127 +++++++++++++------- 1 file changed, 82 insertions(+), 45 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index 7178a8132d2..93e743b6cd1 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -70,7 +70,7 @@ static void recount_totsels(BMesh *bm) } } -/** \name BMesh helper functions for selection flushing. +/** \name BMesh helper functions for selection & hide flushing. * \{ */ static bool bm_vert_is_edge_select_any_other(const BMVert *v, const BMEdge *e_first) @@ -102,6 +102,20 @@ static bool bm_vert_is_edge_select_any(const BMVert *v) } #endif +static bool bm_vert_is_edge_visible_any(const BMVert *v) +{ + if (v->e) { + const BMEdge *e_iter, *e_first; + e_iter = e_first = v->e; + do { + if (!BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN)) { + return true; + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first); + } + return false; +} + static bool bm_edge_is_face_select_any_other(BMLoop *l_first) { const BMLoop *l_iter = l_first; @@ -131,6 +145,20 @@ static bool bm_edge_is_face_select_any(const BMEdge *e) } #endif +static bool bm_edge_is_face_visible_any(const BMEdge *e) +{ + if (e->l) { + const BMLoop *l_iter, *l_first; + l_iter = l_first = e->l; + do { + if (!BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) { + return true; + } + } while ((l_iter = l_iter->radial_next) != l_first); + } + return false; +} + /** \} */ /** @@ -1198,87 +1226,96 @@ void BM_mesh_elem_hflag_enable_all( /***************** Mesh Hiding stuff *********** */ +/* Hide unless any connected elements are visible */ + static void vert_flush_hide_set(BMVert *v) { - BMIter iter; - BMEdge *e; - bool hide = true; - - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - hide = hide && BM_elem_flag_test(e, BM_ELEM_HIDDEN); - } - - BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide); + BM_elem_flag_set(v, BM_ELEM_HIDDEN, !bm_vert_is_edge_visible_any(v)); } static void edge_flush_hide(BMEdge *e) { - BMIter iter; - BMFace *f; - bool hide = true; - - BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - hide = hide && BM_elem_flag_test(f, BM_ELEM_HIDDEN); - } - - BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide); + BM_elem_flag_set(e, BM_ELEM_HIDDEN, !bm_edge_is_face_visible_any(e)); } void BM_vert_hide_set(BMVert *v, const bool hide) { /* vert hiding: vert + surrounding edges and faces */ - BMIter iter, fiter; - BMEdge *e; - BMFace *f; - BLI_assert(v->head.htype == BM_VERT); BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide); - BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide); - - BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide); - } + if (v->e) { + BMEdge *e_iter, *e_first; + e_iter = e_first = v->e; + do { + BM_elem_flag_set(e_iter, BM_ELEM_HIDDEN, hide); + if (e_iter->l) { + const BMLoop *l_radial_iter, *l_radial_first; + l_radial_iter = l_radial_first = e_iter->l; + do { + BM_elem_flag_set(l_radial_iter->f, BM_ELEM_HIDDEN, hide); + } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first); + } + } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first); } } void BM_edge_hide_set(BMEdge *e, const bool hide) { - BMIter iter; - BMFace *f; - /* BMVert *v; */ - BLI_assert(e->head.htype == BM_EDGE); /* edge hiding: faces around the edge */ - BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide); + if (e->l) { + const BMLoop *l_iter, *l_first; + l_iter = l_first = e->l; + do { + BM_elem_flag_set(l_iter->f, BM_ELEM_HIDDEN, hide); + } while ((l_iter = l_iter->radial_next) != l_first); } BM_elem_flag_set(e, BM_ELEM_HIDDEN, hide); /* hide vertices if necessary */ - vert_flush_hide_set(e->v1); - vert_flush_hide_set(e->v2); + if (hide) { + vert_flush_hide_set(e->v1); + vert_flush_hide_set(e->v2); + } + else { + BM_elem_flag_disable(e->v1, BM_ELEM_HIDDEN); + BM_elem_flag_disable(e->v2, BM_ELEM_HIDDEN); + } } void BM_face_hide_set(BMFace *f, const bool hide) { - BMIter iter; - BMLoop *l; - BLI_assert(f->head.htype == BM_FACE); BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide); - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - edge_flush_hide(l->e); - } + if (hide) { + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter; - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - vert_flush_hide_set(l->v); + l_iter = l_first; + do { + edge_flush_hide(l_iter->e); + } while ((l_iter = l_iter->next) != l_first); + + l_iter = l_first; + do { + vert_flush_hide_set(l_iter->v); + } while ((l_iter = l_iter->next) != l_first); + } + else { + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter; + + l_iter = l_first; + do { + BM_elem_flag_disable(l_iter->e, BM_ELEM_HIDDEN); + BM_elem_flag_disable(l_iter->v, BM_ELEM_HIDDEN); + } while ((l_iter = l_iter->next) != l_first); } } From 666cb5ddd9a11e88853e012bf57ba05fca09c60f Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 19 Jan 2017 22:59:41 +1100 Subject: [PATCH 543/590] Cleanup: naming, comments assert for hide+selected --- source/blender/bmesh/intern/bmesh_marking.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index 93e743b6cd1..2231a98a116 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -1226,14 +1226,20 @@ void BM_mesh_elem_hflag_enable_all( /***************** Mesh Hiding stuff *********** */ -/* Hide unless any connected elements are visible */ - +/** + * Hide unless any connected elements are visible. + * Run this after hiding a connected edge or face. + */ static void vert_flush_hide_set(BMVert *v) { BM_elem_flag_set(v, BM_ELEM_HIDDEN, !bm_vert_is_edge_visible_any(v)); } -static void edge_flush_hide(BMEdge *e) +/** + * Hide unless any connected elements are visible. + * Run this after hiding a connected face. + */ +static void edge_flush_hide_set(BMEdge *e) { BM_elem_flag_set(e, BM_ELEM_HIDDEN, !bm_edge_is_face_visible_any(e)); } @@ -1242,6 +1248,7 @@ void BM_vert_hide_set(BMVert *v, const bool hide) { /* vert hiding: vert + surrounding edges and faces */ BLI_assert(v->head.htype == BM_VERT); + BLI_assert(!BM_elem_flag_test(v, BM_ELEM_SELECT)); BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide); @@ -1264,6 +1271,7 @@ void BM_vert_hide_set(BMVert *v, const bool hide) void BM_edge_hide_set(BMEdge *e, const bool hide) { BLI_assert(e->head.htype == BM_EDGE); + BLI_assert(!BM_elem_flag_test(e, BM_ELEM_SELECT)); /* edge hiding: faces around the edge */ if (e->l) { @@ -1290,6 +1298,7 @@ void BM_edge_hide_set(BMEdge *e, const bool hide) void BM_face_hide_set(BMFace *f, const bool hide) { BLI_assert(f->head.htype == BM_FACE); + BLI_assert(!BM_elem_flag_test(f, BM_ELEM_SELECT)); BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide); @@ -1299,7 +1308,7 @@ void BM_face_hide_set(BMFace *f, const bool hide) l_iter = l_first; do { - edge_flush_hide(l_iter->e); + edge_flush_hide_set(l_iter->e); } while ((l_iter = l_iter->next) != l_first); l_iter = l_first; From 446ed355a56441de3031e3bcc756ec462a874439 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Thu, 19 Jan 2017 13:04:56 +0100 Subject: [PATCH 544/590] GPencil: Add option to create blank frame in active layer only Now it is possible to select if the blank frame is created in active layer only or in all layers. --- source/blender/editors/gpencil/gpencil_edit.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index ccccd6381b2..5b011b679a6 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -703,12 +703,14 @@ static int UNUSED_FUNCTION(gp_blank_frame_add_poll)(bContext *C) return 0; } -static int gp_blank_frame_add_exec(bContext *C, wmOperator *UNUSED(op)) +static int gp_blank_frame_add_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); bGPdata *gpd = ED_gpencil_data_get_active(C); bGPDlayer *active_gpl = BKE_gpencil_layer_getactive(gpd); - + + const bool all_layers = RNA_boolean_get(op->ptr, "all_layers"); + /* Initialise datablock and an active layer if nothing exists yet */ if (ELEM(NULL, gpd, active_gpl)) { /* let's just be lazy, and call the "Add New Layer" operator, which sets everything up as required */ @@ -720,6 +722,10 @@ static int gp_blank_frame_add_exec(bContext *C, wmOperator *UNUSED(op)) */ CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) { + if ((all_layers == false) && (gpl != active_gpl)) { + continue; + } + /* 1) Check for an existing frame on the current frame */ bGPDframe *gpf = BKE_gpencil_layer_find_frame(gpl, CFRA); if (gpf) { @@ -754,6 +760,7 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot) /* properties */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + RNA_def_boolean(ot->srna, "all_layers", false, "All Layers", "Create blank frame in all layers, not only active"); } /* ******************* Delete Active Frame ************************ */ From 6d36e033ba4051362a3a4985989e9d360e3888a8 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 19 Jan 2017 14:24:14 +0100 Subject: [PATCH 545/590] Cycles: Remove using namespace hell Please NEVER EVER use such a statement, it's only causing HUGE issues. What is even worse: it's not always possible to immediately see that the hell is coming from such a statement. There is still some statements in the existing code, will leave those for a later cleanup. --- intern/cycles/render/mesh_subdivision.cpp | 2 +- intern/cycles/util/util_boundbox.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/intern/cycles/render/mesh_subdivision.cpp b/intern/cycles/render/mesh_subdivision.cpp index 913c3c74b42..57c76a9f1c8 100644 --- a/intern/cycles/render/mesh_subdivision.cpp +++ b/intern/cycles/render/mesh_subdivision.cpp @@ -92,7 +92,7 @@ namespace Far { if(vert_edges.size() == 2) { float sharpness = refiner.getLevel(0).getEdgeSharpness(vert_edges[0]); - sharpness = min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1])); + sharpness = ccl::min(sharpness, refiner.getLevel(0).getEdgeSharpness(vert_edges[1])); setBaseVertexSharpness(refiner, i, sharpness); } diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h index 599222da9c5..dfe4977aef3 100644 --- a/intern/cycles/util/util_boundbox.h +++ b/intern/cycles/util/util_boundbox.h @@ -25,8 +25,6 @@ #include "util_transform.h" #include "util_types.h" -using namespace std; - CCL_NAMESPACE_BEGIN /* 3D BoundBox */ From 78b94902f839f0fb84e253d3ff1a34cc6cc51919 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 19 Jan 2017 14:41:04 +0100 Subject: [PATCH 546/590] Cycles: Add fast-math safe isnan and isfinite Currently unused, but might become really handy in the future. --- intern/cycles/util/util_math.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 6cb68b53d16..d0062646414 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -1233,6 +1233,20 @@ ccl_device_inline float __uint_as_float(uint i) return u.f; } +/* Versions of functions which are safe for fast math. */ +ccl_device_inline bool isnan_safe(float f) +{ + unsigned int x = __float_as_uint(f); + return (x << 1) > 0xff000000u; +} + +ccl_device_inline bool isfinite_safe(float f) +{ + /* By IEEE 754 rule, 2*Inf equals Inf */ + unsigned int x = __float_as_uint(f); + return (f == f) && (x == 0 || (f != 2.0f*f)); +} + /* Interpolation */ template A lerp(const A& a, const A& b, const B& t) From afdd756e56e0cffb7ac5681749abdba6aa089309 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Thu, 19 Jan 2017 14:48:43 +0100 Subject: [PATCH 547/590] Cycles: Don't use fast math for the host code This is important for the reliable behavior or isnan/isfinite/min/max functions to work with nan and non-finite values. Some of the issues with fast math are possible to work around, but didn't find a way to have reliable min/max implementation yet. --- intern/cycles/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 97854a88e84..79c1c3e3e82 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -74,7 +74,6 @@ elseif(CMAKE_COMPILER_IS_GNUCC) if(CXX_HAS_AVX2) set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c -mfpmath=sse") endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math") elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") check_cxx_compiler_flag(-msse CXX_HAS_SSE) check_cxx_compiler_flag(-mavx CXX_HAS_AVX) @@ -90,7 +89,6 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") if(CXX_HAS_AVX2) set(CYCLES_AVX2_KERNEL_FLAGS "-ffast-math -msse -msse2 -msse3 -mssse3 -msse4.1 -mavx -mavx2 -mfma -mlzcnt -mbmi -mbmi2 -mf16c") endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ffast-math") endif() if(CXX_HAS_SSE) From d6cf28c5e15739f864fbf04614c2a50708b4b152 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 6 Dec 2016 16:15:36 +0100 Subject: [PATCH 548/590] Cycles: Expose diffuse and glossy depth to Light Path node Was a bit confusing to have transparent and translucent depth exposed but no diffuse or glossy. Reviewers: brecht Subscribers: eyecandy Differential Revision: https://developer.blender.org/D2399 --- intern/cycles/kernel/osl/osl_services.cpp | 20 +++++++++++++++++++ intern/cycles/kernel/osl/osl_services.h | 2 ++ .../cycles/kernel/shaders/node_light_path.osl | 10 ++++++++++ intern/cycles/kernel/svm/svm_light_path.h | 2 ++ intern/cycles/kernel/svm/svm_types.h | 2 ++ intern/cycles/render/nodes.cpp | 12 +++++++++++ .../shader/nodes/node_shader_light_path.c | 2 ++ 7 files changed, 50 insertions(+) diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 26543862b80..eeccf9a9641 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -102,6 +102,8 @@ ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal"); #endif ustring OSLRenderServices::u_path_ray_length("path:ray_length"); ustring OSLRenderServices::u_path_ray_depth("path:ray_depth"); +ustring OSLRenderServices::u_path_diffuse_depth("path:diffuse_depth"); +ustring OSLRenderServices::u_path_glossy_depth("path:glossy_depth"); ustring OSLRenderServices::u_path_transparent_depth("path:transparent_depth"); ustring OSLRenderServices::u_path_transmission_depth("path:transmission_depth"); ustring OSLRenderServices::u_trace("trace"); @@ -759,6 +761,24 @@ bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData * int f = state->bounce; return set_attribute_int(f, type, derivatives, val); } + else if(name == u_path_diffuse_depth) { + /* Diffuse Ray Depth */ + PathState *state = sd->osl_path_state; + int f = state->diffuse_bounce; + return set_attribute_int(f, type, derivatives, val); + } + else if(name == u_path_glossy_depth) { + /* Glossy Ray Depth */ + PathState *state = sd->osl_path_state; + int f = state->glossy_bounce; + return set_attribute_int(f, type, derivatives, val); + } + else if(name == u_path_transmission_depth) { + /* Transmission Ray Depth */ + PathState *state = sd->osl_path_state; + int f = state->transmission_bounce; + return set_attribute_int(f, type, derivatives, val); + } else if(name == u_path_transparent_depth) { /* Transparent Ray Depth */ PathState *state = sd->osl_path_state; diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h index 0f2e02c62b0..ec34ca77115 100644 --- a/intern/cycles/kernel/osl/osl_services.h +++ b/intern/cycles/kernel/osl/osl_services.h @@ -165,6 +165,8 @@ public: static ustring u_curve_tangent_normal; static ustring u_path_ray_length; static ustring u_path_ray_depth; + static ustring u_path_diffuse_depth; + static ustring u_path_glossy_depth; static ustring u_path_transparent_depth; static ustring u_path_transmission_depth; static ustring u_trace; diff --git a/intern/cycles/kernel/shaders/node_light_path.osl b/intern/cycles/kernel/shaders/node_light_path.osl index a021a40467d..64fe4c20132 100644 --- a/intern/cycles/kernel/shaders/node_light_path.osl +++ b/intern/cycles/kernel/shaders/node_light_path.osl @@ -27,6 +27,8 @@ shader node_light_path( output float IsVolumeScatterRay = 0.0, output float RayLength = 0.0, output float RayDepth = 0.0, + output float DiffuseDepth = 0.0, + output float GlossyDepth = 0.0, output float TransparentDepth = 0.0, output float TransmissionDepth = 0.0) { @@ -45,6 +47,14 @@ shader node_light_path( getattribute("path:ray_depth", ray_depth); RayDepth = (float)ray_depth; + int diffuse_depth; + getattribute("path:diffuse_depth", diffuse_depth); + DiffuseDepth = (float)diffuse_depth; + + int glossy_depth; + getattribute("path:glossy_depth", glossy_depth); + GlossyDepth = (float)glossy_depth; + int transparent_depth; getattribute("path:transparent_depth", transparent_depth); TransparentDepth = (float)transparent_depth; diff --git a/intern/cycles/kernel/svm/svm_light_path.h b/intern/cycles/kernel/svm/svm_light_path.h index f35ea05048b..04f6f623f18 100644 --- a/intern/cycles/kernel/svm/svm_light_path.h +++ b/intern/cycles/kernel/svm/svm_light_path.h @@ -34,6 +34,8 @@ ccl_device void svm_node_light_path(ShaderData *sd, ccl_addr_space PathState *st case NODE_LP_backfacing: info = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f: 0.0f; break; case NODE_LP_ray_length: info = ccl_fetch(sd, ray_length); break; case NODE_LP_ray_depth: info = (float)state->bounce; break; + case NODE_LP_ray_diffuse: info = (float)state->diffuse_bounce; break; + case NODE_LP_ray_glossy: info = (float)state->glossy_bounce; break; case NODE_LP_ray_transparent: info = (float)state->transparent_bounce; break; case NODE_LP_ray_transmission: info = (float)state->transmission_bounce; break; } diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index 5adf7d34f7f..47209ddfbab 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -188,6 +188,8 @@ typedef enum NodeLightPath { NODE_LP_backfacing, NODE_LP_ray_length, NODE_LP_ray_depth, + NODE_LP_ray_diffuse, + NODE_LP_ray_glossy, NODE_LP_ray_transparent, NODE_LP_ray_transmission, } NodeLightPath; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index c7f37a13fba..1e4a9fd300c 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -3027,6 +3027,8 @@ NODE_DEFINE(LightPathNode) SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray"); SOCKET_OUT_FLOAT(ray_length, "Ray Length"); SOCKET_OUT_FLOAT(ray_depth, "Ray Depth"); + SOCKET_OUT_FLOAT(diffuse_depth, "Diffuse Depth"); + SOCKET_OUT_FLOAT(glossy_depth, "Glossy Depth"); SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth"); SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth"); @@ -3093,6 +3095,16 @@ void LightPathNode::compile(SVMCompiler& compiler) compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, compiler.stack_assign(out)); } + out = output("Diffuse Depth"); + if(!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_diffuse, compiler.stack_assign(out)); + } + + out = output("Glossy Depth"); + if(!out->links.empty()) { + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_glossy, compiler.stack_assign(out)); + } + out = output("Transparent Depth"); if(!out->links.empty()) { compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, compiler.stack_assign(out)); diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.c b/source/blender/nodes/shader/nodes/node_shader_light_path.c index b1001cd3937..052f2a66ec8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_light_path.c +++ b/source/blender/nodes/shader/nodes/node_shader_light_path.c @@ -39,6 +39,8 @@ static bNodeSocketTemplate sh_node_light_path_out[] = { { SOCK_FLOAT, 0, N_("Is Transmission Ray"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 0, N_("Ray Length"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 0, N_("Ray Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 0, N_("Diffuse Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, + { SOCK_FLOAT, 0, N_("Glossy Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 0, N_("Transparent Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { SOCK_FLOAT, 0, N_("Transmission Depth"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, { -1, 0, "" } From 53e7a4a83ce28a25c26b630cad474319069cc1bf Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Jan 2017 06:00:55 +1100 Subject: [PATCH 549/590] Correct asserts, un-hiding when selected is ok --- source/blender/bmesh/intern/bmesh_marking.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index 2231a98a116..7f2032d5f53 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -1248,7 +1248,9 @@ void BM_vert_hide_set(BMVert *v, const bool hide) { /* vert hiding: vert + surrounding edges and faces */ BLI_assert(v->head.htype == BM_VERT); - BLI_assert(!BM_elem_flag_test(v, BM_ELEM_SELECT)); + if (hide) { + BLI_assert(!BM_elem_flag_test(v, BM_ELEM_SELECT)); + } BM_elem_flag_set(v, BM_ELEM_HIDDEN, hide); @@ -1271,7 +1273,9 @@ void BM_vert_hide_set(BMVert *v, const bool hide) void BM_edge_hide_set(BMEdge *e, const bool hide) { BLI_assert(e->head.htype == BM_EDGE); - BLI_assert(!BM_elem_flag_test(e, BM_ELEM_SELECT)); + if (hide) { + BLI_assert(!BM_elem_flag_test(e, BM_ELEM_SELECT)); + } /* edge hiding: faces around the edge */ if (e->l) { @@ -1298,7 +1302,9 @@ void BM_edge_hide_set(BMEdge *e, const bool hide) void BM_face_hide_set(BMFace *f, const bool hide) { BLI_assert(f->head.htype == BM_FACE); - BLI_assert(!BM_elem_flag_test(f, BM_ELEM_SELECT)); + if (hide) { + BLI_assert(!BM_elem_flag_test(f, BM_ELEM_SELECT)); + } BM_elem_flag_set(f, BM_ELEM_HIDDEN, hide); From 2a2ae9c3fa680b84b9fef3c29f10739a5c3da7a5 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 20 Jan 2017 06:06:06 +1100 Subject: [PATCH 550/590] BMesh: remove BM_face_create_ngon_vcloud Instead, add BM_verts_sort_radial_plane and use regular creation API. --- source/blender/bmesh/intern/bmesh_construct.c | 14 +++----------- source/blender/bmesh/intern/bmesh_construct.h | 7 +++---- source/blender/bmesh/operators/bmo_create.c | 6 +++++- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index af7ef01da73..e46a31cb2e9 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -387,15 +387,11 @@ BMFace *BM_face_create_ngon_verts( * * \note Since this is a vcloud there is no direction. */ -BMFace *BM_face_create_ngon_vcloud( - BMesh *bm, BMVert **vert_arr, int len, - const BMFace *f_example, const eBMCreateFlag create_flag) +void BM_verts_sort_radial_plane(BMVert **vert_arr, int len) { struct SortIntByFloat *vang = BLI_array_alloca(vang, len); BMVert **vert_arr_map = BLI_array_alloca(vert_arr_map, len); - BMFace *f; - float totv_inv = 1.0f / (float)len; int i = 0; @@ -472,6 +468,7 @@ BMFace *BM_face_create_ngon_vcloud( for (i = 0; i < len; i++) { vang[i].sort_value = angle_signed_on_axis_v3v3v3_v3(far, cent, vert_arr[i]->co, nor); vang[i].data = i; + vert_arr_map[i] = vert_arr[i]; } /* sort by angle and magic! - we have our ngon */ @@ -479,14 +476,9 @@ BMFace *BM_face_create_ngon_vcloud( /* --- */ - /* create edges and find the winding (if faces are attached to any existing edges) */ for (i = 0; i < len; i++) { - vert_arr_map[i] = vert_arr[vang[i].data]; + vert_arr[i] = vert_arr_map[vang[i].data]; } - - f = BM_face_create_ngon_verts(bm, vert_arr_map, len, f_example, create_flag, true, true); - - return f; } /*************************************************************/ diff --git a/source/blender/bmesh/intern/bmesh_construct.h b/source/blender/bmesh/intern/bmesh_construct.h index 9c6483de42b..a52a17cd2f3 100644 --- a/source/blender/bmesh/intern/bmesh_construct.h +++ b/source/blender/bmesh/intern/bmesh_construct.h @@ -34,6 +34,9 @@ bool BM_verts_from_edges(BMVert **vert_arr, BMEdge **edge_arr, const int len); bool BM_edges_from_verts(BMEdge **edge_arr, BMVert **vert_arr, const int len); void BM_edges_from_verts_ensure(BMesh *bm, BMEdge **edge_arr, BMVert **vert_arr, const int len); +/* sort before creation */ +void BM_verts_sort_radial_plane(BMVert **vert_arr, int len); + BMFace *BM_face_create_quad_tri( BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4, const BMFace *f_example, const eBMCreateFlag create_flag); @@ -50,10 +53,6 @@ BMFace *BM_face_create_ngon_verts( const BMFace *f_example, const eBMCreateFlag create_flag, const bool calc_winding, const bool create_edges); -BMFace *BM_face_create_ngon_vcloud( - BMesh *bm, BMVert **vert_arr, int len, - const BMFace *f_example, const eBMCreateFlag create_flag); - void BM_elem_attrs_copy_ex( BMesh *bm_src, BMesh *bm_dst, const void *ele_src_v, void *ele_dst_v, const char hflag_mask); diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c index 7b8cb36ab59..a980baf8626 100644 --- a/source/blender/bmesh/operators/bmo_create.c +++ b/source/blender/bmesh/operators/bmo_create.c @@ -290,7 +290,11 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) BMFace *f; BMO_iter_as_array(op->slots_in, "geom", BM_VERT, (void **)vert_arr, totv); - f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE); + + BM_verts_sort_radial_plane(vert_arr, totv); + + /* create edges and find the winding (if faces are attached to any existing edges) */ + f = BM_face_create_ngon_verts(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE, true, true); if (f) { BMO_face_flag_enable(bm, f, ELE_OUT); From c91bdaf55b26bf156619f20ae6d9779ced56a7f5 Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 19 Jan 2017 15:55:50 -0500 Subject: [PATCH 551/590] Build dir should be set after the sanity checks Error here is that if do not have 2012 it switch to 2015 but not change the build dir --- make.bat | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/make.bat b/make.bat index f3ec646dc8f..c73101d1430 100644 --- a/make.bat +++ b/make.bat @@ -129,9 +129,6 @@ if "%BUILD_ARCH%"=="x64" ( ) -set BUILD_DIR=%BUILD_DIR%_%TARGET%_%BUILD_ARCH%_vc%BUILD_VS_VER%_%BUILD_TYPE% - - if "%target%"=="Release" ( rem for vc12 check for both cuda 7.5 and 8 if "%CUDA_PATH%"=="" ( @@ -173,7 +170,7 @@ where /Q msbuild if %ERRORLEVEL% NEQ 0 ( if "%BUILD_VS_VER%"=="12" ( rem vs12 not found, try vs14 - echo Visual Studio 2012 not found, trying Visual Studio 2015. + echo Visual Studio 2013 not found, trying Visual Studio 2015. set BUILD_VS_VER=14 set BUILD_VS_YEAR=2015 goto DetectMSVC @@ -184,6 +181,11 @@ if %ERRORLEVEL% NEQ 0 ( goto EOF ) ) + + +set BUILD_DIR=%BUILD_DIR%_%TARGET%_%BUILD_ARCH%_vc%BUILD_VS_VER%_%BUILD_TYPE% + + where /Q cmake if %ERRORLEVEL% NEQ 0 ( echo Error: "CMake" command not in the PATH. From 831cfcfb3dc30ce3a3c8e7251a099ee09c02f34f Mon Sep 17 00:00:00 2001 From: Aaron Date: Thu, 19 Jan 2017 16:16:04 -0500 Subject: [PATCH 552/590] API: Do not show "Created using Sphinx" in the footer I talked to Campbell and he said there is no need for this --- doc/python_api/sphinx_doc_gen.py | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index 3cb98c677c1..e8154f9ea66 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1655,6 +1655,7 @@ def write_sphinx_conf_py(basepath): # not helpful since the source is generated, adds to upload size. fw("html_copy_source = False\n") + fw("html_show_sphinx = False\n") fw("html_split_index = True\n") fw("\n") From 2e3fda2d95b4f0cb04b074c798ed266a41bf2a9d Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Fri, 20 Jan 2017 18:14:28 +1300 Subject: [PATCH 553/590] DopeSheet: Show group colours behind keyframes too Following @AlonDan's feature request and @hjalti's screenshot yesterday, I've decided to implement support for this to make it easier to scan which keyframes correspond with which set of controls, especially when faced with a large wall of keyframes. In retrospect, I should've done this a long time ago! --- .../editors/space_action/action_draw.c | 34 +++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 9fc96e06299..7c9228e1fae 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -170,6 +170,8 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) unsigned char col1a[3], col2a[3]; unsigned char col1b[3], col2b[3]; + const bool show_group_colors = !(saction->flag & SACTION_NODRAWGCOLORS); + /* get theme colors */ UI_GetThemeColor3ubv(TH_BACK, col2); @@ -247,8 +249,36 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) } case ANIMTYPE_GROUP: { - if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22); - else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22); + bActionGroup *agrp = ale->data; + if (show_group_colors && agrp->customCol) { + if (sel) { + unsigned char *cp = agrp->cs.select; + glColor4ub(cp[0], cp[1], cp[2], 0x45); + } + else { + unsigned char *cp = agrp->cs.solid; + glColor4ub(cp[0], cp[1], cp[2], 0x1D); + } + } + else { + if (sel) glColor4ub(col1a[0], col1a[1], col1a[2], 0x22); + else glColor4ub(col2a[0], col2a[1], col2a[2], 0x22); + } + break; + } + case ANIMTYPE_FCURVE: + { + FCurve *fcu = ale->data; + if (show_group_colors && fcu->grp && fcu->grp->customCol) { + unsigned char *cp = fcu->grp->cs.active; + + if (sel) glColor4ub(cp[0], cp[1], cp[2], 0x65); + else glColor4ub(cp[0], cp[1], cp[2], 0x0B); + } + else { + if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); + else glColor4ub(col2[0], col2[1], col2[2], 0x22); + } break; } default: From 05ff32bd250d1ad0382fd02ab99af9e514d6f835 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Fri, 20 Jan 2017 10:50:55 +0100 Subject: [PATCH 554/590] Fix compile error (-Werror=float-conversion). --- intern/cycles/render/object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index 8b8b988b969..c592b62829e 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -166,7 +166,7 @@ void Object::apply_transform(bool apply_to_motion) float3 c0 = transform_get_column(&tfm, 0); float3 c1 = transform_get_column(&tfm, 1); float3 c2 = transform_get_column(&tfm, 2); - float scalar = pow(fabsf(dot(cross(c0, c1), c2)), 1.0f/3.0f); + float scalar = powf(fabsf(dot(cross(c0, c1), c2)), 1.0f/3.0f); /* apply transform to curve keys */ for(size_t i = 0; i < mesh->curve_keys.size(); i++) { From ff1b850081b067ea0b989bdc62c2d85f36e23524 Mon Sep 17 00:00:00 2001 From: Thomas Dinges Date: Fri, 20 Jan 2017 10:58:03 +0100 Subject: [PATCH 555/590] Fix T50460. Greying out issue with Cycles culling options. --- intern/cycles/blender/addon/ui.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 925f923dd41..53bd208c0e7 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -787,10 +787,13 @@ class CyclesObject_PT_cycles_settings(CyclesButtonsPanel, Panel): col = layout.column() col.label(text="Performance:") row = col.row() - row.active = scene.render.use_simplify and cscene.use_camera_cull - row.prop(cob, "use_camera_cull") - row.active = scene.render.use_simplify and cscene.use_distance_cull - row.prop(cob, "use_distance_cull") + sub = row.row() + sub.active = scene.render.use_simplify and cscene.use_camera_cull + sub.prop(cob, "use_camera_cull") + + sub = row.row() + sub.active = scene.render.use_simplify and cscene.use_distance_cull + sub.prop(cob, "use_distance_cull") class CYCLES_OT_use_shading_nodes(Operator): From 254fbcdd7b638943acc033c081ca729954f2b5a0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 20 Jan 2017 11:55:48 +0100 Subject: [PATCH 556/590] Cycles: Fix compilation error on with older GCC Hopefully it works on all platforms now. --- intern/cycles/util/util_math.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index d0062646414..2b81c8c498a 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -22,6 +22,11 @@ * Basic math functions on scalar and vector types. This header is used by * both the kernel code when compiled as C++, and other C++ non-kernel code. */ +#ifndef __KERNEL_GPU__ +# include +#endif + + #ifndef __KERNEL_OPENCL__ #include @@ -97,6 +102,9 @@ ccl_device_inline float fminf(float a, float b) #ifndef __KERNEL_GPU__ +using std::isfinite; +using std::isnan; + ccl_device_inline int abs(int x) { return (x > 0)? x: -x; From 811e6c2d32c5cd84112c6ee64af6ecb482186d91 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 16 Jan 2017 18:59:22 +0100 Subject: [PATCH 557/590] Cycles: Cleanup, delete trailing whitespace --- intern/cycles/render/mesh.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index df4327d021a..5f0b2ef50bc 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -394,7 +394,7 @@ void Mesh::compute_bounds() if(use_motion_blur && attr) { size_t steps_size = verts.size() * (motion_steps - 1); float3 *vert_steps = attr->data_float3(); - + for(size_t i = 0; i < steps_size; i++) bnds.grow(vert_steps[i]); } @@ -403,7 +403,7 @@ void Mesh::compute_bounds() if(use_motion_blur && curve_attr) { size_t steps_size = curve_keys.size() * (motion_steps - 1); float3 *key_steps = curve_attr->data_float3(); - + for(size_t i = 0; i < steps_size; i++) bnds.grow(key_steps[i]); } @@ -417,11 +417,11 @@ void Mesh::compute_bounds() for(size_t i = 0; i < curve_keys_size; i++) bnds.grow_safe(curve_keys[i], curve_radius[i]); - + if(use_motion_blur && attr) { size_t steps_size = verts.size() * (motion_steps - 1); float3 *vert_steps = attr->data_float3(); - + for(size_t i = 0; i < steps_size; i++) bnds.grow_safe(vert_steps[i]); } @@ -429,7 +429,7 @@ void Mesh::compute_bounds() if(use_motion_blur && curve_attr) { size_t steps_size = curve_keys.size() * (motion_steps - 1); float3 *key_steps = curve_attr->data_float3(); - + for(size_t i = 0; i < steps_size; i++) bnds.grow_safe(key_steps[i]); } @@ -464,7 +464,7 @@ void Mesh::add_face_normals() /* don't compute if already there */ if(attributes.find(ATTR_STD_FACE_NORMAL)) return; - + /* get attributes */ Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL); float3 *fN = attr_fN->data_float3(); @@ -1002,7 +1002,7 @@ void MeshManager::update_svm_attributes(Device *device, DeviceScene *dscene, Sce if(attr_map_stride == 0) return; - + /* create attribute map */ uint4 *attr_map = dscene->attributes_map.resize(attr_map_stride*scene->objects.size()); memset(attr_map, 0, dscene->attributes_map.size()*sizeof(uint)); @@ -1946,14 +1946,14 @@ bool Mesh::need_attribute(Scene *scene, AttributeStandard std) { if(std == ATTR_STD_NONE) return false; - + if(scene->need_global_attribute(std)) return true; foreach(Shader *shader, used_shaders) if(shader->attributes.find(std)) return true; - + return false; } @@ -1965,9 +1965,8 @@ bool Mesh::need_attribute(Scene * /*scene*/, ustring name) foreach(Shader *shader, used_shaders) if(shader->attributes.find(name)) return true; - + return false; } CCL_NAMESPACE_END - From 461214508c26110de615e0797cb63bf0df02bdca Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 16 Jan 2017 19:56:40 +0100 Subject: [PATCH 558/590] Cycles: Add utility function to fetch motion triangle when on CPU side --- intern/cycles/render/mesh.cpp | 48 +++++++++++++++++++++++++++++++++++ intern/cycles/render/mesh.h | 19 +++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 5f0b2ef50bc..25d220562ea 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -49,6 +49,54 @@ void Mesh::Triangle::bounds_grow(const float3 *verts, BoundBox& bounds) const bounds.grow(verts[v[2]]); } +void Mesh::Triangle::motion_verts(const float3 *verts, + const float3 *vert_steps, + size_t num_verts, + size_t num_steps, + float time, + float3 r_verts[3]) const +{ + /* Figure out which steps we need to fetch and their interpolation factor. */ + const size_t max_step = num_steps - 1; + const size_t step = min((int)(time * max_step), max_step - 1); + const float t = time*max_step - step; + /* Fetch vertex coordinates. */ + float3 curr_verts[3]; + float3 next_verts[3]; + verts_for_step(verts, vert_steps, num_verts, num_steps, step, curr_verts); + verts_for_step(verts, vert_steps, num_verts, num_steps, step + 1, next_verts); + /* Interpolate between steps. */ + r_verts[0] = (1.0f - t)*curr_verts[0] + t*next_verts[0]; + r_verts[1] = (1.0f - t)*curr_verts[1] + t*next_verts[1]; + r_verts[2] = (1.0f - t)*curr_verts[2] + t*next_verts[2]; +} + +void Mesh::Triangle::verts_for_step(const float3 *verts, + const float3 *vert_steps, + size_t num_verts, + size_t num_steps, + size_t step, + float3 r_verts[3]) const +{ + const size_t center_step = ((num_steps - 1) / 2); + if(step == center_step) { + /* Center step: regular vertex location. */ + r_verts[0] = verts[v[0]]; + r_verts[1] = verts[v[1]]; + r_verts[2] = verts[v[2]]; + } + else { + /* Center step not stored in the attribute array array. */ + if(step > center_step) { + step--; + } + size_t offset = step * num_verts; + r_verts[0] = vert_steps[offset + v[0]]; + r_verts[1] = vert_steps[offset + v[1]]; + r_verts[2] = vert_steps[offset + v[2]]; + } +} + /* Curve */ void Mesh::Curve::bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index c0310f45840..33d8acc9c8b 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -31,6 +31,7 @@ CCL_NAMESPACE_BEGIN +class Attribute; class BVH; class Device; class DeviceScene; @@ -54,11 +55,27 @@ public: int v[3]; void bounds_grow(const float3 *verts, BoundBox& bounds) const; + + void motion_verts(const float3 *verts, + const float3 *vert_steps, + size_t num_verts, + size_t num_steps, + float time, + float3 r_verts[3]) const; + + void verts_for_step(const float3 *verts, + const float3 *vert_steps, + size_t num_verts, + size_t num_steps, + size_t step, + float3 r_verts[3]) const; }; Triangle get_triangle(size_t i) const { - Triangle tri = {{triangles[i*3 + 0], triangles[i*3 + 1], triangles[i*3 + 2]}}; + Triangle tri = {{triangles[i*3 + 0], + triangles[i*3 + 1], + triangles[i*3 + 2]}}; return tri; } From 938ec3a743bccb20551dcfc9419ce889d2a79909 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 16 Jan 2017 20:08:19 +0100 Subject: [PATCH 559/590] Cycles: Cleanup, comments --- intern/cycles/kernel/geom/geom_motion_curve.h | 8 ++++---- intern/cycles/kernel/geom/geom_motion_triangle.h | 2 +- intern/cycles/render/mesh.cpp | 14 ++++++++++++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/intern/cycles/kernel/geom/geom_motion_curve.h b/intern/cycles/kernel/geom/geom_motion_curve.h index 80b33fad68b..dc1388b6643 100644 --- a/intern/cycles/kernel/geom/geom_motion_curve.h +++ b/intern/cycles/kernel/geom/geom_motion_curve.h @@ -50,12 +50,12 @@ ccl_device_inline int find_attribute_curve_motion(KernelGlobals *kg, int object, ccl_device_inline void motion_curve_keys_for_step(KernelGlobals *kg, int offset, int numkeys, int numsteps, int step, int k0, int k1, float4 keys[2]) { if(step == numsteps) { - /* center step: regular vertex location */ + /* center step: regular key location */ keys[0] = kernel_tex_fetch(__curve_keys, k0); keys[1] = kernel_tex_fetch(__curve_keys, k1); } else { - /* center step not stored in this array */ + /* center step is not stored in this array */ if(step > numsteps) step--; @@ -97,14 +97,14 @@ ccl_device_inline void motion_curve_keys(KernelGlobals *kg, int object, int prim ccl_device_inline void motion_cardinal_curve_keys_for_step(KernelGlobals *kg, int offset, int numkeys, int numsteps, int step, int k0, int k1, int k2, int k3, float4 keys[4]) { if(step == numsteps) { - /* center step: regular vertex location */ + /* center step: regular key location */ keys[0] = kernel_tex_fetch(__curve_keys, k0); keys[1] = kernel_tex_fetch(__curve_keys, k1); keys[2] = kernel_tex_fetch(__curve_keys, k2); keys[3] = kernel_tex_fetch(__curve_keys, k3); } else { - /* center step not store in this array */ + /* center step is not stored in this array */ if(step > numsteps) step--; diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h index 538c332c63a..4fc68a2fb4d 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -76,7 +76,7 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, uint4 normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z)); } else { - /* center step not stored in this array */ + /* center step is not stored in this array */ if(step > numsteps) step--; diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 25d220562ea..496ab1ed2ca 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -63,8 +63,18 @@ void Mesh::Triangle::motion_verts(const float3 *verts, /* Fetch vertex coordinates. */ float3 curr_verts[3]; float3 next_verts[3]; - verts_for_step(verts, vert_steps, num_verts, num_steps, step, curr_verts); - verts_for_step(verts, vert_steps, num_verts, num_steps, step + 1, next_verts); + verts_for_step(verts, + vert_steps, + num_verts, + num_steps, + step, + curr_verts); + verts_for_step(verts, + vert_steps, + num_verts, + num_steps, + step + 1, + next_verts); /* Interpolate between steps. */ r_verts[0] = (1.0f - t)*curr_verts[0] + t*next_verts[0]; r_verts[1] = (1.0f - t)*curr_verts[1] + t*next_verts[1]; From 20eb1fe3c1c7a312e0c7ca201ff7c89aa97814e0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 16 Jan 2017 20:26:17 +0100 Subject: [PATCH 560/590] Cycles: Add utility function to fetch motion keys while on CPU side --- intern/cycles/render/mesh.cpp | 165 ++++++++++++++++++++++++++++++++++ intern/cycles/render/mesh.h | 32 +++++++ 2 files changed, 197 insertions(+) diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 496ab1ed2ca..488ec271ee9 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -162,6 +162,171 @@ void Mesh::Curve::bounds_grow(const int k, bounds.grow(upper, mr); } +void Mesh::Curve::motion_keys(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_steps, + float time, + size_t k0, size_t k1, + float4 r_keys[2]) const +{ + /* Figure out which steps we need to fetch and their interpolation factor. */ + const size_t max_step = num_steps - 1; + const size_t step = min((int)(time * max_step), max_step - 1); + const float t = time*max_step - step; + /* Fetch vertex coordinates. */ + float4 curr_keys[2]; + float4 next_keys[2]; + keys_for_step(curve_keys, + curve_radius, + key_steps, + num_steps, + step, + k0, k1, + curr_keys); + keys_for_step(curve_keys, + curve_radius, + key_steps, + num_steps, + step + 1, + k0, k1, + next_keys); + /* Interpolate between steps. */ + r_keys[0] = (1.0f - t)*curr_keys[0] + t*next_keys[0]; + r_keys[1] = (1.0f - t)*curr_keys[1] + t*next_keys[1]; +} + +void Mesh::Curve::cardinal_motion_keys(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_steps, + float time, + size_t k0, size_t k1, + size_t k2, size_t k3, + float4 r_keys[4]) const +{ + /* Figure out which steps we need to fetch and their interpolation factor. */ + const size_t max_step = num_steps - 1; + const size_t step = min((int)(time * max_step), max_step - 1); + const float t = time*max_step - step; + /* Fetch vertex coordinates. */ + float4 curr_keys[4]; + float4 next_keys[4]; + cardinal_keys_for_step(curve_keys, + curve_radius, + key_steps, + num_steps, + step, + k0, k1, k2, k3, + curr_keys); + cardinal_keys_for_step(curve_keys, + curve_radius, + key_steps, + num_steps, + step + 1, + k0, k1, k2, k3, + next_keys); + /* Interpolate between steps. */ + r_keys[0] = (1.0f - t)*curr_keys[0] + t*next_keys[0]; + r_keys[1] = (1.0f - t)*curr_keys[1] + t*next_keys[1]; + r_keys[2] = (1.0f - t)*curr_keys[2] + t*next_keys[2]; + r_keys[3] = (1.0f - t)*curr_keys[3] + t*next_keys[3]; +} + +void Mesh::Curve::keys_for_step(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_steps, + size_t step, + size_t k0, size_t k1, + float4 r_keys[2]) const +{ + const size_t center_step = ((num_steps - 1) / 2); + if(step == center_step) { + /* Center step: regular key location. */ + /* TODO(sergey): Consider adding make_float4(float3, float) + * function. + */ + r_keys[0] = make_float4(curve_keys[first_key + k0].x, + curve_keys[first_key + k0].y, + curve_keys[first_key + k0].z, + curve_radius[k0]); + r_keys[1] = make_float4(curve_keys[first_key + k1].x, + curve_keys[first_key + k1].y, + curve_keys[first_key + k1].z, + curve_radius[k1]); + } + else { + /* Center step is not stored in this array. */ + if(step > center_step) { + step--; + } + const size_t offset = first_key + step * num_keys; + r_keys[0] = make_float4(key_steps[offset + k0].x, + key_steps[offset + k0].y, + key_steps[offset + k0].z, + curve_radius[k0]); + r_keys[1] = make_float4(key_steps[offset + k1].x, + key_steps[offset + k1].y, + key_steps[offset + k1].z, + curve_radius[k1]); + } +} + +void Mesh::Curve::cardinal_keys_for_step(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_steps, + size_t step, + size_t k0, size_t k1, + size_t k2, size_t k3, + float4 r_keys[4]) const +{ + const size_t center_step = ((num_steps - 1) / 2); + if(step == center_step) { + /* Center step: regular key location. */ + r_keys[0] = make_float4(curve_keys[first_key + k0].x, + curve_keys[first_key + k0].y, + curve_keys[first_key + k0].z, + curve_radius[k0]); + r_keys[1] = make_float4(curve_keys[first_key + k1].x, + curve_keys[first_key + k1].y, + curve_keys[first_key + k1].z, + curve_radius[k1]); + r_keys[2] = make_float4(curve_keys[first_key + k2].x, + curve_keys[first_key + k2].y, + curve_keys[first_key + k2].z, + curve_radius[k2]); + r_keys[3] = make_float4(curve_keys[first_key + k3].x, + curve_keys[first_key + k3].y, + curve_keys[first_key + k3].z, + curve_radius[k3]); + } + else { + /* Center step is not stored in this array. */ + if(step > center_step) { + step--; + } + const size_t offset = first_key + step * num_keys; + r_keys[0] = make_float4(key_steps[offset + k0].x, + key_steps[offset + k0].y, + key_steps[offset + k0].z, + curve_radius[k0]); + r_keys[1] = make_float4(key_steps[offset + k1].x, + key_steps[offset + k1].y, + key_steps[offset + k1].z, + curve_radius[k1]); + r_keys[2] = make_float4(key_steps[offset + k2].x, + key_steps[offset + k2].y, + key_steps[offset + k2].z, + curve_radius[k2]); + r_keys[3] = make_float4(key_steps[offset + k3].x, + key_steps[offset + k3].y, + key_steps[offset + k3].z, + curve_radius[k3]); + } +} + /* SubdFace */ float3 Mesh::SubdFace::normal(const Mesh *mesh) const diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index 33d8acc9c8b..b29a2561a0e 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -100,6 +100,38 @@ public: const float *curve_radius, const Transform& aligned_space, BoundBox& bounds) const; + + void motion_keys(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_steps, + float time, + size_t k0, size_t k1, + float4 r_keys[2]) const; + void cardinal_motion_keys(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_steps, + float time, + size_t k0, size_t k1, + size_t k2, size_t k3, + float4 r_keys[4]) const; + + void keys_for_step(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_steps, + size_t step, + size_t k0, size_t k1, + float4 r_keys[2]) const; + void cardinal_keys_for_step(const float3 *curve_keys, + const float *curve_radius, + const float3 *key_steps, + size_t num_steps, + size_t step, + size_t k0, size_t k1, + size_t k2, size_t k3, + float4 r_keys[4]) const; }; Curve get_curve(size_t i) const From ebc695ef2cb2bd410b34e1926c33ab134bbed0b6 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 16 Jan 2017 20:27:05 +0100 Subject: [PATCH 561/590] Cycles: Cleanup, better variable name --- intern/cycles/bvh/bvh_build.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 8cf1495b33d..f0651db6c9d 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -130,12 +130,12 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, /* motion triangles */ if(attr_mP) { - const size_t mesh_size = mesh->verts.size(); + const size_t num_verts = mesh->verts.size(); const size_t num_steps = mesh->motion_steps - 1; const float3 *vert_steps = attr_mP->data_float3(); for(size_t step = 0; step < num_steps; step++) { - t.bounds_grow(vert_steps + step*mesh_size, bounds); + t.bounds_grow(vert_steps + step*num_verts, bounds); } type = PRIMITIVE_MOTION_TRIANGLE; @@ -167,12 +167,12 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, /* motion curve */ if(curve_attr_mP) { - const size_t mesh_size = mesh->curve_keys.size(); + const size_t num_keys = mesh->curve_keys.size(); const size_t num_steps = mesh->motion_steps - 1; const float3 *key_steps = curve_attr_mP->data_float3(); for(size_t step = 0; step < num_steps; step++) { - curve.bounds_grow(k, key_steps + step*mesh_size, curve_radius, bounds); + curve.bounds_grow(k, key_steps + step*num_keys, curve_radius, bounds); } type = PRIMITIVE_MOTION_CURVE; From 14d343a8f989fcde0433beb2936b8cbeddb3b816 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Jan 2017 10:48:56 +0100 Subject: [PATCH 562/590] Cycles: Move motion triangle intersection functions to own file Mimics how regular triangles are working and makes it more clear where the stuff is located in the kernel. Needed to have some forward declarations because of the current placement of things in the kernel. --- intern/cycles/kernel/CMakeLists.txt | 1 + intern/cycles/kernel/geom/geom.h | 1 + .../cycles/kernel/geom/geom_motion_triangle.h | 240 ++------------- .../geom/geom_motion_triangle_intersect.h | 280 ++++++++++++++++++ 4 files changed, 302 insertions(+), 220 deletions(-) create mode 100644 intern/cycles/kernel/geom/geom_motion_triangle_intersect.h diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 56bcafbce38..e06534d0a91 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -164,6 +164,7 @@ set(SRC_GEOM_HEADERS geom/geom_curve.h geom/geom_motion_curve.h geom/geom_motion_triangle.h + geom/geom_motion_triangle_intersect.h geom/geom_object.h geom/geom_patch.h geom/geom_primitive.h diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h index 24ced934c8b..68eaa467a99 100644 --- a/intern/cycles/kernel/geom/geom.h +++ b/intern/cycles/kernel/geom/geom.h @@ -23,6 +23,7 @@ #include "geom_subd_triangle.h" #include "geom_triangle_intersect.h" #include "geom_motion_triangle.h" +#include "geom_motion_triangle_intersect.h" #include "geom_motion_curve.h" #include "geom_curve.h" #include "geom_volume.h" diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h index 4fc68a2fb4d..fe0cd0c2582 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -27,6 +27,26 @@ CCL_NAMESPACE_BEGIN +/* TODO(sergey): Find a proper place for that. */ +ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, + ShaderData *sd, + const Intersection *isect, + const Ray *ray, + float3 verts[3]); + +#ifdef __SUBSURFACE__ +# if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86)) +ccl_device_noinline +# else +ccl_device_inline +# endif +float3 motion_triangle_refine_subsurface(KernelGlobals *kg, + ShaderData *sd, + const Intersection *isect, + const Ray *ray, + float3 verts[3]); +#endif /* __SUBSURFACE__ */ + /* Time interpolation of vertex positions and normals */ ccl_device_inline int find_attribute_motion(KernelGlobals *kg, int object, uint id, AttributeElement *elem) @@ -117,121 +137,6 @@ ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, i verts[2] = (1.0f - t)*verts[2] + t*next_verts[2]; } -/* Refine triangle intersection to more precise hit point. For rays that travel - * far the precision is often not so good, this reintersects the primitive from - * a closer distance. */ - -ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float3 verts[3]) -{ - float3 P = ray->P; - float3 D = ray->D; - float t = isect->t; - -#ifdef __INTERSECTION_REFINE__ - if(isect->object != OBJECT_NONE) { - if(UNLIKELY(t == 0.0f)) { - return P; - } -# ifdef __OBJECT_MOTION__ - Transform tfm = ccl_fetch(sd, ob_itfm); -# else - Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); -# endif - - P = transform_point(&tfm, P); - D = transform_direction(&tfm, D*t); - D = normalize_len(D, &t); - } - - P = P + D*t; - - /* compute refined intersection distance */ - const float3 e1 = verts[0] - verts[2]; - const float3 e2 = verts[1] - verts[2]; - const float3 s1 = cross(D, e2); - - const float invdivisor = 1.0f/dot(s1, e1); - const float3 d = P - verts[2]; - const float3 s2 = cross(d, e1); - float rt = dot(e2, s2)*invdivisor; - - /* compute refined position */ - P = P + D*rt; - - if(isect->object != OBJECT_NONE) { -# ifdef __OBJECT_MOTION__ - Transform tfm = ccl_fetch(sd, ob_tfm); -# else - Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); -# endif - - P = transform_point(&tfm, P); - } - - return P; -#else - return P + D*t; -#endif -} - -/* Same as above, except that isect->t is assumed to be in object space for instancing */ - -#ifdef __SUBSURFACE__ -# if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86)) -ccl_device_noinline -# else -ccl_device_inline -# endif -float3 motion_triangle_refine_subsurface(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, float3 verts[3]) -{ - float3 P = ray->P; - float3 D = ray->D; - float t = isect->t; - -# ifdef __INTERSECTION_REFINE__ - if(isect->object != OBJECT_NONE) { -# ifdef __OBJECT_MOTION__ - Transform tfm = ccl_fetch(sd, ob_itfm); -# else - Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM); -# endif - - P = transform_point(&tfm, P); - D = transform_direction(&tfm, D); - D = normalize(D); - } - - P = P + D*t; - - /* compute refined intersection distance */ - const float3 e1 = verts[0] - verts[2]; - const float3 e2 = verts[1] - verts[2]; - const float3 s1 = cross(D, e2); - - const float invdivisor = 1.0f/dot(s1, e1); - const float3 d = P - verts[2]; - const float3 s2 = cross(d, e1); - float rt = dot(e2, s2)*invdivisor; - - P = P + D*rt; - - if(isect->object != OBJECT_NONE) { -# ifdef __OBJECT_MOTION__ - Transform tfm = ccl_fetch(sd, ob_tfm); -# else - Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM); -# endif - - P = transform_point(&tfm, P); - } - - return P; -# else - return P + D*t; -# endif -} -#endif - /* Setup of motion triangle specific parts of ShaderData, moved into this one * function to more easily share computation of interpolated positions and * normals */ @@ -319,110 +224,5 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderD } } -/* Ray intersection. We simply compute the vertex positions at the given ray - * time and do a ray intersection with the resulting triangle */ - -ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg, Intersection *isect, - float3 P, float3 dir, float time, uint visibility, int object, int prim_addr) -{ - /* primitive index for vertex location lookup */ - int prim = kernel_tex_fetch(__prim_index, prim_addr); - int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; - - /* get vertex locations for intersection */ - float3 verts[3]; - motion_triangle_vertices(kg, fobject, prim, time, verts); - - /* ray-triangle intersection, unoptimized */ - float t, u, v; - - if(ray_triangle_intersect_uv(P, dir, isect->t, verts[2], verts[0], verts[1], &u, &v, &t)) { -#ifdef __VISIBILITY_FLAG__ - /* visibility flag test. we do it here under the assumption - * that most triangles are culled by node flags */ - if(kernel_tex_fetch(__prim_visibility, prim_addr) & visibility) -#endif - { - isect->t = t; - isect->u = u; - isect->v = v; - isect->prim = prim_addr; - isect->object = object; - isect->type = PRIMITIVE_MOTION_TRIANGLE; - - return true; - } - } - - return false; -} - -/* Special ray intersection routines for subsurface scattering. In that case we - * only want to intersect with primitives in the same object, and if case of - * multiple hits we pick a single random primitive as the intersection point. */ - -#ifdef __SUBSURFACE__ -ccl_device_inline void motion_triangle_intersect_subsurface( - KernelGlobals *kg, - SubsurfaceIntersection *ss_isect, - float3 P, - float3 dir, - float time, - int object, - int prim_addr, - float tmax, - uint *lcg_state, - int max_hits) -{ - /* primitive index for vertex location lookup */ - int prim = kernel_tex_fetch(__prim_index, prim_addr); - int fobject = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; - - /* get vertex locations for intersection */ - float3 verts[3]; - motion_triangle_vertices(kg, fobject, prim, time, verts); - - /* ray-triangle intersection, unoptimized */ - float t, u, v; - - if(ray_triangle_intersect_uv(P, dir, tmax, verts[2], verts[0], verts[1], &u, &v, &t)) { - for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { - if(ss_isect->hits[i].t == t) { - return; - } - } - - ss_isect->num_hits++; - - int hit; - - if(ss_isect->num_hits <= max_hits) { - hit = ss_isect->num_hits - 1; - } - else { - /* reservoir sampling: if we are at the maximum number of - * hits, randomly replace element or skip it */ - hit = lcg_step_uint(lcg_state) % ss_isect->num_hits; - - if(hit >= max_hits) - return; - } - - /* record intersection */ - Intersection *isect = &ss_isect->hits[hit]; - isect->t = t; - isect->u = u; - isect->v = v; - isect->prim = prim_addr; - isect->object = object; - isect->type = PRIMITIVE_MOTION_TRIANGLE; - - /* Record geometric normal. */ - ss_isect->Ng[hit] = normalize(cross(verts[1] - verts[0], - verts[2] - verts[0])); - } -} -#endif - CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h b/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h new file mode 100644 index 00000000000..d57d74ea882 --- /dev/null +++ b/intern/cycles/kernel/geom/geom_motion_triangle_intersect.h @@ -0,0 +1,280 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Motion Triangle Primitive + * + * These are stored as regular triangles, plus extra positions and normals at + * times other than the frame center. Computing the triangle vertex positions + * or normals at a given ray time is a matter of interpolation of the two steps + * between which the ray time lies. + * + * The extra positions and normals are stored as ATTR_STD_MOTION_VERTEX_POSITION + * and ATTR_STD_MOTION_VERTEX_NORMAL mesh attributes. + */ + +CCL_NAMESPACE_BEGIN + +/* Refine triangle intersection to more precise hit point. For rays that travel + * far the precision is often not so good, this reintersects the primitive from + * a closer distance. + */ + +ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, + ShaderData *sd, + const Intersection *isect, + const Ray *ray, + float3 verts[3]) +{ + float3 P = ray->P; + float3 D = ray->D; + float t = isect->t; + +#ifdef __INTERSECTION_REFINE__ + if(isect->object != OBJECT_NONE) { + if(UNLIKELY(t == 0.0f)) { + return P; + } +# ifdef __OBJECT_MOTION__ + Transform tfm = ccl_fetch(sd, ob_itfm); +# else + Transform tfm = object_fetch_transform(kg, + isect->object, + OBJECT_INVERSE_TRANSFORM); +# endif + + P = transform_point(&tfm, P); + D = transform_direction(&tfm, D*t); + D = normalize_len(D, &t); + } + + P = P + D*t; + + /* Compute refined intersection distance. */ + const float3 e1 = verts[0] - verts[2]; + const float3 e2 = verts[1] - verts[2]; + const float3 s1 = cross(D, e2); + + const float invdivisor = 1.0f/dot(s1, e1); + const float3 d = P - verts[2]; + const float3 s2 = cross(d, e1); + float rt = dot(e2, s2)*invdivisor; + + /* Compute refined position. */ + P = P + D*rt; + + if(isect->object != OBJECT_NONE) { +# ifdef __OBJECT_MOTION__ + Transform tfm = ccl_fetch(sd, ob_tfm); +# else + Transform tfm = object_fetch_transform(kg, + isect->object, + OBJECT_TRANSFORM); +# endif + + P = transform_point(&tfm, P); + } + + return P; +#else + return P + D*t; +#endif +} + +/* Same as above, except that isect->t is assumed to be in object space + * for instancing. + */ + +#ifdef __SUBSURFACE__ +# if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86)) +ccl_device_noinline +# else +ccl_device_inline +# endif +float3 motion_triangle_refine_subsurface(KernelGlobals *kg, + ShaderData *sd, + const Intersection *isect, + const Ray *ray, + float3 verts[3]) +{ + float3 P = ray->P; + float3 D = ray->D; + float t = isect->t; + +# ifdef __INTERSECTION_REFINE__ + if(isect->object != OBJECT_NONE) { +# ifdef __OBJECT_MOTION__ + Transform tfm = ccl_fetch(sd, ob_itfm); +# else + Transform tfm = object_fetch_transform(kg, + isect->object, + OBJECT_INVERSE_TRANSFORM); +# endif + + P = transform_point(&tfm, P); + D = transform_direction(&tfm, D); + D = normalize(D); + } + + P = P + D*t; + + /* compute refined intersection distance */ + const float3 e1 = verts[0] - verts[2]; + const float3 e2 = verts[1] - verts[2]; + const float3 s1 = cross(D, e2); + + const float invdivisor = 1.0f/dot(s1, e1); + const float3 d = P - verts[2]; + const float3 s2 = cross(d, e1); + float rt = dot(e2, s2)*invdivisor; + + P = P + D*rt; + + if(isect->object != OBJECT_NONE) { +# ifdef __OBJECT_MOTION__ + Transform tfm = ccl_fetch(sd, ob_tfm); +# else + Transform tfm = object_fetch_transform(kg, + isect->object, + OBJECT_TRANSFORM); +# endif + + P = transform_point(&tfm, P); + } + + return P; +# else /* __INTERSECTION_REFINE__ */ + return P + D*t; +# endif /* __INTERSECTION_REFINE__ */ +} +#endif /* __SUBSURFACE__ */ + + +/* Ray intersection. We simply compute the vertex positions at the given ray + * time and do a ray intersection with the resulting triangle. + */ + +ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg, + Intersection *isect, + float3 P, + float3 dir, + float time, + uint visibility, + int object, + int prim_addr) +{ + /* Primitive index for vertex location lookup. */ + int prim = kernel_tex_fetch(__prim_index, prim_addr); + int fobject = (object == OBJECT_NONE) + ? kernel_tex_fetch(__prim_object, prim_addr) + : object; + /* Get vertex locations for intersection. */ + float3 verts[3]; + motion_triangle_vertices(kg, fobject, prim, time, verts); + /* Ray-triangle intersection, unoptimized. */ + float t, u, v; + if(ray_triangle_intersect_uv(P, + dir, + isect->t, + verts[2], verts[0], verts[1], + &u, &v, &t)) + { +#ifdef __VISIBILITY_FLAG__ + /* Visibility flag test. we do it here under the assumption + * that most triangles are culled by node flags. + */ + if(kernel_tex_fetch(__prim_visibility, prim_addr) & visibility) +#endif + { + isect->t = t; + isect->u = u; + isect->v = v; + isect->prim = prim_addr; + isect->object = object; + isect->type = PRIMITIVE_MOTION_TRIANGLE; + return true; + } + } + return false; +} + +/* Special ray intersection routines for subsurface scattering. In that case we + * only want to intersect with primitives in the same object, and if case of + * multiple hits we pick a single random primitive as the intersection point. + */ +#ifdef __SUBSURFACE__ +ccl_device_inline void motion_triangle_intersect_subsurface( + KernelGlobals *kg, + SubsurfaceIntersection *ss_isect, + float3 P, + float3 dir, + float time, + int object, + int prim_addr, + float tmax, + uint *lcg_state, + int max_hits) +{ + /* Primitive index for vertex location lookup. */ + int prim = kernel_tex_fetch(__prim_index, prim_addr); + int fobject = (object == OBJECT_NONE) + ? kernel_tex_fetch(__prim_object, prim_addr) + : object; + /* Get vertex locations for intersection. */ + float3 verts[3]; + motion_triangle_vertices(kg, fobject, prim, time, verts); + /* Ray-triangle intersection, unoptimized. */ + float t, u, v; + if(ray_triangle_intersect_uv(P, + dir, + tmax, + verts[2], verts[0], verts[1], + &u, &v, &t)) + { + for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) { + if(ss_isect->hits[i].t == t) { + return; + } + } + ss_isect->num_hits++; + int hit; + if(ss_isect->num_hits <= max_hits) { + hit = ss_isect->num_hits - 1; + } + else { + /* Reservoir sampling: if we are at the maximum number of + * hits, randomly replace element or skip it. + */ + hit = lcg_step_uint(lcg_state) % ss_isect->num_hits; + + if(hit >= max_hits) + return; + } + /* Record intersection. */ + Intersection *isect = &ss_isect->hits[hit]; + isect->t = t; + isect->u = u; + isect->v = v; + isect->prim = prim_addr; + isect->object = object; + isect->type = PRIMITIVE_MOTION_TRIANGLE; + /* Record geometric normal. */ + ss_isect->Ng[hit] = normalize(cross(verts[1] - verts[0], + verts[2] - verts[0])); + } +} +#endif /* __SUBSURFACE__ */ + +CCL_NAMESPACE_END From 26cdc64a7fb03b2a732947ea71a3575e6087b0b4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Jan 2017 10:58:04 +0100 Subject: [PATCH 563/590] Cycles: Split motion triangle file once again, avoids annoying forward declarations --- intern/cycles/kernel/CMakeLists.txt | 1 + intern/cycles/kernel/geom/geom.h | 1 + .../cycles/kernel/geom/geom_motion_triangle.h | 108 --------------- .../kernel/geom/geom_motion_triangle_shader.h | 123 ++++++++++++++++++ 4 files changed, 125 insertions(+), 108 deletions(-) create mode 100644 intern/cycles/kernel/geom/geom_motion_triangle_shader.h diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index e06534d0a91..29e0f44841e 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -165,6 +165,7 @@ set(SRC_GEOM_HEADERS geom/geom_motion_curve.h geom/geom_motion_triangle.h geom/geom_motion_triangle_intersect.h + geom/geom_motion_triangle_shader.h geom/geom_object.h geom/geom_patch.h geom/geom_primitive.h diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h index 68eaa467a99..6838e26c242 100644 --- a/intern/cycles/kernel/geom/geom.h +++ b/intern/cycles/kernel/geom/geom.h @@ -24,6 +24,7 @@ #include "geom_triangle_intersect.h" #include "geom_motion_triangle.h" #include "geom_motion_triangle_intersect.h" +#include "geom_motion_triangle_shader.h" #include "geom_motion_curve.h" #include "geom_curve.h" #include "geom_volume.h" diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h index fe0cd0c2582..4e84aa97776 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -27,26 +27,6 @@ CCL_NAMESPACE_BEGIN -/* TODO(sergey): Find a proper place for that. */ -ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg, - ShaderData *sd, - const Intersection *isect, - const Ray *ray, - float3 verts[3]); - -#ifdef __SUBSURFACE__ -# if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86)) -ccl_device_noinline -# else -ccl_device_inline -# endif -float3 motion_triangle_refine_subsurface(KernelGlobals *kg, - ShaderData *sd, - const Intersection *isect, - const Ray *ray, - float3 verts[3]); -#endif /* __SUBSURFACE__ */ - /* Time interpolation of vertex positions and normals */ ccl_device_inline int find_attribute_motion(KernelGlobals *kg, int object, uint id, AttributeElement *elem) @@ -137,92 +117,4 @@ ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, i verts[2] = (1.0f - t)*verts[2] + t*next_verts[2]; } -/* Setup of motion triangle specific parts of ShaderData, moved into this one - * function to more easily share computation of interpolated positions and - * normals */ - -/* return 3 triangle vertex normals */ -ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderData *sd, const Intersection *isect, const Ray *ray, bool subsurface) -{ - /* get shader */ - ccl_fetch(sd, shader) = kernel_tex_fetch(__tri_shader, ccl_fetch(sd, prim)); - - /* get motion info */ - int numsteps, numverts; - object_motion_info(kg, ccl_fetch(sd, object), &numsteps, &numverts, NULL); - - /* figure out which steps we need to fetch and their interpolation factor */ - int maxstep = numsteps*2; - int step = min((int)(ccl_fetch(sd, time)*maxstep), maxstep-1); - float t = ccl_fetch(sd, time)*maxstep - step; - - /* find attribute */ - AttributeElement elem; - int offset = find_attribute_motion(kg, ccl_fetch(sd, object), ATTR_STD_MOTION_VERTEX_POSITION, &elem); - kernel_assert(offset != ATTR_STD_NOT_FOUND); - - /* fetch vertex coordinates */ - float3 verts[3], next_verts[3]; - uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); - - motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts); - motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts); - - /* interpolate between steps */ - verts[0] = (1.0f - t)*verts[0] + t*next_verts[0]; - verts[1] = (1.0f - t)*verts[1] + t*next_verts[1]; - verts[2] = (1.0f - t)*verts[2] + t*next_verts[2]; - - /* compute refined position */ -#ifdef __SUBSURFACE__ - if(!subsurface) -#endif - ccl_fetch(sd, P) = motion_triangle_refine(kg, sd, isect, ray, verts); -#ifdef __SUBSURFACE__ - else - ccl_fetch(sd, P) = motion_triangle_refine_subsurface(kg, sd, isect, ray, verts); -#endif - - /* compute face normal */ - float3 Ng; - if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED) - Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0])); - else - Ng = normalize(cross(verts[1] - verts[0], verts[2] - verts[0])); - - ccl_fetch(sd, Ng) = Ng; - ccl_fetch(sd, N) = Ng; - - /* compute derivatives of P w.r.t. uv */ -#ifdef __DPDU__ - ccl_fetch(sd, dPdu) = (verts[0] - verts[2]); - ccl_fetch(sd, dPdv) = (verts[1] - verts[2]); -#endif - - /* compute smooth normal */ - if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) { - /* find attribute */ - AttributeElement elem; - int offset = find_attribute_motion(kg, ccl_fetch(sd, object), ATTR_STD_MOTION_VERTEX_NORMAL, &elem); - kernel_assert(offset != ATTR_STD_NOT_FOUND); - - /* fetch vertex coordinates */ - float3 normals[3], next_normals[3]; - motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals); - motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_normals); - - /* interpolate between steps */ - normals[0] = (1.0f - t)*normals[0] + t*next_normals[0]; - normals[1] = (1.0f - t)*normals[1] + t*next_normals[1]; - normals[2] = (1.0f - t)*normals[2] + t*next_normals[2]; - - /* interpolate between vertices */ - float u = ccl_fetch(sd, u); - float v = ccl_fetch(sd, v); - float w = 1.0f - u - v; - ccl_fetch(sd, N) = (u*normals[0] + v*normals[1] + w*normals[2]); - } -} - CCL_NAMESPACE_END - diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h new file mode 100644 index 00000000000..c5dbc6a2f52 --- /dev/null +++ b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h @@ -0,0 +1,123 @@ +/* + * Copyright 2011-2016 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Motion Triangle Primitive + * + * These are stored as regular triangles, plus extra positions and normals at + * times other than the frame center. Computing the triangle vertex positions + * or normals at a given ray time is a matter of interpolation of the two steps + * between which the ray time lies. + * + * The extra positions and normals are stored as ATTR_STD_MOTION_VERTEX_POSITION + * and ATTR_STD_MOTION_VERTEX_NORMAL mesh attributes. + */ + +CCL_NAMESPACE_BEGIN + +/* Setup of motion triangle specific parts of ShaderData, moved into this one + * function to more easily share computation of interpolated positions and + * normals */ + +/* return 3 triangle vertex normals */ +ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, + ShaderData *sd, const + Intersection *isect, + const Ray *ray, + bool subsurface) +{ + /* Get shader. */ + ccl_fetch(sd, shader) = kernel_tex_fetch(__tri_shader, ccl_fetch(sd, prim)); + /* Get motion info. */ + /* TODO(sergey): This logic is really similar to motion_triangle_vertices(), + * can we de-duplicate something here? + */ + int numsteps, numverts; + object_motion_info(kg, ccl_fetch(sd, object), &numsteps, &numverts, NULL); + /* Figure out which steps we need to fetch and their interpolation factor. */ + int maxstep = numsteps*2; + int step = min((int)(ccl_fetch(sd, time)*maxstep), maxstep-1); + float t = ccl_fetch(sd, time)*maxstep - step; + /* Find attribute. */ + AttributeElement elem; + int offset = find_attribute_motion(kg, ccl_fetch(sd, object), + ATTR_STD_MOTION_VERTEX_POSITION, + &elem); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + /* Fetch vertex coordinates. */ + float3 verts[3], next_verts[3]; + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts); + motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts); + /* Interpolate between steps. */ + verts[0] = (1.0f - t)*verts[0] + t*next_verts[0]; + verts[1] = (1.0f - t)*verts[1] + t*next_verts[1]; + verts[2] = (1.0f - t)*verts[2] + t*next_verts[2]; + /* Compute refined position. */ +#ifdef __SUBSURFACE__ + if(subsurface) { + ccl_fetch(sd, P) = motion_triangle_refine_subsurface(kg, + sd, + isect, + ray, + verts); + } + else +#endif /* __SUBSURFACE__*/ + { + ccl_fetch(sd, P) = motion_triangle_refine(kg, sd, isect, ray, verts); + } + /* Compute face normal. */ + float3 Ng; + if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED) { + Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0])); + } + else { + Ng = normalize(cross(verts[1] - verts[0], verts[2] - verts[0])); + } + ccl_fetch(sd, Ng) = Ng; + ccl_fetch(sd, N) = Ng; + /* Compute derivatives of P w.r.t. uv. */ +#ifdef __DPDU__ + ccl_fetch(sd, dPdu) = (verts[0] - verts[2]); + ccl_fetch(sd, dPdv) = (verts[1] - verts[2]); +#endif + /* Compute smooth normal. */ + if(ccl_fetch(sd, shader) & SHADER_SMOOTH_NORMAL) { + /* Find attribute. */ + AttributeElement elem; + int offset = find_attribute_motion(kg, + ccl_fetch(sd, object), + ATTR_STD_MOTION_VERTEX_NORMAL, + &elem); + kernel_assert(offset != ATTR_STD_NOT_FOUND); + /* Fetch vertex coordinates. */ + float3 normals[3], next_normals[3]; + motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step, normals); + motion_triangle_normals_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_normals); + /* Interpolate between steps. */ + normals[0] = (1.0f - t)*normals[0] + t*next_normals[0]; + normals[1] = (1.0f - t)*normals[1] + t*next_normals[1]; + normals[2] = (1.0f - t)*normals[2] + t*next_normals[2]; + /* Interpolate between vertices. */ + float u = ccl_fetch(sd, u); + float v = ccl_fetch(sd, v); + float w = 1.0f - u - v; + ccl_fetch(sd, N) = (u*normals[0] + v*normals[1] + w*normals[2]); + } +} + +CCL_NAMESPACE_END + From 6f900c383a4f8415331eb56a3e2b69c0cec30702 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Jan 2017 12:12:14 +0100 Subject: [PATCH 564/590] Cycles: Cleanup, trailing whitespace --- intern/cycles/bvh/bvh_build.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index f0651db6c9d..a045481e50f 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -203,7 +203,7 @@ static size_t count_curve_segments(Mesh *mesh) for(size_t i = 0; i < num_curves; i++) num += mesh->get_curve(i).num_keys - 1; - + return num; } @@ -374,7 +374,7 @@ void BVHBuild::progress_update() { if(time_dt() - progress_start_time < 0.25) return; - + double progress_start = (double)progress_count/(double)progress_total; double duplicates = (double)(progress_total - progress_original_total)/(double)progress_total; @@ -382,7 +382,7 @@ void BVHBuild::progress_update() progress_start * 100.0, duplicates * 100.0); progress.set_substatus(msg); - progress_start_time = time_dt(); + progress_start_time = time_dt(); } void BVHBuild::thread_build_node(InnerNode *inner, @@ -700,8 +700,8 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, } else { int mid = num/2; - BVHNode *leaf0 = create_object_leaf_nodes(ref, start, mid); - BVHNode *leaf1 = create_object_leaf_nodes(ref+mid, start+mid, num-mid); + BVHNode *leaf0 = create_object_leaf_nodes(ref, start, mid); + BVHNode *leaf1 = create_object_leaf_nodes(ref+mid, start+mid, num-mid); BoundBox bounds = BoundBox::empty; bounds.grow(leaf0->m_bounds); @@ -958,7 +958,7 @@ void BVHBuild::rotate(BVHNode *node, int max_depth) /* nothing to rotate if we reached a leaf node. */ if(node->is_leaf() || max_depth < 0) return; - + InnerNode *parent = (InnerNode*)node; /* rotate all children first */ From d50d370755beba0d23356acc301a180afa87e676 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Jan 2017 14:23:29 +0100 Subject: [PATCH 565/590] Cycles: Add utility function to calculate curve boundbox from given 4 keys Also fixed some issues with motion keys calculation: - Clamp lower and upper limits of curves so we can safely call those functions for the very first and very last curve segment. - Fixed wrong indexing for the curve radius array. - Fixed wrong motion attribute offset calculation. --- intern/cycles/render/mesh.cpp | 64 +++++++++++++++++++++++++++-------- intern/cycles/render/mesh.h | 5 +++ 2 files changed, 55 insertions(+), 14 deletions(-) diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 488ec271ee9..1522a2dc18b 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -162,9 +162,32 @@ void Mesh::Curve::bounds_grow(const int k, bounds.grow(upper, mr); } +void Mesh::Curve::bounds_grow(float4 keys[4], BoundBox& bounds) const +{ + float3 P[4] = { + float4_to_float3(keys[0]), + float4_to_float3(keys[1]), + float4_to_float3(keys[2]), + float4_to_float3(keys[3]), + }; + + float3 lower; + float3 upper; + + curvebounds(&lower.x, &upper.x, P, 0); + curvebounds(&lower.y, &upper.y, P, 1); + curvebounds(&lower.z, &upper.z, P, 2); + + float mr = max(keys[1].w, keys[2].w); + + bounds.grow(lower, mr); + bounds.grow(upper, mr); +} + void Mesh::Curve::motion_keys(const float3 *curve_keys, const float *curve_radius, const float3 *key_steps, + size_t num_curve_keys, size_t num_steps, float time, size_t k0, size_t k1, @@ -180,6 +203,7 @@ void Mesh::Curve::motion_keys(const float3 *curve_keys, keys_for_step(curve_keys, curve_radius, key_steps, + num_curve_keys, num_steps, step, k0, k1, @@ -187,6 +211,7 @@ void Mesh::Curve::motion_keys(const float3 *curve_keys, keys_for_step(curve_keys, curve_radius, key_steps, + num_curve_keys, num_steps, step + 1, k0, k1, @@ -199,6 +224,7 @@ void Mesh::Curve::motion_keys(const float3 *curve_keys, void Mesh::Curve::cardinal_motion_keys(const float3 *curve_keys, const float *curve_radius, const float3 *key_steps, + size_t num_curve_keys, size_t num_steps, float time, size_t k0, size_t k1, @@ -215,6 +241,7 @@ void Mesh::Curve::cardinal_motion_keys(const float3 *curve_keys, cardinal_keys_for_step(curve_keys, curve_radius, key_steps, + num_curve_keys, num_steps, step, k0, k1, k2, k3, @@ -222,6 +249,7 @@ void Mesh::Curve::cardinal_motion_keys(const float3 *curve_keys, cardinal_keys_for_step(curve_keys, curve_radius, key_steps, + num_curve_keys, num_steps, step + 1, k0, k1, k2, k3, @@ -236,11 +264,14 @@ void Mesh::Curve::cardinal_motion_keys(const float3 *curve_keys, void Mesh::Curve::keys_for_step(const float3 *curve_keys, const float *curve_radius, const float3 *key_steps, + size_t num_curve_keys, size_t num_steps, size_t step, size_t k0, size_t k1, float4 r_keys[2]) const { + k0 = max(k0, 0); + k1 = min(k1, num_keys - 1); const size_t center_step = ((num_steps - 1) / 2); if(step == center_step) { /* Center step: regular key location. */ @@ -250,80 +281,83 @@ void Mesh::Curve::keys_for_step(const float3 *curve_keys, r_keys[0] = make_float4(curve_keys[first_key + k0].x, curve_keys[first_key + k0].y, curve_keys[first_key + k0].z, - curve_radius[k0]); + curve_radius[first_key + k0]); r_keys[1] = make_float4(curve_keys[first_key + k1].x, curve_keys[first_key + k1].y, curve_keys[first_key + k1].z, - curve_radius[k1]); + curve_radius[first_key + k1]); } else { /* Center step is not stored in this array. */ if(step > center_step) { step--; } - const size_t offset = first_key + step * num_keys; + const size_t offset = first_key + step * num_curve_keys; r_keys[0] = make_float4(key_steps[offset + k0].x, key_steps[offset + k0].y, key_steps[offset + k0].z, - curve_radius[k0]); + curve_radius[first_key + k0]); r_keys[1] = make_float4(key_steps[offset + k1].x, key_steps[offset + k1].y, key_steps[offset + k1].z, - curve_radius[k1]); + curve_radius[first_key + k1]); } } void Mesh::Curve::cardinal_keys_for_step(const float3 *curve_keys, const float *curve_radius, const float3 *key_steps, + size_t num_curve_keys, size_t num_steps, size_t step, size_t k0, size_t k1, size_t k2, size_t k3, float4 r_keys[4]) const { + k0 = max(k0, 0); + k3 = min(k3, num_keys - 1); const size_t center_step = ((num_steps - 1) / 2); if(step == center_step) { /* Center step: regular key location. */ r_keys[0] = make_float4(curve_keys[first_key + k0].x, curve_keys[first_key + k0].y, curve_keys[first_key + k0].z, - curve_radius[k0]); + curve_radius[first_key + k0]); r_keys[1] = make_float4(curve_keys[first_key + k1].x, curve_keys[first_key + k1].y, curve_keys[first_key + k1].z, - curve_radius[k1]); + curve_radius[first_key + k1]); r_keys[2] = make_float4(curve_keys[first_key + k2].x, curve_keys[first_key + k2].y, curve_keys[first_key + k2].z, - curve_radius[k2]); + curve_radius[first_key + k2]); r_keys[3] = make_float4(curve_keys[first_key + k3].x, curve_keys[first_key + k3].y, curve_keys[first_key + k3].z, - curve_radius[k3]); + curve_radius[first_key + k3]); } else { /* Center step is not stored in this array. */ if(step > center_step) { step--; } - const size_t offset = first_key + step * num_keys; + const size_t offset = first_key + step * num_curve_keys; r_keys[0] = make_float4(key_steps[offset + k0].x, key_steps[offset + k0].y, key_steps[offset + k0].z, - curve_radius[k0]); + curve_radius[first_key + k0]); r_keys[1] = make_float4(key_steps[offset + k1].x, key_steps[offset + k1].y, key_steps[offset + k1].z, - curve_radius[k1]); + curve_radius[first_key + k1]); r_keys[2] = make_float4(key_steps[offset + k2].x, key_steps[offset + k2].y, key_steps[offset + k2].z, - curve_radius[k2]); + curve_radius[first_key + k2]); r_keys[3] = make_float4(key_steps[offset + k3].x, key_steps[offset + k3].y, key_steps[offset + k3].z, - curve_radius[k3]); + curve_radius[first_key + k3]); } } @@ -1019,6 +1053,7 @@ void Mesh::compute_bvh(DeviceScene *dscene, bparams.use_qbvh = params->use_qbvh; bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && params->use_bvh_unaligned_nodes; + bparams.num_motion_curve_steps = params->num_bvh_motion_curve_steps; delete bvh; bvh = BVH::create(bparams, objects); @@ -1787,6 +1822,7 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * bparams.use_spatial_split = scene->params.use_bvh_spatial_split; bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && scene->params.use_bvh_unaligned_nodes; + bparams.num_motion_curve_steps = scene->params.num_bvh_motion_curve_steps; delete bvh; bvh = BVH::create(bparams, scene->objects); diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index b29a2561a0e..5f33e30eac2 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -95,6 +95,7 @@ public: const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const; + void bounds_grow(float4 keys[4], BoundBox& bounds) const; void bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, @@ -104,6 +105,7 @@ public: void motion_keys(const float3 *curve_keys, const float *curve_radius, const float3 *key_steps, + size_t num_curve_keys, size_t num_steps, float time, size_t k0, size_t k1, @@ -111,6 +113,7 @@ public: void cardinal_motion_keys(const float3 *curve_keys, const float *curve_radius, const float3 *key_steps, + size_t num_curve_keys, size_t num_steps, float time, size_t k0, size_t k1, @@ -120,6 +123,7 @@ public: void keys_for_step(const float3 *curve_keys, const float *curve_radius, const float3 *key_steps, + size_t num_curve_keys, size_t num_steps, size_t step, size_t k0, size_t k1, @@ -127,6 +131,7 @@ public: void cardinal_keys_for_step(const float3 *curve_keys, const float *curve_radius, const float3 *key_steps, + size_t num_curve_keys, size_t num_steps, size_t step, size_t k0, size_t k1, From 5298853e95057942251262d649fcd41b5769f52c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Jan 2017 14:37:32 +0100 Subject: [PATCH 566/590] Cycles: Add option to split curve motion primitives by time steps The idea is to create several smaller BVH nodes for each of the motion curve primitives. This acts as a forced spatial split for the single primitive. This gives up render time speedup of motion blurred hair in the cost of extra memory usage. The numbers goes as: BVH Steps Render time (sec) Memory usage (MB) 0 258 191 1 123 278 2 69 453 3 43 627 Scene used for the tests is the agent's hair from one of the barber shop scenes. Currently it's only limited to scenes without spatial split enabled, since the spatial split builder requires some changes to work properly with motion steps coordinates. --- intern/cycles/blender/addon/properties.py | 6 ++ intern/cycles/blender/addon/ui.py | 4 + intern/cycles/blender/blender_sync.cpp | 1 + intern/cycles/bvh/bvh_build.cpp | 113 +++++++++++++++++----- intern/cycles/bvh/bvh_params.h | 10 ++ intern/cycles/render/scene.h | 3 + 6 files changed, 115 insertions(+), 22 deletions(-) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 3616b13e751..802b9b76c5d 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -528,6 +528,12 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Use special type BVH optimized for hair (uses more ram but renders faster)", default=True, ) + cls.debug_bvh_time_steps = IntProperty( + name="BVH Time Steps", + description="Split BVH primitives by this number of time steps to speed up render time in cost of memory", + default=0, + min=0, max=16, + ) cls.tile_order = EnumProperty( name="Tile Order", description="Tile order for rendering", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 53bd208c0e7..d26ab73fac3 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -432,6 +432,10 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): col.prop(cscene, "debug_use_spatial_splits") col.prop(cscene, "debug_use_hair_bvh") + row = col.row() + row.active = not cscene.debug_use_spatial_splits + row.prop(cscene, "debug_bvh_time_steps") + class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel): bl_label = "Layer" diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 38b2ce19e8a..a9b7d7d3583 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -498,6 +498,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits"); params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh"); + params.num_bvh_motion_curve_steps = RNA_int_get(&cscene, "debug_bvh_time_steps"); if(background && params.shadingsystem != SHADINGSYSTEM_OSL) params.persistent_data = r.use_persistent_data(); diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index a045481e50f..4d684e51c1b 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -158,32 +158,101 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, size_t num_curves = mesh->num_curves(); for(uint j = 0; j < num_curves; j++) { const Mesh::Curve curve = mesh->get_curve(j); - PrimitiveType type = PRIMITIVE_CURVE; const float *curve_radius = &mesh->curve_radius[0]; - for(int k = 0; k < curve.num_keys - 1; k++) { - BoundBox bounds = BoundBox::empty; - curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds); - - /* motion curve */ - if(curve_attr_mP) { - const size_t num_keys = mesh->curve_keys.size(); - const size_t num_steps = mesh->motion_steps - 1; - const float3 *key_steps = curve_attr_mP->data_float3(); - - for(size_t step = 0; step < num_steps; step++) { - curve.bounds_grow(k, key_steps + step*num_keys, curve_radius, bounds); + if(curve_attr_mP == NULL) { + /* Really simple logic for static hair. */ + BoundBox bounds = BoundBox::empty; + curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds); + if(bounds.valid()) { + int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE, k); + references.push_back(BVHReference(bounds, j, i, packed_type)); + root.grow(bounds); + center.grow(bounds.center2()); } - - type = PRIMITIVE_MOTION_CURVE; } - - if(bounds.valid()) { - int packed_type = PRIMITIVE_PACK_SEGMENT(type, k); - - references.push_back(BVHReference(bounds, j, i, packed_type)); - root.grow(bounds); - center.grow(bounds.center2()); + else if(params.num_motion_curve_steps == 0 || params.use_spatial_split) { + /* Simple case of motion curves: single node for the while + * shutter time. Lowest memory usage but less optimal + * rendering. + */ + /* TODO(sergey): Support motion steps for spatially split BVH. */ + BoundBox bounds = BoundBox::empty; + curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds); + const size_t num_keys = mesh->curve_keys.size(); + const size_t num_steps = mesh->motion_steps; + const float3 *key_steps = curve_attr_mP->data_float3(); + for(size_t step = 0; step < num_steps - 1; step++) { + curve.bounds_grow(k, + key_steps + step*num_keys, + curve_radius, + bounds); + } + if(bounds.valid()) { + int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k); + references.push_back(BVHReference(bounds, + j, + i, + packed_type)); + root.grow(bounds); + center.grow(bounds.center2()); + } + } + else { + /* Motion curves, trace optimized case: we split curve keys + * primitives into separate nodes for each of the time steps. + * This way we minimize overlap of neighbor curve primitives. + */ + const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1; + const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1); + const size_t num_steps = mesh->motion_steps; + const float3 *curve_keys = &mesh->curve_keys[0]; + const float3 *key_steps = curve_attr_mP->data_float3(); + const size_t num_keys = mesh->curve_keys.size(); + /* Calculate bounding box of the previous time step. + * Will be reused later to avoid duplicated work on + * calculating BVH time step boundbox. + */ + float4 prev_keys[4]; + curve.cardinal_motion_keys(curve_keys, + curve_radius, + key_steps, + num_keys, + num_steps, + 0.0f, + k - 1, k, k + 1, k + 2, + prev_keys); + BoundBox prev_bounds = BoundBox::empty; + curve.bounds_grow(prev_keys, prev_bounds); + for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) { + const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1; + float4 curr_keys[4]; + curve.cardinal_motion_keys(curve_keys, + curve_radius, + key_steps, + num_keys, + num_steps, + curr_time, + k - 1, k, k + 1, k + 2, + curr_keys); + BoundBox curr_bounds = BoundBox::empty; + curve.bounds_grow(curr_keys, curr_bounds); + BoundBox bounds = prev_bounds; + bounds.grow(curr_bounds); + if(bounds.valid()) { + int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k); + references.push_back(BVHReference(bounds, + j, + i, + packed_type)); + root.grow(bounds); + center.grow(bounds.center2()); + } + /* Current time boundbox becomes previous one for the + * next time step. + */ + prev_bounds = curr_bounds; + } } } } diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index 6d426475737..1521fe9b5e4 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -61,6 +61,14 @@ public: */ bool use_unaligned_nodes; + /* Split time range to this number of steps and create leaf node for each + * of this time steps. + * + * Speeds up rendering of motion curve primitives in the cost of higher + * memory usage. + */ + int num_motion_curve_steps; + /* fixed parameters */ enum { MAX_DEPTH = 64, @@ -91,6 +99,8 @@ public: use_unaligned_nodes = false; primitive_mask = PRIMITIVE_ALL; + + num_motion_curve_steps = 0; } /* SAH costs */ diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index df9363cc768..948697dd136 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -143,6 +143,7 @@ public: } bvh_type; bool use_bvh_spatial_split; bool use_bvh_unaligned_nodes; + int num_bvh_motion_curve_steps; bool use_qbvh; bool persistent_data; int texture_limit; @@ -153,6 +154,7 @@ public: bvh_type = BVH_DYNAMIC; use_bvh_spatial_split = false; use_bvh_unaligned_nodes = true; + num_bvh_motion_curve_steps = 0; use_qbvh = false; persistent_data = false; texture_limit = 0; @@ -163,6 +165,7 @@ public: && bvh_type == params.bvh_type && use_bvh_spatial_split == params.use_bvh_spatial_split && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes + && num_bvh_motion_curve_steps == params.num_bvh_motion_curve_steps && use_qbvh == params.use_qbvh && persistent_data == params.persistent_data && texture_limit == params.texture_limit); } From c4890cd354bdba341be5b5fb9cf3724ee294634b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Jan 2017 15:13:01 +0100 Subject: [PATCH 567/590] Cycles: Add option to split triangle motion primitives by time steps Similar to the previous commit, the statistics goes as: BVH Steps Render time (sec) Memory usage (MB) 0 46 260 1 27 373 2 18 598 3 15 826 Scene used for the tests is the agent's body from one of the barber shop scenes (no textures or anything, just a diffuse material). Once again this is limited to regular (non-spatial split) BVH, Support of spatial split to this feature will come later. --- intern/cycles/blender/blender_sync.cpp | 2 +- intern/cycles/bvh/bvh_build.cpp | 107 ++++++++++++++++++++----- intern/cycles/bvh/bvh_params.h | 3 + intern/cycles/render/mesh.cpp | 6 +- intern/cycles/render/scene.h | 6 +- 5 files changed, 100 insertions(+), 24 deletions(-) diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index a9b7d7d3583..f8f2303ec76 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -498,7 +498,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits"); params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh"); - params.num_bvh_motion_curve_steps = RNA_int_get(&cscene, "debug_bvh_time_steps"); + params.num_bvh_time_steps = RNA_int_get(&cscene, "debug_bvh_time_steps"); if(background && params.shadingsystem != SHADINGSYSTEM_OSL) params.persistent_data = r.use_persistent_data(); diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 4d684e51c1b..21b8b980405 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -120,31 +120,101 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, if(mesh->has_motion_blur()) attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - size_t num_triangles = mesh->num_triangles(); + const size_t num_triangles = mesh->num_triangles(); for(uint j = 0; j < num_triangles; j++) { Mesh::Triangle t = mesh->get_triangle(j); - BoundBox bounds = BoundBox::empty; - PrimitiveType type = PRIMITIVE_TRIANGLE; - - t.bounds_grow(&mesh->verts[0], bounds); - - /* motion triangles */ - if(attr_mP) { + const float3 *verts = &mesh->verts[0]; + if(attr_mP == NULL) { + BoundBox bounds = BoundBox::empty; + t.bounds_grow(verts, bounds); + if(bounds.valid()) { + references.push_back(BVHReference(bounds, + j, + i, + PRIMITIVE_TRIANGLE)); + root.grow(bounds); + center.grow(bounds.center2()); + } + } + else if(params.num_motion_triangle_steps == 0 || params.use_spatial_split) { + /* Motion triangles, simple case: single node for the whole + * primitive. Lowest memory footprint and faster BVH build but + * least optimal ray-tracing. + */ + /* TODO(sergey): Support motion steps for spatially split BVH. */ const size_t num_verts = mesh->verts.size(); - const size_t num_steps = mesh->motion_steps - 1; + const size_t num_steps = mesh->motion_steps; const float3 *vert_steps = attr_mP->data_float3(); - - for(size_t step = 0; step < num_steps; step++) { + BoundBox bounds = BoundBox::empty; + t.bounds_grow(verts, bounds); + for(size_t step = 0; step < num_steps - 1; step++) { t.bounds_grow(vert_steps + step*num_verts, bounds); } - - type = PRIMITIVE_MOTION_TRIANGLE; + if(bounds.valid()) { + references.push_back( + BVHReference(bounds, + j, + i, + PRIMITIVE_MOTION_TRIANGLE)); + root.grow(bounds); + center.grow(bounds.center2()); + } } - - if(bounds.valid()) { - references.push_back(BVHReference(bounds, j, i, type)); - root.grow(bounds); - center.grow(bounds.center2()); + else { + /* Motion triangles, trace optimized case: we split triangle + * primitives into separate nodes for each of the time steps. + * This way we minimize overlap of neighbor curve primitives. + */ + const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1; + const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1); + const size_t num_verts = mesh->verts.size(); + const size_t num_steps = mesh->motion_steps; + const float3 *vert_steps = attr_mP->data_float3(); + /* Calculate bounding box of the previous time step. + * Will be reused later to avoid duplicated work on + * calculating BVH time step boundbox. + */ + float3 prev_verts[3]; + t.motion_verts(verts, + vert_steps, + num_verts, + num_steps, + 0.0f, + prev_verts); + BoundBox prev_bounds = BoundBox::empty; + prev_bounds.grow(prev_verts[0]); + prev_bounds.grow(prev_verts[1]); + prev_bounds.grow(prev_verts[2]); + /* Create all primitive time steps, */ + for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) { + const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1; + float3 curr_verts[3]; + t.motion_verts(verts, + vert_steps, + num_verts, + num_steps, + curr_time, + curr_verts); + BoundBox curr_bounds = BoundBox::empty; + curr_bounds.grow(curr_verts[0]); + curr_bounds.grow(curr_verts[1]); + curr_bounds.grow(curr_verts[2]); + BoundBox bounds = prev_bounds; + bounds.grow(curr_bounds); + if(bounds.valid()) { + references.push_back( + BVHReference(bounds, + j, + i, + PRIMITIVE_MOTION_TRIANGLE)); + root.grow(bounds); + center.grow(bounds.center2()); + } + /* Current time boundbox becomes previous one for the + * next time step. + */ + prev_bounds = curr_bounds; + } } } } @@ -224,6 +294,7 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, prev_keys); BoundBox prev_bounds = BoundBox::empty; curve.bounds_grow(prev_keys, prev_bounds); + /* Create all primitive time steps, */ for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) { const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1; float4 curr_keys[4]; diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index 1521fe9b5e4..233c7adacba 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -69,6 +69,9 @@ public: */ int num_motion_curve_steps; + /* Same as above, but for triangle primitives. */ + int num_motion_triangle_steps; + /* fixed parameters */ enum { MAX_DEPTH = 64, diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 1522a2dc18b..c42b32919d4 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -1053,7 +1053,8 @@ void Mesh::compute_bvh(DeviceScene *dscene, bparams.use_qbvh = params->use_qbvh; bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && params->use_bvh_unaligned_nodes; - bparams.num_motion_curve_steps = params->num_bvh_motion_curve_steps; + bparams.num_motion_triangle_steps = params->num_bvh_time_steps; + bparams.num_motion_curve_steps = params->num_bvh_time_steps; delete bvh; bvh = BVH::create(bparams, objects); @@ -1822,7 +1823,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * bparams.use_spatial_split = scene->params.use_bvh_spatial_split; bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && scene->params.use_bvh_unaligned_nodes; - bparams.num_motion_curve_steps = scene->params.num_bvh_motion_curve_steps; + bparams.num_motion_triangle_steps = scene->params.num_bvh_time_steps; + bparams.num_motion_curve_steps = scene->params.num_bvh_time_steps; delete bvh; bvh = BVH::create(bparams, scene->objects); diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index 948697dd136..8768682043f 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -143,7 +143,7 @@ public: } bvh_type; bool use_bvh_spatial_split; bool use_bvh_unaligned_nodes; - int num_bvh_motion_curve_steps; + int num_bvh_time_steps; bool use_qbvh; bool persistent_data; int texture_limit; @@ -154,7 +154,7 @@ public: bvh_type = BVH_DYNAMIC; use_bvh_spatial_split = false; use_bvh_unaligned_nodes = true; - num_bvh_motion_curve_steps = 0; + num_bvh_time_steps = 0; use_qbvh = false; persistent_data = false; texture_limit = 0; @@ -165,7 +165,7 @@ public: && bvh_type == params.bvh_type && use_bvh_spatial_split == params.use_bvh_spatial_split && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes - && num_bvh_motion_curve_steps == params.num_bvh_motion_curve_steps + && num_bvh_time_steps == params.num_bvh_time_steps && use_qbvh == params.use_qbvh && persistent_data == params.persistent_data && texture_limit == params.texture_limit); } From 1ad04c7d65b0e9e3efa8563005e91d9aa419fec5 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Jan 2017 15:34:18 +0100 Subject: [PATCH 568/590] Cycles: Store time in BVH nodes This way we can stop traversing BVH node early on. Gives about 2-2.5x times render time improvement with 3 BVH steps. Hopefully this gives no measurable performance loss for scenes with single BVH step. Traversal is currently only implemented for QBVH, meaning old CPUs and GPU do not benefit from this change. --- intern/cycles/bvh/bvh.cpp | 17 ++++++++++++ intern/cycles/bvh/bvh.h | 4 +++ intern/cycles/bvh/bvh_build.cpp | 31 +++++++++++++++++++--- intern/cycles/bvh/bvh_node.cpp | 13 +++++++++ intern/cycles/bvh/bvh_node.h | 7 ++++- intern/cycles/bvh/bvh_params.h | 16 +++++++++-- intern/cycles/kernel/bvh/qbvh_shadow_all.h | 10 +++++-- intern/cycles/kernel/bvh/qbvh_traversal.h | 4 +++ 8 files changed, 93 insertions(+), 9 deletions(-) diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index 4851de5b481..874a4246d1d 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -845,6 +845,8 @@ void QBVH::pack_aligned_inner(const BVHStackEntry& e, bounds, child, e.node->m_visibility, + e.node->m_time_from, + e.node->m_time_to, num); } @@ -852,12 +854,17 @@ void QBVH::pack_aligned_node(int idx, const BoundBox *bounds, const int *child, const uint visibility, + const float time_from, + const float time_to, const int num) { float4 data[BVH_QNODE_SIZE]; memset(data, 0, sizeof(data)); data[0].x = __uint_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED); + data[0].y = time_from; + data[0].z = time_to; + for(int i = 0; i < num; i++) { float3 bb_min = bounds[i].min; float3 bb_max = bounds[i].max; @@ -908,6 +915,8 @@ void QBVH::pack_unaligned_inner(const BVHStackEntry& e, bounds, child, e.node->m_visibility, + e.node->m_time_from, + e.node->m_time_to, num); } @@ -916,12 +925,16 @@ void QBVH::pack_unaligned_node(int idx, const BoundBox *bounds, const int *child, const uint visibility, + const float time_from, + const float time_to, const int num) { float4 data[BVH_UNALIGNED_QNODE_SIZE]; memset(data, 0, sizeof(data)); data[0].x = __uint_as_float(visibility | PATH_RAY_NODE_UNALIGNED); + data[0].y = time_from; + data[0].z = time_to; for(int i = 0; i < num; i++) { Transform space = BVHUnaligned::compute_node_transform( @@ -1207,6 +1220,8 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) child_bbox, &c[0], visibility, + 0.0f, + 1.0f, 4); } else { @@ -1214,6 +1229,8 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) child_bbox, &c[0], visibility, + 0.0f, + 1.0f, 4); } } diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h index f8fb3b568ca..35f4d305883 100644 --- a/intern/cycles/bvh/bvh.h +++ b/intern/cycles/bvh/bvh.h @@ -175,6 +175,8 @@ protected: const BoundBox *bounds, const int *child, const uint visibility, + const float time_from, + const float time_to, const int num); void pack_unaligned_inner(const BVHStackEntry& e, @@ -185,6 +187,8 @@ protected: const BoundBox *bounds, const int *child, const uint visibility, + const float time_from, + const float time_to, const int num); /* refit */ diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 21b8b980405..4abd686cc6e 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -202,11 +202,14 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, BoundBox bounds = prev_bounds; bounds.grow(curr_bounds); if(bounds.valid()) { + const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1; references.push_back( BVHReference(bounds, j, i, - PRIMITIVE_MOTION_TRIANGLE)); + PRIMITIVE_MOTION_TRIANGLE, + prev_time, + curr_time)); root.grow(bounds); center.grow(bounds.center2()); } @@ -311,11 +314,14 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, BoundBox bounds = prev_bounds; bounds.grow(curr_bounds); if(bounds.valid()) { + const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1; int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k); references.push_back(BVHReference(bounds, j, i, - packed_type)); + packed_type, + prev_time, + curr_time)); root.grow(bounds); center.grow(bounds.center2()); } @@ -487,6 +493,7 @@ BVHNode* BVHBuild::run() else { /*rotate(rootnode, 4, 5);*/ rootnode->update_visibility(); + rootnode->update_time(); } if(rootnode != NULL) { VLOG(1) << "BVH build statistics:\n" @@ -836,7 +843,10 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, prim_object[start] = ref->prim_object(); uint visibility = objects[ref->prim_object()]->visibility; - return new LeafNode(ref->bounds(), visibility, start, start+1); + BVHNode *leaf_node = new LeafNode(ref->bounds(), visibility, start, start+1); + leaf_node->m_time_from = ref->time_from(); + leaf_node->m_time_to = ref->time_to(); + return leaf_node; } else { int mid = num/2; @@ -847,7 +857,10 @@ BVHNode *BVHBuild::create_object_leaf_nodes(const BVHReference *ref, int start, bounds.grow(leaf0->m_bounds); bounds.grow(leaf1->m_bounds); - return new InnerNode(bounds, leaf0, leaf1); + BVHNode *inner_node = new InnerNode(bounds, leaf0, leaf1); + inner_node->m_time_from = min(leaf0->m_time_from, leaf1->m_time_from); + inner_node->m_time_to = max(leaf0->m_time_to, leaf1->m_time_to); + return inner_node; } } @@ -951,6 +964,16 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, visibility[i], start_index, start_index + num); + if(true) { + float time_from = 1.0f, time_to = 0.0f; + for(int j = 0; j < num; ++j) { + const BVHReference &ref = p_ref[i][j]; + time_from = min(time_from, ref.time_from()); + time_to = max(time_to, ref.time_to()); + } + leaf_node->m_time_from = time_from; + leaf_node->m_time_to = time_to; + } if(alignment_found) { /* Need to recalculate leaf bounds with new alignment. */ leaf_node->m_bounds = BoundBox::empty; diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp index f5cd699bdf4..67580e1bc7b 100644 --- a/intern/cycles/bvh/bvh_node.cpp +++ b/intern/cycles/bvh/bvh_node.cpp @@ -176,6 +176,19 @@ uint BVHNode::update_visibility() return m_visibility; } +void BVHNode::update_time() +{ + if(!is_leaf()) { + InnerNode *inner = (InnerNode*)this; + BVHNode *child0 = inner->children[0]; + BVHNode *child1 = inner->children[1]; + child0->update_time(); + child1->update_time(); + m_time_from = min(child0->m_time_from, child1->m_time_from); + m_time_to = max(child0->m_time_to, child1->m_time_to); + } +} + /* Inner Node */ void InnerNode::print(int depth) const diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h index 2faa40ab657..090c426de56 100644 --- a/intern/cycles/bvh/bvh_node.h +++ b/intern/cycles/bvh/bvh_node.h @@ -47,7 +47,9 @@ class BVHNode { public: BVHNode() : m_is_unaligned(false), - m_aligned_space(NULL) + m_aligned_space(NULL), + m_time_from(0.0f), + m_time_to(1.0f) { } @@ -91,12 +93,15 @@ public: void deleteSubtree(); uint update_visibility(); + void update_time(); bool m_is_unaligned; // TODO(sergey): Can be stored as 3x3 matrix, but better to have some // utilities and type defines in util_transform first. Transform *m_aligned_space; + + float m_time_from, m_time_to; }; class InnerNode : public BVHNode diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index 233c7adacba..65f9da1c194 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -130,8 +130,15 @@ class BVHReference public: __forceinline BVHReference() {} - __forceinline BVHReference(const BoundBox& bounds_, int prim_index_, int prim_object_, int prim_type) - : rbounds(bounds_) + __forceinline BVHReference(const BoundBox& bounds_, + int prim_index_, + int prim_object_, + int prim_type, + float time_from = 0.0f, + float time_to = 1.0f) + : rbounds(bounds_), + time_from_(time_from), + time_to_(time_to) { rbounds.min.w = __int_as_float(prim_index_); rbounds.max.w = __int_as_float(prim_object_); @@ -142,6 +149,9 @@ public: __forceinline int prim_index() const { return __float_as_int(rbounds.min.w); } __forceinline int prim_object() const { return __float_as_int(rbounds.max.w); } __forceinline int prim_type() const { return type; } + __forceinline float time_from() const { return time_from_; } + __forceinline float time_to() const { return time_to_; } + BVHReference& operator=(const BVHReference &arg) { if(&arg != this) { @@ -150,9 +160,11 @@ public: return *this; } + protected: BoundBox rbounds; uint type; + float time_from_, time_to_; }; /* BVH Range diff --git a/intern/cycles/kernel/bvh/qbvh_shadow_all.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index b2e99725626..607295f9ed5 100644 --- a/intern/cycles/kernel/bvh/qbvh_shadow_all.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -106,14 +106,20 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + if(false #ifdef __VISIBILITY_FLAG__ - if((__float_as_uint(inodes.x) & PATH_RAY_SHADOW) == 0) { + || ((__float_as_uint(inodes.x) & PATH_RAY_SHADOW) == 0) +#endif +#if BVH_FEATURE(BVH_MOTION) + || UNLIKELY(ray->time < inodes.y) + || UNLIKELY(ray->time > inodes.z) +#endif + ) { /* Pop. */ node_addr = traversal_stack[stack_ptr].addr; --stack_ptr; continue; } -#endif ssef dist; int child_mask = NODE_INTERSECT(kg, diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h index 1d5643ca540..10ae7bee852 100644 --- a/intern/cycles/kernel/bvh/qbvh_traversal.h +++ b/intern/cycles/kernel/bvh/qbvh_traversal.h @@ -117,6 +117,10 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); if(UNLIKELY(node_dist > isect->t) +#if BVH_FEATURE(BVH_MOTION) + || UNLIKELY(ray->time < inodes.y) + || UNLIKELY(ray->time > inodes.z) +#endif #ifdef __VISIBILITY_FLAG__ || (__float_as_uint(inodes.x) & visibility) == 0) #endif From 404e59c842fe04630dc4173e774443887d7a3cb0 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Fri, 20 Jan 2017 16:49:14 +0100 Subject: [PATCH 569/590] D1873: Customize style for animation motion paths New options to define the style of the animation paths in order to get better visibility in complex scenes. Now is possible define the color, thickness and several options relative to the style of the lines used to draw motion path. --- .../startup/bl_ui/properties_animviz.py | 12 ++ source/blender/blenkernel/intern/anim.c | 10 +- .../blenloader/intern/versioning_270.c | 30 +++ .../editors/space_view3d/drawanimviz.c | 192 ++++++++++++------ source/blender/makesdna/DNA_action_types.h | 8 +- source/blender/makesrna/intern/rna_animviz.c | 29 ++- 6 files changed, 217 insertions(+), 64 deletions(-) diff --git a/release/scripts/startup/bl_ui/properties_animviz.py b/release/scripts/startup/bl_ui/properties_animviz.py index 11081232f12..046b5eb2aa5 100644 --- a/release/scripts/startup/bl_ui/properties_animviz.py +++ b/release/scripts/startup/bl_ui/properties_animviz.py @@ -86,8 +86,12 @@ class MotionPathButtonsPanel: col = split.column() col.label(text="Show:") col.prop(mps, "show_frame_numbers", text="Frame Numbers") + if mpath is not None: + col.prop(mpath, "lines", text='Lines') + col.prop(mpath, "line_thickness", text='Thickness') col = split.column() + col.label('') col.prop(mps, "show_keyframe_highlight", text="Keyframes") sub = col.column() sub.enabled = mps.show_keyframe_highlight @@ -95,6 +99,14 @@ class MotionPathButtonsPanel: sub.prop(mps, "show_keyframe_action_all", text="+ Non-Grouped Keyframes") sub.prop(mps, "show_keyframe_numbers", text="Keyframe Numbers") + # Customize path + if mpath is not None: + row = layout.row(align=True) + row.prop(mpath, "use_custom_color", text='', toggle=True, icon='COLOR') + sub = row.row(align=True) + sub.enabled = mpath.use_custom_color + sub.prop(mpath, "color", text='') + # FIXME: this panel still needs to be ported so that it will work correctly with animviz class OnionSkinButtonsPanel: diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index 7d3d12ac112..2f65e71c6d2 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -201,7 +201,15 @@ bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Objec mpath->flag |= MOTIONPATH_FLAG_BHEAD; else mpath->flag &= ~MOTIONPATH_FLAG_BHEAD; - + + /* set default custom values */ + mpath->color[0] = 1.0; /* Red */ + mpath->color[1] = 0.0; + mpath->color[2] = 0.0; + + mpath->line_thickness = 1; + mpath->flag |= MOTIONPATH_FLAG_LINES; /* draw lines by default */ + /* allocate a cache */ mpath->points = MEM_callocN(sizeof(bMotionPathVert) * mpath->length, "bMotionPathVerts"); diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 88c583b827e..805542c35a6 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1474,6 +1474,36 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) for (Brush *br = main->brush.first; br; br = br->id.next) { br->fill_threshold /= sqrt_3; } + + /* Custom motion paths */ + if (!DNA_struct_elem_find(fd->filesdna, "bMotionPath", "int", "line_thickness")) { + Object *ob; + for (ob = main->object.first; ob; ob = ob->id.next) { + bMotionPath *mpath; + bPoseChannel *pchan; + mpath = ob->mpath; + if (mpath) { + mpath->color[0] = 1.0f; + mpath->color[1] = 0.0f; + mpath->color[2] = 0.0f; + mpath->line_thickness = 1; + mpath->flag |= MOTIONPATH_FLAG_LINES; + } + /* bones motion path */ + if (ob->pose) { + for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + mpath = pchan->mpath; + if (mpath) { + mpath->color[0] = 1.0f; + mpath->color[1] = 0.0f; + mpath->color[2] = 0.0f; + mpath->line_thickness = 1; + mpath->flag |= MOTIONPATH_FLAG_LINES; + } + } + } + } + } } /* To be added to next subversion bump! */ diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c index cf738de0202..975936b61a7 100644 --- a/source/blender/editors/space_view3d/drawanimviz.c +++ b/source/blender/editors/space_view3d/drawanimviz.c @@ -75,6 +75,80 @@ void draw_motion_paths_init(View3D *v3d, ARegion *ar) glLoadMatrixf(rv3d->viewmat); } +/* set color +* - more intense for active/selected bones, less intense for unselected bones +* - black for before current frame, green for current frame, blue for after current frame +* - intensity decreases as distance from current frame increases +* +* If the user select custom color, the color is replaced for the color selected in UI panel +* - 75% Darker color is used for previous frames +* - 50% Darker color for current frame +* - User selected color for next frames +*/ +void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra, + float prev_color[3], float frame_color[3], float next_color[3]) +{ + int frame = sfra + i; + int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */ + +#define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min) + float intensity; /* how faint */ + + if (frame < CFRA) { + if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { + /* Custom color: previous frames color is darker than current frame */ + glColor3fv(prev_color); + } + else { + /* black - before cfra */ + if (sel) { + /* intensity = 0.5f; */ + intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f); + } + else { + /* intensity = 0.8f; */ + intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f); + } + UI_ThemeColorBlend(TH_WIRE, blend_base, intensity); + } + } + else if (frame > CFRA) { + if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { + /* Custom color: next frames color is equal to user selected color */ + glColor3fv(next_color); + } + else { + /* blue - after cfra */ + if (sel) { + /* intensity = 0.5f; */ + intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f); + } + else { + /* intensity = 0.8f; */ + intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f); + } + UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity); + } + } + else { + if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { + /* Custom color: current frame color is slightly darker than user selected color */ + glColor3fv(frame_color); + } + else { + /* green - on cfra */ + if (sel) { + intensity = 0.5f; + } + else { + intensity = 0.99f; + } + UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10); + } + } +#undef SET_INTENSITY +} + /* Draw the given motion path for an Object or a Bone * - assumes that the viewport has already been initialized properly * i.e. draw_motion_paths_init() has been called @@ -86,6 +160,28 @@ void draw_motion_path_instance(Scene *scene, bMotionPathVert *mpv, *mpv_start; int i, stepsize = avs->path_step; int sfra, efra, sind, len; + float prev_color[3]; + float frame_color[3]; + float next_color[3]; + + /* Custom color - Previous frames: color is darker than current frame */ + prev_color[0] = mpath->color[0] * 0.25f; + prev_color[1] = mpath->color[1] * 0.25f; + prev_color[2] = mpath->color[2] * 0.25f; + + /* Custom color - Current frame: color is slightly darker than user selected color */ + frame_color[0] = mpath->color[0] * 0.50f; + frame_color[1] = mpath->color[1] * 0.50f; + frame_color[2] = mpath->color[2] * 0.50f; + + /* Custom color - Next frames: color is equal to user selection */ + next_color[0] = mpath->color[0]; + next_color[1] = mpath->color[1]; + next_color[2] = mpath->color[2]; + + /* Save old line width */ + GLfloat old_width; + glGetFloatv(GL_LINE_WIDTH, &old_width); /* get frame ranges */ if (avs->path_type == MOTIONPATH_TYPE_ACFRA) { @@ -130,64 +226,27 @@ void draw_motion_path_instance(Scene *scene, mpv_start = (mpath->points + sind); /* draw curve-line of path */ - - glBegin(GL_LINE_STRIP); - for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { - short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT); - float intensity; /* how faint */ - - int frame = sfra + i; - int blend_base = (abs(frame - CFRA) == 1) ? TH_CFRAME : TH_BACK; /* "bleed" cframe color to ease color blending */ - - /* set color - * - more intense for active/selected bones, less intense for unselected bones - * - black for before current frame, green for current frame, blue for after current frame - * - intensity decreases as distance from current frame increases - */ -#define SET_INTENSITY(A, B, C, min, max) (((1.0f - ((C - B) / (C - A))) * (max - min)) + min) - if (frame < CFRA) { - /* black - before cfra */ - if (sel) { - /* intensity = 0.5f; */ - intensity = SET_INTENSITY(sfra, i, CFRA, 0.25f, 0.75f); - } - else { - /* intensity = 0.8f; */ - intensity = SET_INTENSITY(sfra, i, CFRA, 0.68f, 0.92f); - } - UI_ThemeColorBlend(TH_WIRE, blend_base, intensity); - } - else if (frame > CFRA) { - /* blue - after cfra */ - if (sel) { - /* intensity = 0.5f; */ - intensity = SET_INTENSITY(CFRA, i, efra, 0.25f, 0.75f); - } - else { - /* intensity = 0.8f; */ - intensity = SET_INTENSITY(CFRA, i, efra, 0.68f, 0.92f); - } - UI_ThemeColorBlend(TH_BONE_POSE, blend_base, intensity); - } - else { - /* green - on cfra */ - if (sel) { - intensity = 0.5f; - } - else { - intensity = 0.99f; - } - UI_ThemeColorBlendShade(TH_CFRAME, TH_BACK, intensity, 10); - } -#undef SET_INTENSITY + /* Draw lines only if line drawing option is enabled */ + if (mpath->flag & MOTIONPATH_FLAG_LINES) { + /* set line thickness */ + glLineWidth(mpath->line_thickness); - /* draw a vertex with this color */ - glVertex3fv(mpv->co); + glBegin(GL_LINE_STRIP); + for (i = 0, mpv = mpv_start; i < len; i++, mpv++) { + short sel = (pchan) ? (pchan->bone->flag & BONE_SELECTED) : (ob->flag & SELECT); + /* Set color */ + set_motion_path_color(scene, mpath, i, sel, sfra, efra, prev_color, frame_color, next_color); + /* draw a vertex with this color */ + glVertex3fv(mpv->co); + } + + glEnd(); + /* back to old line thickness */ + glLineWidth(old_width); } - - glEnd(); - - glPointSize(1.0); + + /* Point must be bigger than line thickness */ + glPointSize(mpath->line_thickness + 1.0); /* draw little black point at each frame * NOTE: this is not really visible/noticeable @@ -197,8 +256,13 @@ void draw_motion_path_instance(Scene *scene, glVertex3fv(mpv->co); glEnd(); - /* Draw little white dots at each framestep value */ - UI_ThemeColor(TH_TEXT_HI); + /* Draw little white dots at each framestep value or replace with custom color */ + if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { + glColor4fv(mpath->color); + } + else { + UI_ThemeColor(TH_TEXT_HI); + } glBegin(GL_POINTS); for (i = 0, mpv = mpv_start; i < len; i += stepsize, mpv += stepsize) glVertex3fv(mpv->co); @@ -208,11 +272,11 @@ void draw_motion_path_instance(Scene *scene, * NOTE: this is only done when keyframes are shown, since this adds similar types of clutter */ if ((avs->path_viewflag & MOTIONPATH_VIEW_KFRAS) && - (sfra < CFRA) && (CFRA <= efra)) + (sfra < CFRA) && (CFRA <= efra)) { UI_ThemeColor(TH_CFRAME); - glPointSize(6.0f); + glPointSize(mpath->line_thickness + 5.0); glBegin(GL_POINTS); mpv = mpv_start + (CFRA - sfra); glVertex3fv(mpv->co); @@ -289,7 +353,13 @@ void draw_motion_path_instance(Scene *scene, UI_GetThemeColor3ubv(TH_VERTEX_SELECT, col); col[3] = 255; - glPointSize(4.0f); + /* if custom, point must be bigger than line */ + if (mpath->flag & MOTIONPATH_FLAG_CUSTOM) { + glPointSize(mpath->line_thickness + 3.0); + } + else { + glPointSize(4.0f); + } glColor3ubv(col); glBegin(GL_POINTS); diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index f3df9090d41..1083400ece2 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -76,6 +76,8 @@ typedef struct bMotionPath { int start_frame; /* for drawing paths, the start frame number */ int end_frame; /* for drawing paths, the end frame number */ + float color[3]; /* optional custom color */ + int line_thickness; /* line thickness */ int flag; /* baking settings - eMotionPath_Flag */ } bMotionPath; @@ -84,7 +86,11 @@ typedef enum eMotionPath_Flag { /* (for bones) path represents the head of the bone */ MOTIONPATH_FLAG_BHEAD = (1 << 0), /* motion path is being edited */ - MOTIONPATH_FLAG_EDIT = (1 << 1) + MOTIONPATH_FLAG_EDIT = (1 << 1), + /* Custom colors */ + MOTIONPATH_FLAG_CUSTOM = (1 << 2), + /* Draw lines or only points */ + MOTIONPATH_FLAG_LINES = (1 << 3) } eMotionPath_Flag; /* Visualization General --------------------------- */ diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c index 8e42e68ed1e..eea24bfb1e0 100644 --- a/source/blender/makesrna/intern/rna_animviz.c +++ b/source/blender/makesrna/intern/rna_animviz.c @@ -153,7 +153,20 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) prop = RNA_def_property(srna, "length", PROP_INT, PROP_TIME); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_ui_text(prop, "Length", "Number of frames cached"); - + + /* Custom Color */ + prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 3); + RNA_def_property_ui_text(prop, "Color", "Custom color for motion path"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + /* Line width */ + prop = RNA_def_property(srna, "line_thickness", PROP_INT, PROP_NONE); + RNA_def_property_int_sdna(prop, NULL, "line_thickness"); + RNA_def_property_range(prop, 1, 6); + RNA_def_property_ui_text(prop, "Line thickness", "Line thickness for drawing path"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + /* Settings */ prop = RNA_def_property(srna, "use_bone_head", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_BHEAD); @@ -164,6 +177,19 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) prop = RNA_def_property(srna, "is_modified", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_EDIT); RNA_def_property_ui_text(prop, "Edit Path", "Path is being edited"); + + /* Use custom color */ + prop = RNA_def_property(srna, "use_custom_color", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_CUSTOM); + RNA_def_property_ui_text(prop, "Custom colors", "Use custom color for this motion path"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + + /* Draw lines between keyframes */ + prop = RNA_def_property(srna, "lines", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", MOTIONPATH_FLAG_LINES); + RNA_def_property_ui_text(prop, "Lines", "Draw straight lines between keyframe points"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); + } /* --- */ @@ -337,6 +363,7 @@ static void rna_def_animviz_paths(BlenderRNA *brna) "Number of frames to show after the current frame " "(only for 'Around Current Frame' Onion-skinning method)"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); /* XXX since this is only for 3d-view drawing */ + } /* --- */ From 2666a222f62ea7b33aa1a72ea0ca504ca10383de Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 20 Jan 2017 12:21:04 +0100 Subject: [PATCH 570/590] Cleanup/fix last remnant usages of int instead of size_t for string length in BLI_string_utils. --- source/blender/blenlib/BLI_string_utils.h | 2 +- source/blender/blenlib/intern/string_utils.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h index 719d6e3c57b..bb19ed574bb 100644 --- a/source/blender/blenlib/BLI_string_utils.h +++ b/source/blender/blenlib/BLI_string_utils.h @@ -44,7 +44,7 @@ struct ListBase; typedef bool (*UniquenameCheckCallback)(void *arg, const char *name); -int BLI_split_name_num(char *left, int *nr, const char *name, const char delim); +size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim); void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len); void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len); diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index 435a88d6e21..8d91a55a5ad 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -61,7 +61,7 @@ * \param delim Delimiter character * \return Length of \a left */ -int BLI_split_name_num(char *left, int *nr, const char *name, const char delim) +size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim) { const size_t name_len = strlen(name); @@ -70,7 +70,7 @@ int BLI_split_name_num(char *left, int *nr, const char *name, const char delim) /* name doesn't end with a delimiter "foo." */ if ((name_len > 1 && name[name_len - 1] == delim) == 0) { - int a = name_len; + size_t a = name_len; while (a--) { if (name[a] == delim) { left[a] = '\0'; /* truncate left part here */ @@ -295,7 +295,7 @@ bool BLI_uniquename_cb( char *tempname = alloca(name_len); char *left = alloca(name_len); int number; - int len = BLI_split_name_num(left, &number, name, delim); + size_t len = BLI_split_name_num(left, &number, name, delim); do { /* add 1 to account for \0 */ const size_t numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1; From 051526da6279c5e5166cb7188ef7e3e060fc3a5a Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 20 Jan 2017 13:03:21 +0100 Subject: [PATCH 571/590] Cleanup/fix some BLI_string_utf8 not using size_t/off_t as expected. --- source/blender/blenkernel/intern/library.c | 7 ++++--- source/blender/blenkernel/intern/text.c | 7 ++++--- source/blender/blenlib/BLI_string_utf8.h | 4 ++-- source/blender/blenlib/intern/string_utf8.c | 18 ++++++++++++------ .../editors/interface/interface_handlers.c | 2 +- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index ea613795249..77013a55d18 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -1408,7 +1408,8 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name) static bool check_for_dupid(ListBase *lb, ID *id, char *name) { ID *idtest; - int nr = 0, a, left_len; + int nr = 0, a; + size_t left_len; #define MAX_IN_USE 64 bool in_use[MAX_IN_USE]; /* to speed up finding unused numbers within [1 .. MAX_IN_USE - 1] */ @@ -1442,7 +1443,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name) /* Code above may have generated invalid utf-8 string, due to raw truncation. * Ensure we get a valid one now! */ - left_len -= BLI_utf8_invalid_strip(left, left_len); + left_len -= (size_t)BLI_utf8_invalid_strip(left, left_len); for (idtest = lb->first; idtest; idtest = idtest->next) { int nrtest; @@ -1484,7 +1485,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name) * shave off the end chars until we have a unique name. * Check the null terminators match as well so we don't get Cube.000 -> Cube.00 */ if (nr == 0 && name[left_len] == '\0') { - int len; + size_t len; /* FIXME: this code will never be executed, because either nr will be * at least 1, or name will not end at left_len! */ BLI_assert(0); diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 672857e88fe..a0b987d8cfe 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -235,8 +235,9 @@ Text *BKE_text_add(Main *bmain, const char *name) /* to a valid utf-8 sequences */ int txt_extended_ascii_as_utf8(char **str) { - int bad_char, added = 0, i = 0; - int length = strlen(*str); + size_t bad_char, i = 0; + const size_t length = strlen(*str); + int added = 0; while ((*str)[i]) { if ((bad_char = BLI_utf8_invalid_byte(*str + i, length - i)) == -1) @@ -248,7 +249,7 @@ int txt_extended_ascii_as_utf8(char **str) if (added != 0) { char *newstr = MEM_mallocN(length + added + 1, "text_line"); - int mi = 0; + size_t mi = 0; i = 0; while ((*str)[i]) { diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h index 0740b574c1a..970f4e6c3db 100644 --- a/source/blender/blenlib/BLI_string_utf8.h +++ b/source/blender/blenlib/BLI_string_utf8.h @@ -36,8 +36,8 @@ extern "C" { char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(); size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(); char *BLI_strncat_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(); -int BLI_utf8_invalid_byte(const char *str, int length) ATTR_NONNULL(); -int BLI_utf8_invalid_strip(char *str, int length) ATTR_NONNULL(); +off_t BLI_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL(); +int BLI_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(); int BLI_str_utf8_size(const char *p) ATTR_NONNULL(); /* warning, can return -1 on bad chars */ int BLI_str_utf8_size_safe(const char *p) ATTR_NONNULL(); diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c index 0ab11810b48..7352cd7332b 100644 --- a/source/blender/blenlib/intern/string_utf8.c +++ b/source/blender/blenlib/intern/string_utf8.c @@ -74,7 +74,7 @@ static const size_t utf8_skip_data[256] = { * * \return the offset of the first invalid byte. */ -int BLI_utf8_invalid_byte(const char *str, int length) +off_t BLI_utf8_invalid_byte(const char *str, size_t length) { const unsigned char *p, *perr, *pend = (const unsigned char *)str + length; unsigned char c; @@ -161,18 +161,24 @@ int BLI_utf8_invalid_byte(const char *str, int length) utf8_error: - return (int)((const char *)perr - (const char *)str); + return ((const char *)perr - (const char *)str); } -int BLI_utf8_invalid_strip(char *str, int length) +/** + * Remove any invalid utf-8 byte (taking into account multi-bytes sequence of course). + * + * @return number of stripped bytes. + */ +int BLI_utf8_invalid_strip(char *str, size_t length) { - int bad_char, tot = 0; + off_t bad_char; + int tot = 0; BLI_assert(str[length] == '\0'); while ((bad_char = BLI_utf8_invalid_byte(str, length)) != -1) { str += bad_char; - length -= (bad_char + 1); + length -= (size_t)(bad_char + 1); if (length == 0) { /* last character bad, strip it */ @@ -182,7 +188,7 @@ int BLI_utf8_invalid_strip(char *str, int length) } else { /* strip, keep looking */ - memmove(str, str + 1, (size_t)length + 1); /* +1 for NULL char! */ + memmove(str, str + 1, length + 1); /* +1 for NULL char! */ tot++; } } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a761bcfdf5e..734cd02a056 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2963,7 +2963,7 @@ static bool ui_textedit_copypaste(uiBut *but, uiHandleButtonData *data, const in if (pbuf) { if (ui_but_is_utf8(but)) { - buf_len -= BLI_utf8_invalid_strip(pbuf, buf_len); + buf_len -= BLI_utf8_invalid_strip(pbuf, (size_t)buf_len); } ui_textedit_insert_buf(but, data, pbuf, buf_len); From 094d916c603e2b150404388f9d9287942b589abe Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 20 Jan 2017 17:47:09 +0100 Subject: [PATCH 572/590] Fix compilation error with strict flags --- source/blender/editors/space_view3d/drawanimviz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_view3d/drawanimviz.c b/source/blender/editors/space_view3d/drawanimviz.c index 975936b61a7..f0e65f84205 100644 --- a/source/blender/editors/space_view3d/drawanimviz.c +++ b/source/blender/editors/space_view3d/drawanimviz.c @@ -85,7 +85,7 @@ void draw_motion_paths_init(View3D *v3d, ARegion *ar) * - 50% Darker color for current frame * - User selected color for next frames */ -void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra, +static void set_motion_path_color(Scene *scene, bMotionPath *mpath, int i, short sel, int sfra, int efra, float prev_color[3], float frame_color[3], float next_color[3]) { int frame = sfra + i; From a1c21e0b5049ebe342707497021ce7e1f2e624e7 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 20 Jan 2017 17:52:48 +0100 Subject: [PATCH 573/590] Cycles: Cleanup, split one gigantic function into two smaller ones --- intern/cycles/bvh/bvh_build.cpp | 361 ++++++++++++++++---------------- intern/cycles/bvh/bvh_build.h | 2 + 2 files changed, 186 insertions(+), 177 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 4abd686cc6e..9ff68333c80 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -112,104 +112,214 @@ BVHBuild::~BVHBuild() /* Adding References */ -void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i) +void BVHBuild::add_reference_triangles(BoundBox& root, BoundBox& center, Mesh *mesh, int i) { - if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { - Attribute *attr_mP = NULL; - - if(mesh->has_motion_blur()) - attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - const size_t num_triangles = mesh->num_triangles(); - for(uint j = 0; j < num_triangles; j++) { - Mesh::Triangle t = mesh->get_triangle(j); - const float3 *verts = &mesh->verts[0]; - if(attr_mP == NULL) { - BoundBox bounds = BoundBox::empty; - t.bounds_grow(verts, bounds); - if(bounds.valid()) { - references.push_back(BVHReference(bounds, - j, - i, - PRIMITIVE_TRIANGLE)); - root.grow(bounds); - center.grow(bounds.center2()); - } + Attribute *attr_mP = NULL; + if(mesh->has_motion_blur()) { + attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + } + const size_t num_triangles = mesh->num_triangles(); + for(uint j = 0; j < num_triangles; j++) { + Mesh::Triangle t = mesh->get_triangle(j); + const float3 *verts = &mesh->verts[0]; + if(attr_mP == NULL) { + BoundBox bounds = BoundBox::empty; + t.bounds_grow(verts, bounds); + if(bounds.valid()) { + references.push_back(BVHReference(bounds, + j, + i, + PRIMITIVE_TRIANGLE)); + root.grow(bounds); + center.grow(bounds.center2()); } - else if(params.num_motion_triangle_steps == 0 || params.use_spatial_split) { - /* Motion triangles, simple case: single node for the whole - * primitive. Lowest memory footprint and faster BVH build but - * least optimal ray-tracing. - */ - /* TODO(sergey): Support motion steps for spatially split BVH. */ - const size_t num_verts = mesh->verts.size(); - const size_t num_steps = mesh->motion_steps; - const float3 *vert_steps = attr_mP->data_float3(); - BoundBox bounds = BoundBox::empty; - t.bounds_grow(verts, bounds); - for(size_t step = 0; step < num_steps - 1; step++) { - t.bounds_grow(vert_steps + step*num_verts, bounds); - } + } + else if(params.num_motion_triangle_steps == 0 || params.use_spatial_split) { + /* Motion triangles, simple case: single node for the whole + * primitive. Lowest memory footprint and faster BVH build but + * least optimal ray-tracing. + */ + /* TODO(sergey): Support motion steps for spatially split BVH. */ + const size_t num_verts = mesh->verts.size(); + const size_t num_steps = mesh->motion_steps; + const float3 *vert_steps = attr_mP->data_float3(); + BoundBox bounds = BoundBox::empty; + t.bounds_grow(verts, bounds); + for(size_t step = 0; step < num_steps - 1; step++) { + t.bounds_grow(vert_steps + step*num_verts, bounds); + } + if(bounds.valid()) { + references.push_back( + BVHReference(bounds, + j, + i, + PRIMITIVE_MOTION_TRIANGLE)); + root.grow(bounds); + center.grow(bounds.center2()); + } + } + else { + /* Motion triangles, trace optimized case: we split triangle + * primitives into separate nodes for each of the time steps. + * This way we minimize overlap of neighbor curve primitives. + */ + const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1; + const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1); + const size_t num_verts = mesh->verts.size(); + const size_t num_steps = mesh->motion_steps; + const float3 *vert_steps = attr_mP->data_float3(); + /* Calculate bounding box of the previous time step. + * Will be reused later to avoid duplicated work on + * calculating BVH time step boundbox. + */ + float3 prev_verts[3]; + t.motion_verts(verts, + vert_steps, + num_verts, + num_steps, + 0.0f, + prev_verts); + BoundBox prev_bounds = BoundBox::empty; + prev_bounds.grow(prev_verts[0]); + prev_bounds.grow(prev_verts[1]); + prev_bounds.grow(prev_verts[2]); + /* Create all primitive time steps, */ + for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) { + const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1; + float3 curr_verts[3]; + t.motion_verts(verts, + vert_steps, + num_verts, + num_steps, + curr_time, + curr_verts); + BoundBox curr_bounds = BoundBox::empty; + curr_bounds.grow(curr_verts[0]); + curr_bounds.grow(curr_verts[1]); + curr_bounds.grow(curr_verts[2]); + BoundBox bounds = prev_bounds; + bounds.grow(curr_bounds); if(bounds.valid()) { + const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1; references.push_back( BVHReference(bounds, j, i, - PRIMITIVE_MOTION_TRIANGLE)); + PRIMITIVE_MOTION_TRIANGLE, + prev_time, + curr_time)); + root.grow(bounds); + center.grow(bounds.center2()); + } + /* Current time boundbox becomes previous one for the + * next time step. + */ + prev_bounds = curr_bounds; + } + } + } +} + +void BVHBuild::add_reference_curves(BoundBox& root, BoundBox& center, Mesh *mesh, int i) +{ + Attribute *curve_attr_mP = NULL; + if(mesh->has_motion_blur()) { + curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + } + size_t num_curves = mesh->num_curves(); + for(uint j = 0; j < num_curves; j++) { + const Mesh::Curve curve = mesh->get_curve(j); + const float *curve_radius = &mesh->curve_radius[0]; + for(int k = 0; k < curve.num_keys - 1; k++) { + if(curve_attr_mP == NULL) { + /* Really simple logic for static hair. */ + BoundBox bounds = BoundBox::empty; + curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds); + if(bounds.valid()) { + int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE, k); + references.push_back(BVHReference(bounds, j, i, packed_type)); + root.grow(bounds); + center.grow(bounds.center2()); + } + } + else if(params.num_motion_curve_steps == 0 || params.use_spatial_split) { + /* Simple case of motion curves: single node for the while + * shutter time. Lowest memory usage but less optimal + * rendering. + */ + /* TODO(sergey): Support motion steps for spatially split BVH. */ + BoundBox bounds = BoundBox::empty; + curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds); + const size_t num_keys = mesh->curve_keys.size(); + const size_t num_steps = mesh->motion_steps; + const float3 *key_steps = curve_attr_mP->data_float3(); + for(size_t step = 0; step < num_steps - 1; step++) { + curve.bounds_grow(k, + key_steps + step*num_keys, + curve_radius, + bounds); + } + if(bounds.valid()) { + int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k); + references.push_back(BVHReference(bounds, + j, + i, + packed_type)); root.grow(bounds); center.grow(bounds.center2()); } } else { - /* Motion triangles, trace optimized case: we split triangle + /* Motion curves, trace optimized case: we split curve keys * primitives into separate nodes for each of the time steps. * This way we minimize overlap of neighbor curve primitives. */ const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1; const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1); - const size_t num_verts = mesh->verts.size(); const size_t num_steps = mesh->motion_steps; - const float3 *vert_steps = attr_mP->data_float3(); + const float3 *curve_keys = &mesh->curve_keys[0]; + const float3 *key_steps = curve_attr_mP->data_float3(); + const size_t num_keys = mesh->curve_keys.size(); /* Calculate bounding box of the previous time step. * Will be reused later to avoid duplicated work on * calculating BVH time step boundbox. */ - float3 prev_verts[3]; - t.motion_verts(verts, - vert_steps, - num_verts, - num_steps, - 0.0f, - prev_verts); + float4 prev_keys[4]; + curve.cardinal_motion_keys(curve_keys, + curve_radius, + key_steps, + num_keys, + num_steps, + 0.0f, + k - 1, k, k + 1, k + 2, + prev_keys); BoundBox prev_bounds = BoundBox::empty; - prev_bounds.grow(prev_verts[0]); - prev_bounds.grow(prev_verts[1]); - prev_bounds.grow(prev_verts[2]); + curve.bounds_grow(prev_keys, prev_bounds); /* Create all primitive time steps, */ for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) { const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1; - float3 curr_verts[3]; - t.motion_verts(verts, - vert_steps, - num_verts, - num_steps, - curr_time, - curr_verts); + float4 curr_keys[4]; + curve.cardinal_motion_keys(curve_keys, + curve_radius, + key_steps, + num_keys, + num_steps, + curr_time, + k - 1, k, k + 1, k + 2, + curr_keys); BoundBox curr_bounds = BoundBox::empty; - curr_bounds.grow(curr_verts[0]); - curr_bounds.grow(curr_verts[1]); - curr_bounds.grow(curr_verts[2]); + curve.bounds_grow(curr_keys, curr_bounds); BoundBox bounds = prev_bounds; bounds.grow(curr_bounds); if(bounds.valid()) { const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1; - references.push_back( - BVHReference(bounds, - j, - i, - PRIMITIVE_MOTION_TRIANGLE, - prev_time, - curr_time)); + int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k); + references.push_back(BVHReference(bounds, + j, + i, + packed_type, + prev_time, + curr_time)); root.grow(bounds); center.grow(bounds.center2()); } @@ -221,118 +331,15 @@ void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, } } } +} +void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i) +{ + if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { + add_reference_triangles(root, center, mesh, i); + } if(params.primitive_mask & PRIMITIVE_ALL_CURVE) { - Attribute *curve_attr_mP = NULL; - - if(mesh->has_motion_blur()) - curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - - size_t num_curves = mesh->num_curves(); - for(uint j = 0; j < num_curves; j++) { - const Mesh::Curve curve = mesh->get_curve(j); - const float *curve_radius = &mesh->curve_radius[0]; - for(int k = 0; k < curve.num_keys - 1; k++) { - if(curve_attr_mP == NULL) { - /* Really simple logic for static hair. */ - BoundBox bounds = BoundBox::empty; - curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds); - if(bounds.valid()) { - int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_CURVE, k); - references.push_back(BVHReference(bounds, j, i, packed_type)); - root.grow(bounds); - center.grow(bounds.center2()); - } - } - else if(params.num_motion_curve_steps == 0 || params.use_spatial_split) { - /* Simple case of motion curves: single node for the while - * shutter time. Lowest memory usage but less optimal - * rendering. - */ - /* TODO(sergey): Support motion steps for spatially split BVH. */ - BoundBox bounds = BoundBox::empty; - curve.bounds_grow(k, &mesh->curve_keys[0], curve_radius, bounds); - const size_t num_keys = mesh->curve_keys.size(); - const size_t num_steps = mesh->motion_steps; - const float3 *key_steps = curve_attr_mP->data_float3(); - for(size_t step = 0; step < num_steps - 1; step++) { - curve.bounds_grow(k, - key_steps + step*num_keys, - curve_radius, - bounds); - } - if(bounds.valid()) { - int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k); - references.push_back(BVHReference(bounds, - j, - i, - packed_type)); - root.grow(bounds); - center.grow(bounds.center2()); - } - } - else { - /* Motion curves, trace optimized case: we split curve keys - * primitives into separate nodes for each of the time steps. - * This way we minimize overlap of neighbor curve primitives. - */ - const int num_bvh_steps = params.num_motion_curve_steps * 2 + 1; - const float num_bvh_steps_inv_1 = 1.0f / (num_bvh_steps - 1); - const size_t num_steps = mesh->motion_steps; - const float3 *curve_keys = &mesh->curve_keys[0]; - const float3 *key_steps = curve_attr_mP->data_float3(); - const size_t num_keys = mesh->curve_keys.size(); - /* Calculate bounding box of the previous time step. - * Will be reused later to avoid duplicated work on - * calculating BVH time step boundbox. - */ - float4 prev_keys[4]; - curve.cardinal_motion_keys(curve_keys, - curve_radius, - key_steps, - num_keys, - num_steps, - 0.0f, - k - 1, k, k + 1, k + 2, - prev_keys); - BoundBox prev_bounds = BoundBox::empty; - curve.bounds_grow(prev_keys, prev_bounds); - /* Create all primitive time steps, */ - for(int bvh_step = 1; bvh_step < num_bvh_steps; ++bvh_step) { - const float curr_time = (float)(bvh_step) * num_bvh_steps_inv_1; - float4 curr_keys[4]; - curve.cardinal_motion_keys(curve_keys, - curve_radius, - key_steps, - num_keys, - num_steps, - curr_time, - k - 1, k, k + 1, k + 2, - curr_keys); - BoundBox curr_bounds = BoundBox::empty; - curve.bounds_grow(curr_keys, curr_bounds); - BoundBox bounds = prev_bounds; - bounds.grow(curr_bounds); - if(bounds.valid()) { - const float prev_time = (float)(bvh_step - 1) * num_bvh_steps_inv_1; - int packed_type = PRIMITIVE_PACK_SEGMENT(PRIMITIVE_MOTION_CURVE, k); - references.push_back(BVHReference(bounds, - j, - i, - packed_type, - prev_time, - curr_time)); - root.grow(bounds); - center.grow(bounds.center2()); - } - /* Current time boundbox becomes previous one for the - * next time step. - */ - prev_bounds = curr_bounds; - } - } - } - } + add_reference_curves(root, center, mesh, i); } } diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h index 64180349935..ee3cde66a2f 100644 --- a/intern/cycles/bvh/bvh_build.h +++ b/intern/cycles/bvh/bvh_build.h @@ -63,6 +63,8 @@ protected: friend class BVHObjectBinning; /* Adding references. */ + void add_reference_triangles(BoundBox& root, BoundBox& center, Mesh *mesh, int i); + void add_reference_curves(BoundBox& root, BoundBox& center, Mesh *mesh, int i); void add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i); void add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i); void add_references(BVHRange& root); From 43268c1997871a02c06e686d61892cb48753d1ed Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 20 Jan 2017 17:54:17 +0100 Subject: [PATCH 574/590] Cycles: Use more const qualifiers to avoid possible issues --- intern/cycles/bvh/bvh_build.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 9ff68333c80..1ce3a754460 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -114,7 +114,7 @@ BVHBuild::~BVHBuild() void BVHBuild::add_reference_triangles(BoundBox& root, BoundBox& center, Mesh *mesh, int i) { - Attribute *attr_mP = NULL; + const Attribute *attr_mP = NULL; if(mesh->has_motion_blur()) { attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); } @@ -222,11 +222,11 @@ void BVHBuild::add_reference_triangles(BoundBox& root, BoundBox& center, Mesh *m void BVHBuild::add_reference_curves(BoundBox& root, BoundBox& center, Mesh *mesh, int i) { - Attribute *curve_attr_mP = NULL; + const Attribute *curve_attr_mP = NULL; if(mesh->has_motion_blur()) { curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); } - size_t num_curves = mesh->num_curves(); + const size_t num_curves = mesh->num_curves(); for(uint j = 0; j < num_curves; j++) { const Mesh::Curve curve = mesh->get_curve(j); const float *curve_radius = &mesh->curve_radius[0]; From 21e128226533c704c43c285bb5f78faf16a11b58 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 20 Jan 2017 18:41:56 +0100 Subject: [PATCH 575/590] Fix float buffer of tracking image accessed outside of check that it has been correctly allocated. Reported by coverity scan. --- .../blender/blenkernel/intern/tracking_util.c | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c index c34da4f6814..1c056cda68d 100644 --- a/source/blender/blenkernel/intern/tracking_util.c +++ b/source/blender/blenkernel/intern/tracking_util.c @@ -625,17 +625,17 @@ static ImBuf *make_grayscale_ibuf_copy(ImBuf *ibuf) */ size = (size_t)grayscale->x * (size_t)grayscale->y * sizeof(float); grayscale->channels = 1; - if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image"))) { + if ((grayscale->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) { grayscale->mall |= IB_rectfloat; grayscale->flags |= IB_rectfloat; - } - for (i = 0; i < grayscale->x * grayscale->y; ++i) { - const float *pixel = ibuf->rect_float + ibuf->channels * i; + for (i = 0; i < grayscale->x * grayscale->y; ++i) { + const float *pixel = ibuf->rect_float + ibuf->channels * i; - grayscale->rect_float[i] = 0.2126f * pixel[0] + - 0.7152f * pixel[1] + - 0.0722f * pixel[2]; + grayscale->rect_float[i] = 0.2126f * pixel[0] + + 0.7152f * pixel[1] + + 0.0722f * pixel[2]; + } } return grayscale; @@ -653,14 +653,14 @@ static void ibuf_to_float_image(const ImBuf *ibuf, libmv_FloatImage *float_image static ImBuf *float_image_to_ibuf(libmv_FloatImage *float_image) { ImBuf *ibuf = IMB_allocImBuf(float_image->width, float_image->height, 32, 0); - size_t size = (size_t)ibuf->x * (size_t)ibuf->y * - float_image->channels * sizeof(float); + size_t size = (size_t)ibuf->x * (size_t)ibuf->y * float_image->channels * sizeof(float); ibuf->channels = float_image->channels; - if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image"))) { + if ((ibuf->rect_float = MEM_mapallocN(size, "tracking grayscale image")) != NULL) { ibuf->mall |= IB_rectfloat; ibuf->flags |= IB_rectfloat; + + memcpy(ibuf->rect_float, float_image->buffer, size); } - memcpy(ibuf->rect_float, float_image->buffer, size); return ibuf; } From a97ec403c28dc330b37459b1c94944ffe086abbb Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 20 Jan 2017 18:43:42 +0100 Subject: [PATCH 576/590] Fix/cleanup stupid check on array of char being non-NULL pointer... Reported by coverity scan. --- source/blender/editors/interface/interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index a913421d12c..682db20af55 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1993,7 +1993,7 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but) static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but) { BLI_assert(but->type == UI_BTYPE_TEXT); - return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr && but->drawstr[0]); + return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr[0]); } static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but) From 475d536f720df3ed9bed783e6d108fa1341fe541 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 20 Jan 2017 18:46:06 +0100 Subject: [PATCH 577/590] Fix minor glitches in GP code. Reported by coverity scan. --- source/blender/editors/gpencil/drawgpencil.c | 8 +++----- source/blender/editors/gpencil/gpencil_interpolate.c | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 2fd574d6523..a542bf8fa11 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -1563,7 +1563,7 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i { bGPdata *gpd_source = NULL; ToolSettings *ts; - bGPDbrush *brush; + bGPDbrush *brush = NULL; if (scene) { ts = scene->toolsettings; brush = BKE_gpencil_brush_getactive(ts); @@ -1572,8 +1572,7 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i BKE_gpencil_brush_init_presets(ts); brush = BKE_gpencil_brush_getactive(ts); } - } - if (scene) { + if (spacetype == SPACE_VIEW3D) { gpd_source = (scene->gpd ? scene->gpd : NULL); } @@ -1581,13 +1580,12 @@ static void gp_draw_data_all(Scene *scene, bGPdata *gpd, int offsx, int offsy, i /* currently drawing only gpencil data from either clip or track, but not both - XXX fix logic behind */ gpd_source = (scene->clip->gpd ? scene->clip->gpd : NULL); } - + if (gpd_source) { if (brush != NULL) { gp_draw_data(brush, ts->gp_sculpt.alpha, gpd_source, offsx, offsy, winx, winy, cfra, dflag); } - } } diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 0d3fa1fc90c..297058168a0 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -735,7 +735,7 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting } break; - case BEZT_IPO_CIRC: + case GP_IPO_CIRC: switch (easing) { case BEZT_IPO_EASE_IN: result = BLI_easing_circ_ease_in(time, begin, change, duration); @@ -753,7 +753,7 @@ static float gp_interpolate_seq_easing_calc(GP_Interpolate_Settings *ipo_setting } break; - case BEZT_IPO_CUBIC: + case GP_IPO_CUBIC: switch (easing) { case BEZT_IPO_EASE_IN: result = BLI_easing_cubic_ease_in(time, begin, change, duration); From 82187a58f53fef8fe88f89a8aa38729d871a2a37 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Fri, 20 Jan 2017 21:57:48 +0100 Subject: [PATCH 578/590] Fix own mistake in rB051526da6279, confusing off_t with ptrdiff_t. --- source/blender/blenkernel/intern/text.c | 6 +++--- source/blender/blenlib/BLI_string_utf8.h | 2 +- source/blender/blenlib/intern/string_utf8.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index a0b987d8cfe..88575c7d3be 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -235,8 +235,8 @@ Text *BKE_text_add(Main *bmain, const char *name) /* to a valid utf-8 sequences */ int txt_extended_ascii_as_utf8(char **str) { - size_t bad_char, i = 0; - const size_t length = strlen(*str); + ptrdiff_t bad_char, i = 0; + const ptrdiff_t length = (ptrdiff_t)strlen(*str); int added = 0; while ((*str)[i]) { @@ -249,7 +249,7 @@ int txt_extended_ascii_as_utf8(char **str) if (added != 0) { char *newstr = MEM_mallocN(length + added + 1, "text_line"); - size_t mi = 0; + ptrdiff_t mi = 0; i = 0; while ((*str)[i]) { diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h index 970f4e6c3db..32504a88b48 100644 --- a/source/blender/blenlib/BLI_string_utf8.h +++ b/source/blender/blenlib/BLI_string_utf8.h @@ -36,7 +36,7 @@ extern "C" { char *BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(); size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(); char *BLI_strncat_utf8(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL(); -off_t BLI_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL(); +ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length) ATTR_NONNULL(); int BLI_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(); int BLI_str_utf8_size(const char *p) ATTR_NONNULL(); /* warning, can return -1 on bad chars */ diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c index 7352cd7332b..83d4a75952f 100644 --- a/source/blender/blenlib/intern/string_utf8.c +++ b/source/blender/blenlib/intern/string_utf8.c @@ -74,7 +74,7 @@ static const size_t utf8_skip_data[256] = { * * \return the offset of the first invalid byte. */ -off_t BLI_utf8_invalid_byte(const char *str, size_t length) +ptrdiff_t BLI_utf8_invalid_byte(const char *str, size_t length) { const unsigned char *p, *perr, *pend = (const unsigned char *)str + length; unsigned char c; @@ -171,7 +171,7 @@ utf8_error: */ int BLI_utf8_invalid_strip(char *str, size_t length) { - off_t bad_char; + ptrdiff_t bad_char; int tot = 0; BLI_assert(str[length] == '\0'); From d2382f782e74f9e7b4df49ffc8e40dabb0b8af50 Mon Sep 17 00:00:00 2001 From: Joshua Leung Date: Sun, 22 Jan 2017 02:54:35 +1300 Subject: [PATCH 579/590] Fix T49527: Blender stalls when changing armature ghosting range with stepsize = 0 A big thanks to Steffen Mortensen (stifan) for finding the root cause of this bug! --- source/blender/blenkernel/intern/armature.c | 1 + source/blender/editors/space_view3d/drawarmature.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 2b333941c6e..0287d6ae9ca 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -87,6 +87,7 @@ bArmature *BKE_armature_add(Main *bmain, const char *name) arm->deformflag = ARM_DEF_VGROUP | ARM_DEF_ENVELOPE; arm->flag = ARM_COL_CUSTOM; /* custom bone-group colors */ arm->layer = 1; + arm->ghostsize = 1; return arm; } diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index 95a2df68e4a..149144d969a 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -2463,6 +2463,10 @@ static void draw_ghost_poses_range(Scene *scene, View3D *v3d, ARegion *ar, Base if (end <= start) return; + /* prevent infinite loops if this is set to 0 - T49527 */ + if (arm->ghostsize < 1) + arm->ghostsize = 1; + stepsize = (float)(arm->ghostsize); range = (float)(end - start); @@ -2608,7 +2612,11 @@ static void draw_ghost_poses(Scene *scene, View3D *v3d, ARegion *ar, Base *base) calc_action_range(adt->action, &start, &end, 0); if (start == end) return; - + + /* prevent infinite loops if this is set to 0 - T49527 */ + if (arm->ghostsize < 1) + arm->ghostsize = 1; + stepsize = (float)(arm->ghostsize); range = (float)(arm->ghostep) * stepsize + 0.5f; /* plus half to make the for loop end correct */ From ce8889175a553967583a1152e71b4390a240a112 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Sun, 22 Jan 2017 12:42:14 +0100 Subject: [PATCH 580/590] Fix T50491: Cycles UI breaks when pushing F8. Cycles add-on did not actually support reloading correctly. When you want to correctly reload sub-modules (i.e. modules of an add-on which is a package), you need to use importlib, a mere import will do nothing with already loaded modules (RNA classes are sort of pre-registered when they are evaluated, through the meta-class system). --- intern/cycles/blender/addon/__init__.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index 29388317873..1fc3758ad4d 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -28,6 +28,20 @@ bl_info = { "support": 'OFFICIAL', "category": "Render"} +# Support 'reload' case. +if "bpy" in locals(): + import importlib + if "engine" in locals(): + importlib.reload(engine) + if "version_update" in locals(): + importlib.reload(version_update) + if "ui" in locals(): + importlib.reload(ui) + if "properties" in locals(): + importlib.reload(properties) + if "presets" in locals(): + importlib.reload(presets) + import bpy from . import ( From 2268f41418d9728d75414fc2eebffc1c683fbb05 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 23 Jan 2017 10:23:09 +0100 Subject: [PATCH 581/590] Cycles: Update current Cycles version --- intern/cycles/util/util_version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/intern/cycles/util/util_version.h b/intern/cycles/util/util_version.h index 186a177d9d3..d609c739ac7 100644 --- a/intern/cycles/util/util_version.h +++ b/intern/cycles/util/util_version.h @@ -21,9 +21,9 @@ CCL_NAMESPACE_BEGIN -#define CYCLES_VERSION_MAJOR 1 -#define CYCLES_VERSION_MINOR 7 -#define CYCLES_VERSION_PATCH 0 +#define CYCLES_VERSION_MAJOR 1 +#define CYCLES_VERSION_MINOR 8 +#define CYCLES_VERSION_PATCH 1 #define CYCLES_MAKE_VERSION_STRING2(a,b,c) #a "." #b "." #c #define CYCLES_MAKE_VERSION_STRING(a,b,c) CYCLES_MAKE_VERSION_STRING2(a,b,c) From 77982e159c7b34d82182b1391ad9afdfdace5e96 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 23 Jan 2017 10:35:15 +0100 Subject: [PATCH 582/590] Cycles: Fix typo in the panel name No user visible changes, it was a typo in the name of the class. Spotted by povmaniac in IRC, thanks! --- intern/cycles/blender/addon/ui.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index d26ab73fac3..ddcefaf4c01 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -217,7 +217,7 @@ class CyclesRender_PT_sampling(CyclesButtonsPanel, Panel): draw_samples_info(layout, context) -class CyclesRender_PT_geometery(CyclesButtonsPanel, Panel): +class CyclesRender_PT_geometry(CyclesButtonsPanel, Panel): bl_label = "Geometry" bl_options = {'DEFAULT_CLOSED'} From 7b8810b01a2f378a45874da6676eaccf7c0b9626 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 23 Jan 2017 11:46:02 +0100 Subject: [PATCH 583/590] Silence strict compiler warnings Similar thing to other areas where we mix Blender's char with OpenGL API. --- source/blender/editors/space_action/action_draw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 7c9228e1fae..0764f586de9 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -252,11 +252,11 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) bActionGroup *agrp = ale->data; if (show_group_colors && agrp->customCol) { if (sel) { - unsigned char *cp = agrp->cs.select; + unsigned char *cp = (unsigned char *)agrp->cs.select; glColor4ub(cp[0], cp[1], cp[2], 0x45); } else { - unsigned char *cp = agrp->cs.solid; + unsigned char *cp = (unsigned char *)agrp->cs.solid; glColor4ub(cp[0], cp[1], cp[2], 0x1D); } } @@ -270,7 +270,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) { FCurve *fcu = ale->data; if (show_group_colors && fcu->grp && fcu->grp->customCol) { - unsigned char *cp = fcu->grp->cs.active; + unsigned char *cp = (unsigned char *)fcu->grp->cs.active; if (sel) glColor4ub(cp[0], cp[1], cp[2], 0x65); else glColor4ub(cp[0], cp[1], cp[2], 0x0B); From 2ae39ff6b192b259e6a2c593d72a9c9008a029c4 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 23 Jan 2017 11:52:41 +0100 Subject: [PATCH 584/590] Fix strict compiler warning in the gflags code --- extern/gflags/README.blender | 4 +++- extern/gflags/src/gflags.cc | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/extern/gflags/README.blender b/extern/gflags/README.blender index 0c8ea9a2be3..b48d4d5d110 100644 --- a/extern/gflags/README.blender +++ b/extern/gflags/README.blender @@ -18,6 +18,8 @@ Local modifications: - Applied some modifications from fork https://github.com/Nazg-Gul/gflags.git (see https://github.com/gflags/gflags/pull/129) -- Avoid attemot of acquiring mutex lock in FlagRegistry::GlobalRegistry when +- Avoid attempt of acquiring mutex lock in FlagRegistry::GlobalRegistry when doing static flags initialization. See d81dd2d in Blender repository. +- Made `google::{anonymous}::FlagValue::ValueSize() const` inlined, so it does + not trigger strict compiler warning. \ No newline at end of file diff --git a/extern/gflags/src/gflags.cc b/extern/gflags/src/gflags.cc index 7abe1f70da3..6dcc5170bcc 100644 --- a/extern/gflags/src/gflags.cc +++ b/extern/gflags/src/gflags.cc @@ -218,7 +218,7 @@ class FlagValue { bool Equal(const FlagValue& x) const; FlagValue* New() const; // creates a new one with default value void CopyFrom(const FlagValue& x); - int ValueSize() const; + inline int ValueSize() const; // Calls the given validate-fn on value_buffer_, and returns // whatever it returns. But first casts validate_fn_proto to a @@ -443,7 +443,7 @@ void FlagValue::CopyFrom(const FlagValue& x) { } } -int FlagValue::ValueSize() const { +inline int FlagValue::ValueSize() const { if (type_ > FV_MAX_INDEX) { assert(false); // unknown type return 0; From b9311b5e5a51fec85e3bb3c1d3eaa8a2dcc839e3 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 23 Dec 2016 10:49:59 +0100 Subject: [PATCH 585/590] Cycles: Make object flag names more obvious that hey are object and not shader --- intern/cycles/kernel/bvh/bvh_subsurface.h | 2 +- intern/cycles/kernel/bvh/qbvh_subsurface.h | 2 +- .../kernel/geom/geom_motion_triangle_shader.h | 2 +- intern/cycles/kernel/geom/geom_primitive.h | 2 +- intern/cycles/kernel/geom/geom_triangle.h | 4 ++-- intern/cycles/kernel/kernel_bake.h | 2 +- intern/cycles/kernel/kernel_light.h | 2 +- intern/cycles/kernel/kernel_path.h | 6 +++--- intern/cycles/kernel/kernel_path_branched.h | 6 +++--- intern/cycles/kernel/kernel_shader.h | 6 +++--- intern/cycles/kernel/kernel_types.h | 18 +++++++++--------- intern/cycles/kernel/osl/osl_services.cpp | 2 +- ...dout_emission_blurring_pathtermination_ao.h | 6 +++--- intern/cycles/kernel/svm/svm_wireframe.h | 2 +- intern/cycles/render/object.cpp | 6 +++--- 15 files changed, 34 insertions(+), 34 deletions(-) diff --git a/intern/cycles/kernel/bvh/bvh_subsurface.h b/intern/cycles/kernel/bvh/bvh_subsurface.h index d9623c94b2e..889bbca21e2 100644 --- a/intern/cycles/kernel/bvh/bvh_subsurface.h +++ b/intern/cycles/kernel/bvh/bvh_subsurface.h @@ -72,7 +72,7 @@ void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, ss_isect->num_hits = 0; const int object_flag = kernel_tex_fetch(__object_flag, subsurface_object); - if(!(object_flag & SD_TRANSFORM_APPLIED)) { + if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { #if BVH_FEATURE(BVH_MOTION) Transform ob_itfm; bvh_instance_motion_push(kg, diff --git a/intern/cycles/kernel/bvh/qbvh_subsurface.h b/intern/cycles/kernel/bvh/qbvh_subsurface.h index ccd36df034a..84dc4003133 100644 --- a/intern/cycles/kernel/bvh/qbvh_subsurface.h +++ b/intern/cycles/kernel/bvh/qbvh_subsurface.h @@ -61,7 +61,7 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, ss_isect->num_hits = 0; const int object_flag = kernel_tex_fetch(__object_flag, subsurface_object); - if(!(object_flag & SD_TRANSFORM_APPLIED)) { + if(!(object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { #if BVH_FEATURE(BVH_MOTION) Transform ob_itfm; bvh_instance_motion_push(kg, diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h index c5dbc6a2f52..5b1e014f850 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h @@ -81,7 +81,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, } /* Compute face normal. */ float3 Ng; - if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED) { + if(ccl_fetch(sd, flag) & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0])); } else { diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h index 4384c2093e9..dba82588dbc 100644 --- a/intern/cycles/kernel/geom/geom_primitive.h +++ b/intern/cycles/kernel/geom/geom_primitive.h @@ -157,7 +157,7 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData * if(is_curve_primitive) { center = curve_motion_center_location(kg, sd); - if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED)) + if(!(ccl_fetch(sd, flag) & SD_OBJECT_TRANSFORM_APPLIED)) object_position_transform(kg, sd, ¢er); } else diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h index 17538872ead..9ed619f0bbf 100644 --- a/intern/cycles/kernel/geom/geom_triangle.h +++ b/intern/cycles/kernel/geom/geom_triangle.h @@ -32,7 +32,7 @@ ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd) const float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); /* return normal */ - if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED) + if(ccl_fetch(sd, flag) & SD_OBJECT_NEGATIVE_SCALE_APPLIED) return normalize(cross(v2 - v0, v1 - v0)); else return normalize(cross(v1 - v0, v2 - v0)); @@ -55,7 +55,7 @@ ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int int object_flag = kernel_tex_fetch(__object_flag, object); /* compute normal */ - if(object_flag & SD_NEGATIVE_SCALE_APPLIED) + if(object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) *Ng = normalize(cross(v2 - v0, v1 - v0)); else *Ng = normalize(cross(v1 - v0, v2 - v0)); diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index c32ac6ccf41..5bcc57cdcdf 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -320,7 +320,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, P, Ng, Ng, shader, object, prim, u, v, 1.0f, 0.5f, - !(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED), + !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED), LAMP_NONE); sd.I = sd.N; diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index d4cc36d1495..a2909cec1a1 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -767,7 +767,7 @@ ccl_device void object_transform_light_sample(KernelGlobals *kg, LightSample *ls { #ifdef __INSTANCING__ /* instance transform */ - if(!(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED)) { + if(!(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED)) { # ifdef __OBJECT_MOTION__ Transform itfm; Transform tfm = object_fetch_transform_motion_test(kg, object, time, &itfm); diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index e25f2597366..557c308b747 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -777,11 +777,11 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, /* holdout */ #ifdef __HOLDOUT__ - if((sd.flag & (SD_HOLDOUT|SD_HOLDOUT_MASK)) && (state.flag & PATH_RAY_CAMERA)) { + if((sd.flag & (SD_HOLDOUT|SD_OBJECT_HOLDOUT_MASK)) && (state.flag & PATH_RAY_CAMERA)) { if(kernel_data.background.transparent) { float3 holdout_weight; - if(sd.flag & SD_HOLDOUT_MASK) + if(sd.flag & SD_OBJECT_HOLDOUT_MASK) holdout_weight = make_float3(1.0f, 1.0f, 1.0f); else holdout_weight = shader_holdout_eval(kg, &sd); @@ -790,7 +790,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, L_transparent += average(holdout_weight*throughput); } - if(sd.flag & SD_HOLDOUT_MASK) + if(sd.flag & SD_OBJECT_HOLDOUT_MASK) break; } #endif /* __HOLDOUT__ */ diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index 72a8d98ac00..4ec0ac8e8c9 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -473,11 +473,11 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* holdout */ #ifdef __HOLDOUT__ - if(sd.flag & (SD_HOLDOUT|SD_HOLDOUT_MASK)) { + if(sd.flag & (SD_HOLDOUT|SD_OBJECT_HOLDOUT_MASK)) { if(kernel_data.background.transparent) { float3 holdout_weight; - if(sd.flag & SD_HOLDOUT_MASK) + if(sd.flag & SD_OBJECT_HOLDOUT_MASK) holdout_weight = make_float3(1.0f, 1.0f, 1.0f); else holdout_weight = shader_holdout_eval(kg, &sd); @@ -486,7 +486,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in L_transparent += average(holdout_weight*throughput); } - if(sd.flag & SD_HOLDOUT_MASK) + if(sd.flag & SD_OBJECT_HOLDOUT_MASK) break; } #endif /* __HOLDOUT__ */ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index c1b3153d8fe..d7a9167aaf8 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -298,7 +298,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, ccl_fetch(sd, N) = triangle_smooth_normal(kg, ccl_fetch(sd, prim), ccl_fetch(sd, u), ccl_fetch(sd, v)); #ifdef __INSTANCING__ - if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED)) { + if(!(ccl_fetch(sd, flag) & SD_OBJECT_TRANSFORM_APPLIED)) { object_normal_transform_auto(kg, sd, &ccl_fetch(sd, N)); } #endif @@ -309,7 +309,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, triangle_dPdudv(kg, ccl_fetch(sd, prim), &ccl_fetch(sd, dPdu), &ccl_fetch(sd, dPdv)); # ifdef __INSTANCING__ - if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED)) { + if(!(ccl_fetch(sd, flag) & SD_OBJECT_TRANSFORM_APPLIED)) { object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdu)); object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdv)); } @@ -364,7 +364,7 @@ ccl_device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd, P, Ng, I, shader, object, prim, u, v, 0.0f, 0.5f, - !(kernel_tex_fetch(__object_flag, object) & SD_TRANSFORM_APPLIED), + !(kernel_tex_fetch(__object_flag, object) & SD_OBJECT_TRANSFORM_APPLIED), LAMP_NONE); } diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index 4180465d1a1..a826cda702b 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -732,16 +732,16 @@ enum ShaderDataFlag { SD_VOLUME_CUBIC|SD_HAS_BUMP|SD_HAS_DISPLACEMENT|SD_HAS_CONSTANT_EMISSION), /* object flags */ - SD_HOLDOUT_MASK = (1 << 24), /* holdout for camera rays */ - SD_OBJECT_MOTION = (1 << 25), /* has object motion blur */ - SD_TRANSFORM_APPLIED = (1 << 26), /* vertices have transform applied */ - SD_NEGATIVE_SCALE_APPLIED = (1 << 27), /* vertices have negative scale applied */ - SD_OBJECT_HAS_VOLUME = (1 << 28), /* object has a volume shader */ - SD_OBJECT_INTERSECTS_VOLUME = (1 << 29), /* object intersects AABB of an object with volume shader */ - SD_OBJECT_HAS_VERTEX_MOTION = (1 << 30), /* has position for motion vertices */ + SD_OBJECT_HOLDOUT_MASK = (1 << 24), /* holdout for camera rays */ + SD_OBJECT_MOTION = (1 << 25), /* has object motion blur */ + SD_OBJECT_TRANSFORM_APPLIED = (1 << 26), /* vertices have transform applied */ + SD_OBJECT_NEGATIVE_SCALE_APPLIED = (1 << 27), /* vertices have negative scale applied */ + SD_OBJECT_HAS_VOLUME = (1 << 28), /* object has a volume shader */ + SD_OBJECT_INTERSECTS_VOLUME = (1 << 29), /* object intersects AABB of an object with volume shader */ + SD_OBJECT_HAS_VERTEX_MOTION = (1 << 30), /* has position for motion vertices */ - SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED| - SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME| + SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_OBJECT_TRANSFORM_APPLIED| + SD_OBJECT_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME| SD_OBJECT_INTERSECTS_VOLUME) }; diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index eeccf9a9641..2c8acb4e902 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -712,7 +712,7 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD else motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P); - if(!(sd->flag & SD_TRANSFORM_APPLIED)) { + if(!(sd->flag & SD_OBJECT_TRANSFORM_APPLIED)) { object_position_transform(kg, sd, &P[0]); object_position_transform(kg, sd, &P[1]); object_position_transform(kg, sd, &P[2]); diff --git a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h index 435d1171d5c..fe5899de254 100644 --- a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h +++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h @@ -137,13 +137,13 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( /* holdout */ #ifdef __HOLDOUT__ - if((ccl_fetch(sd, flag) & (SD_HOLDOUT|SD_HOLDOUT_MASK)) && + if((ccl_fetch(sd, flag) & (SD_HOLDOUT|SD_OBJECT_HOLDOUT_MASK)) && (state->flag & PATH_RAY_CAMERA)) { if(kernel_data.background.transparent) { float3 holdout_weight; - if(ccl_fetch(sd, flag) & SD_HOLDOUT_MASK) + if(ccl_fetch(sd, flag) & SD_OBJECT_HOLDOUT_MASK) holdout_weight = make_float3(1.0f, 1.0f, 1.0f); else holdout_weight = shader_holdout_eval(kg, sd); @@ -152,7 +152,7 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( L_transparent_coop[ray_index] += average(holdout_weight*throughput); } - if(ccl_fetch(sd, flag) & SD_HOLDOUT_MASK) { + if(ccl_fetch(sd, flag) & SD_OBJECT_HOLDOUT_MASK) { ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER); *enqueue_flag = 1; } diff --git a/intern/cycles/kernel/svm/svm_wireframe.h b/intern/cycles/kernel/svm/svm_wireframe.h index 6eed9bc1a99..29af11c36b6 100644 --- a/intern/cycles/kernel/svm/svm_wireframe.h +++ b/intern/cycles/kernel/svm/svm_wireframe.h @@ -57,7 +57,7 @@ ccl_device_inline float wireframe(KernelGlobals *kg, else motion_triangle_vertices(kg, ccl_fetch(sd, object), ccl_fetch(sd, prim), ccl_fetch(sd, time), Co); - if(!(ccl_fetch(sd, flag) & SD_TRANSFORM_APPLIED)) { + if(!(ccl_fetch(sd, flag) & SD_OBJECT_TRANSFORM_APPLIED)) { object_position_transform(kg, sd, &Co[0]); object_position_transform(kg, sd, &Co[1]); object_position_transform(kg, sd, &Co[2]); diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index c592b62829e..8342f376836 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -410,7 +410,7 @@ void ObjectManager::device_update_object_transform(UpdateObejctTransformState *s /* Object flag. */ if(ob->use_holdout) { - flag |= SD_HOLDOUT_MASK; + flag |= SD_OBJECT_HOLDOUT_MASK; } state->object_flag[object_index] = flag; @@ -716,9 +716,9 @@ void ObjectManager::apply_static_transforms(DeviceScene *dscene, Scene *scene, u if(progress.get_cancel()) return; } - object_flag[i] |= SD_TRANSFORM_APPLIED; + object_flag[i] |= SD_OBJECT_TRANSFORM_APPLIED; if(object->mesh->transform_negative_scaled) - object_flag[i] |= SD_NEGATIVE_SCALE_APPLIED; + object_flag[i] |= SD_OBJECT_NEGATIVE_SCALE_APPLIED; } else have_instancing = true; From bc096e1eb8790c1624ce7386cd86668267fbea48 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 23 Dec 2016 11:31:19 +0100 Subject: [PATCH 586/590] Cycles: Split ShaderData object and shader flags We started to run out of bits there, so now we separate flags which came from __object_flags and which are either runtime or coming from __shader_flags. Rule now is: SD_OBJECT_* flags are to be tested against new object_flags field of ShaderData, all the rest flags are to be tested against flags field of ShaderData. There should be no user-visible changes, and time difference should be minimal. In fact, from tests here can only see hardly measurable difference and sometimes the new code is somewhat faster (all within a noise floor, so hard to tell for sure). Reviewers: brecht, dingto, juicyfruit, lukasstockner97, maiself Differential Revision: https://developer.blender.org/D2428 --- intern/cycles/kernel/bvh/bvh_volume.h | 2 - intern/cycles/kernel/bvh/bvh_volume_all.h | 1 - intern/cycles/kernel/bvh/qbvh_volume.h | 1 - intern/cycles/kernel/bvh/qbvh_volume_all.h | 2 - .../kernel/geom/geom_motion_triangle_shader.h | 2 +- intern/cycles/kernel/geom/geom_object.h | 1 - intern/cycles/kernel/geom/geom_primitive.h | 5 +- intern/cycles/kernel/geom/geom_triangle.h | 16 +-- intern/cycles/kernel/kernel_path.h | 18 ++- intern/cycles/kernel/kernel_path_branched.h | 19 +-- intern/cycles/kernel/kernel_shader.h | 27 ++-- intern/cycles/kernel/kernel_types.h | 136 ++++++++++++------ intern/cycles/kernel/osl/osl_services.cpp | 2 +- ...out_emission_blurring_pathtermination_ao.h | 14 +- intern/cycles/kernel/svm/svm_wireframe.h | 2 +- 15 files changed, 155 insertions(+), 93 deletions(-) diff --git a/intern/cycles/kernel/bvh/bvh_volume.h b/intern/cycles/kernel/bvh/bvh_volume.h index 107373c17dc..57e5b8d736d 100644 --- a/intern/cycles/kernel/bvh/bvh_volume.h +++ b/intern/cycles/kernel/bvh/bvh_volume.h @@ -236,9 +236,7 @@ bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* instance push */ object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); - if(object_flag & SD_OBJECT_HAS_VOLUME) { - # if BVH_FEATURE(BVH_MOTION) bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm); # else diff --git a/intern/cycles/kernel/bvh/bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h index 529848ebe7b..5a1accebaa0 100644 --- a/intern/cycles/kernel/bvh/bvh_volume_all.h +++ b/intern/cycles/kernel/bvh/bvh_volume_all.h @@ -287,7 +287,6 @@ uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* instance push */ object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); - if(object_flag & SD_OBJECT_HAS_VOLUME) { # if BVH_FEATURE(BVH_MOTION) diff --git a/intern/cycles/kernel/bvh/qbvh_volume.h b/intern/cycles/kernel/bvh/qbvh_volume.h index 1e77d8e67ec..dc6627e2dbb 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume.h +++ b/intern/cycles/kernel/bvh/qbvh_volume.h @@ -293,7 +293,6 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Instance push. */ object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); - if(object_flag & SD_OBJECT_HAS_VOLUME) { # if BVH_FEATURE(BVH_MOTION) bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm); diff --git a/intern/cycles/kernel/bvh/qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h index eb48af6fc68..ff1fa92af6e 100644 --- a/intern/cycles/kernel/bvh/qbvh_volume_all.h +++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h @@ -344,9 +344,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Instance push. */ object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); - if(object_flag & SD_OBJECT_HAS_VOLUME) { - # if BVH_FEATURE(BVH_MOTION) bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm); # else diff --git a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h index 5b1e014f850..0e024a05db6 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle_shader.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle_shader.h @@ -81,7 +81,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, } /* Compute face normal. */ float3 Ng; - if(ccl_fetch(sd, flag) & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { + if(ccl_fetch(sd, object_flag) & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { Ng = normalize(cross(verts[2] - verts[0], verts[1] - verts[0])); } else { diff --git a/intern/cycles/kernel/geom/geom_object.h b/intern/cycles/kernel/geom/geom_object.h index 9f0fe032ba4..f51b2d18657 100644 --- a/intern/cycles/kernel/geom/geom_object.h +++ b/intern/cycles/kernel/geom/geom_object.h @@ -113,7 +113,6 @@ ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals *kg, int ccl_device_inline Transform object_fetch_transform_motion_test(KernelGlobals *kg, int object, float time, Transform *itfm) { int object_flag = kernel_tex_fetch(__object_flag, object); - if(object_flag & SD_OBJECT_MOTION) { /* if we do motion blur */ Transform tfm = object_fetch_transform_motion(kg, object, time); diff --git a/intern/cycles/kernel/geom/geom_primitive.h b/intern/cycles/kernel/geom/geom_primitive.h index dba82588dbc..8a73bb2f78b 100644 --- a/intern/cycles/kernel/geom/geom_primitive.h +++ b/intern/cycles/kernel/geom/geom_primitive.h @@ -157,8 +157,9 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData * if(is_curve_primitive) { center = curve_motion_center_location(kg, sd); - if(!(ccl_fetch(sd, flag) & SD_OBJECT_TRANSFORM_APPLIED)) + if(!(ccl_fetch(sd, object_flag) & SD_OBJECT_TRANSFORM_APPLIED)) { object_position_transform(kg, sd, ¢er); + } } else #endif @@ -181,7 +182,7 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData * motion_post = primitive_attribute_float3(kg, sd, desc, NULL, NULL); #ifdef __HAIR__ - if(is_curve_primitive && (ccl_fetch(sd, flag) & SD_OBJECT_HAS_VERTEX_MOTION) == 0) { + if(is_curve_primitive && (ccl_fetch(sd, object_flag) & SD_OBJECT_HAS_VERTEX_MOTION) == 0) { object_position_transform(kg, sd, &motion_pre); object_position_transform(kg, sd, &motion_post); } diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h index 9ed619f0bbf..3229091bbb0 100644 --- a/intern/cycles/kernel/geom/geom_triangle.h +++ b/intern/cycles/kernel/geom/geom_triangle.h @@ -32,10 +32,12 @@ ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd) const float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); /* return normal */ - if(ccl_fetch(sd, flag) & SD_OBJECT_NEGATIVE_SCALE_APPLIED) + if(ccl_fetch(sd, object_flag) & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { return normalize(cross(v2 - v0, v1 - v0)); - else + } + else { return normalize(cross(v1 - v0, v2 - v0)); + } } /* point and normal on triangle */ @@ -46,20 +48,18 @@ ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); - /* compute point */ float t = 1.0f - u - v; *P = (u*v0 + v*v1 + t*v2); - /* get object flags */ int object_flag = kernel_tex_fetch(__object_flag, object); - /* compute normal */ - if(object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) + if(object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { *Ng = normalize(cross(v2 - v0, v1 - v0)); - else + } + else { *Ng = normalize(cross(v1 - v0, v2 - v0)); - + } /* shader`*/ *shader = kernel_tex_fetch(__tri_shader, prim); } diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 557c308b747..8ce9a4f02ec 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -452,7 +452,7 @@ bool kernel_path_subsurface_scatter( # ifdef __VOLUME__ ss_indirect->need_update_volume_stack = kernel_data.integrator.use_volumes && - ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME; + ccl_fetch(sd, object_flag) & SD_OBJECT_INTERSECTS_VOLUME; # endif /* __VOLUME__ */ /* compute lighting with the BSDF closure */ @@ -777,21 +777,25 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, /* holdout */ #ifdef __HOLDOUT__ - if((sd.flag & (SD_HOLDOUT|SD_OBJECT_HOLDOUT_MASK)) && (state.flag & PATH_RAY_CAMERA)) { + if(((sd.flag & SD_HOLDOUT) || + (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) && + (state.flag & PATH_RAY_CAMERA)) + { if(kernel_data.background.transparent) { float3 holdout_weight; - - if(sd.flag & SD_OBJECT_HOLDOUT_MASK) + if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) { holdout_weight = make_float3(1.0f, 1.0f, 1.0f); - else + } + else { holdout_weight = shader_holdout_eval(kg, &sd); - + } /* any throughput is ok, should all be identical here */ L_transparent += average(holdout_weight*throughput); } - if(sd.flag & SD_OBJECT_HOLDOUT_MASK) + if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) { break; + } } #endif /* __HOLDOUT__ */ diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index 4ec0ac8e8c9..ff2b828795d 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -167,8 +167,9 @@ ccl_device void kernel_branched_path_subsurface_scatter(KernelGlobals *kg, true); #ifdef __VOLUME__ Ray volume_ray = *ray; - bool need_update_volume_stack = kernel_data.integrator.use_volumes && - ccl_fetch(sd, flag) & SD_OBJECT_INTERSECTS_VOLUME; + bool need_update_volume_stack = + kernel_data.integrator.use_volumes && + ccl_fetch(sd, object_flag) & SD_OBJECT_INTERSECTS_VOLUME; #endif /* __VOLUME__ */ /* compute lighting with the BSDF closure */ @@ -473,21 +474,21 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* holdout */ #ifdef __HOLDOUT__ - if(sd.flag & (SD_HOLDOUT|SD_OBJECT_HOLDOUT_MASK)) { + if((sd.flag & SD_HOLDOUT) || (sd.object_flag & SD_OBJECT_HOLDOUT_MASK)) { if(kernel_data.background.transparent) { float3 holdout_weight; - - if(sd.flag & SD_OBJECT_HOLDOUT_MASK) + if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) { holdout_weight = make_float3(1.0f, 1.0f, 1.0f); - else + } + else { holdout_weight = shader_holdout_eval(kg, &sd); - + } /* any throughput is ok, should all be identical here */ L_transparent += average(holdout_weight*throughput); } - - if(sd.flag & SD_OBJECT_HOLDOUT_MASK) + if(sd.object_flag & SD_OBJECT_HOLDOUT_MASK) { break; + } } #endif /* __HOLDOUT__ */ diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index d7a9167aaf8..d0826e5e879 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -38,7 +38,7 @@ CCL_NAMESPACE_BEGIN #ifdef __OBJECT_MOTION__ ccl_device void shader_setup_object_transforms(KernelGlobals *kg, ShaderData *sd, float time) { - if(ccl_fetch(sd, flag) & SD_OBJECT_MOTION) { + if(ccl_fetch(sd, object_flag) & SD_OBJECT_MOTION) { ccl_fetch(sd, ob_tfm) = object_fetch_transform_motion(kg, ccl_fetch(sd, object), time); ccl_fetch(sd, ob_itfm) = transform_quick_inverse(ccl_fetch(sd, ob_tfm)); } @@ -59,7 +59,9 @@ ccl_device_noinline void shader_setup_from_ray(KernelGlobals *kg, #endif ccl_fetch(sd, type) = isect->type; - ccl_fetch(sd, flag) = kernel_tex_fetch(__object_flag, ccl_fetch(sd, object)); + ccl_fetch(sd, flag) = 0; + ccl_fetch(sd, object_flag) = kernel_tex_fetch(__object_flag, + ccl_fetch(sd, object)); /* matrices and time */ #ifdef __OBJECT_MOTION__ @@ -160,10 +162,11 @@ void shader_setup_from_subsurface( const Intersection *isect, const Ray *ray) { - bool backfacing = sd->flag & SD_BACKFACING; + const bool backfacing = sd->flag & SD_BACKFACING; /* object, matrices, time, ray_length stay the same */ - sd->flag = kernel_tex_fetch(__object_flag, sd->object); + sd->flag = 0; + sd->object_flag = kernel_tex_fetch(__object_flag, sd->object); sd->prim = kernel_tex_fetch(__prim_index, isect->prim); sd->type = isect->type; @@ -271,8 +274,10 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, ccl_fetch(sd, ray_length) = t; ccl_fetch(sd, flag) = kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*SHADER_SIZE); + ccl_fetch(sd, object_flag) = 0; if(ccl_fetch(sd, object) != OBJECT_NONE) { - ccl_fetch(sd, flag) |= kernel_tex_fetch(__object_flag, ccl_fetch(sd, object)); + ccl_fetch(sd, object_flag) |= kernel_tex_fetch(__object_flag, + ccl_fetch(sd, object)); #ifdef __OBJECT_MOTION__ shader_setup_object_transforms(kg, sd, time); @@ -298,7 +303,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, ccl_fetch(sd, N) = triangle_smooth_normal(kg, ccl_fetch(sd, prim), ccl_fetch(sd, u), ccl_fetch(sd, v)); #ifdef __INSTANCING__ - if(!(ccl_fetch(sd, flag) & SD_OBJECT_TRANSFORM_APPLIED)) { + if(!(ccl_fetch(sd, object_flag) & SD_OBJECT_TRANSFORM_APPLIED)) { object_normal_transform_auto(kg, sd, &ccl_fetch(sd, N)); } #endif @@ -309,7 +314,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals *kg, triangle_dPdudv(kg, ccl_fetch(sd, prim), &ccl_fetch(sd, dPdu), &ccl_fetch(sd, dPdv)); # ifdef __INSTANCING__ - if(!(ccl_fetch(sd, flag) & SD_OBJECT_TRANSFORM_APPLIED)) { + if(!(ccl_fetch(sd, object_flag) & SD_OBJECT_TRANSFORM_APPLIED)) { object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdu)); object_dir_transform_auto(kg, sd, &ccl_fetch(sd, dPdv)); } @@ -379,6 +384,7 @@ ccl_device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderDat ccl_fetch(sd, I) = -ray->D; ccl_fetch(sd, shader) = kernel_data.background.surface_shader; ccl_fetch(sd, flag) = kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*SHADER_SIZE); + ccl_fetch(sd, object_flag) = 0; #ifdef __OBJECT_MOTION__ ccl_fetch(sd, time) = ray->time; #endif @@ -420,6 +426,7 @@ ccl_device_inline void shader_setup_from_volume(KernelGlobals *kg, ShaderData *s sd->I = -ray->D; sd->shader = SHADER_NONE; sd->flag = 0; + sd->object_flag = 0; #ifdef __OBJECT_MOTION__ sd->time = ray->time; #endif @@ -1027,6 +1034,7 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg, sd->num_closure = 0; sd->num_closure_extra = 0; sd->flag = 0; + sd->object_flag = 0; for(int i = 0; stack[i].shader != SHADER_NONE; i++) { /* setup shaderdata from stack. it's mostly setup already in @@ -1034,11 +1042,12 @@ ccl_device_inline void shader_eval_volume(KernelGlobals *kg, sd->object = stack[i].object; sd->shader = stack[i].shader; - sd->flag &= ~(SD_SHADER_FLAGS|SD_OBJECT_FLAGS); + sd->flag &= ~SD_SHADER_FLAGS; sd->flag |= kernel_tex_fetch(__shader_flag, (sd->shader & SHADER_MASK)*SHADER_SIZE); + sd->object_flag &= ~SD_OBJECT_FLAGS; if(sd->object != OBJECT_NONE) { - sd->flag |= kernel_tex_fetch(__object_flag, sd->object); + sd->object_flag |= kernel_tex_fetch(__object_flag, sd->object); #ifdef __OBJECT_MOTION__ /* todo: this is inefficient for motion blur, we should be diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index a826cda702b..b7af90cd739 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -692,56 +692,108 @@ typedef enum ShaderContext { /* Shader Data * * Main shader state at a point on the surface or in a volume. All coordinates - * are in world space. */ + * are in world space. + */ enum ShaderDataFlag { - /* runtime flags */ - SD_BACKFACING = (1 << 0), /* backside of surface? */ - SD_EMISSION = (1 << 1), /* have emissive closure? */ - SD_BSDF = (1 << 2), /* have bsdf closure? */ - SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */ - SD_BSSRDF = (1 << 4), /* have bssrdf */ - SD_HOLDOUT = (1 << 5), /* have holdout closure? */ - SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */ - SD_SCATTER = (1 << 7), /* have volume phase closure? */ - SD_AO = (1 << 8), /* have ao closure? */ - SD_TRANSPARENT = (1 << 9), /* have transparent closure? */ + /* Runtime flags. */ + + /* Set when ray hits backside of surface. */ + SD_BACKFACING = (1 << 0), + /* Shader has emissive closure. */ + SD_EMISSION = (1 << 1), + /* Shader has BSDF closure. */ + SD_BSDF = (1 << 2), + /* Shader has non-singular BSDF closure. */ + SD_BSDF_HAS_EVAL = (1 << 3), + /* Shader has BSSRDF closure. */ + SD_BSSRDF = (1 << 4), + /* Shader has holdout closure. */ + SD_HOLDOUT = (1 << 5), + /* Shader has volume absorption closure. */ + SD_ABSORPTION = (1 << 6), + /* Shader has have volume phase (scatter) closure. */ + SD_SCATTER = (1 << 7), + /* Shader has AO closure. */ + SD_AO = (1 << 8), + /* Shader has transparent closure. */ + SD_TRANSPARENT = (1 << 9), + /* BSDF requires LCG for evaluation. */ SD_BSDF_NEEDS_LCG = (1 << 10), - SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF| - SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO| + SD_CLOSURE_FLAGS = (SD_EMISSION | + SD_BSDF | + SD_BSDF_HAS_EVAL | + SD_BSSRDF | + SD_HOLDOUT | + SD_ABSORPTION | + SD_SCATTER | + SD_AO | SD_BSDF_NEEDS_LCG), - /* shader flags */ - SD_USE_MIS = (1 << 12), /* direct light sample */ - SD_HAS_TRANSPARENT_SHADOW = (1 << 13), /* has transparent shadow */ - SD_HAS_VOLUME = (1 << 14), /* has volume shader */ - SD_HAS_ONLY_VOLUME = (1 << 15), /* has only volume shader, no surface */ - SD_HETEROGENEOUS_VOLUME = (1 << 16), /* has heterogeneous volume */ - SD_HAS_BSSRDF_BUMP = (1 << 17), /* bssrdf normal uses bump */ - SD_VOLUME_EQUIANGULAR = (1 << 18), /* use equiangular sampling */ - SD_VOLUME_MIS = (1 << 19), /* use multiple importance sampling */ - SD_VOLUME_CUBIC = (1 << 20), /* use cubic interpolation for voxels */ - SD_HAS_BUMP = (1 << 21), /* has data connected to the displacement input */ - SD_HAS_DISPLACEMENT = (1 << 22), /* has true displacement */ - SD_HAS_CONSTANT_EMISSION = (1 << 23), /* has constant emission (value stored in __shader_flag) */ + /* Shader flags. */ - SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME| - SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME| - SD_HAS_BSSRDF_BUMP|SD_VOLUME_EQUIANGULAR|SD_VOLUME_MIS| - SD_VOLUME_CUBIC|SD_HAS_BUMP|SD_HAS_DISPLACEMENT|SD_HAS_CONSTANT_EMISSION), + /* direct light sample */ + SD_USE_MIS = (1 << 16), + /* Has transparent shadow. */ + SD_HAS_TRANSPARENT_SHADOW = (1 << 17), + /* Has volume shader. */ + SD_HAS_VOLUME = (1 << 18), + /* Has only volume shader, no surface. */ + SD_HAS_ONLY_VOLUME = (1 << 19), + /* Has heterogeneous volume. */ + SD_HETEROGENEOUS_VOLUME = (1 << 20), + /* BSSRDF normal uses bump. */ + SD_HAS_BSSRDF_BUMP = (1 << 21), + /* Use equiangular volume sampling */ + SD_VOLUME_EQUIANGULAR = (1 << 22), + /* Use multiple importance volume sampling. */ + SD_VOLUME_MIS = (1 << 23), + /* Use cubic interpolation for voxels. */ + SD_VOLUME_CUBIC = (1 << 24), + /* Has data connected to the displacement input. */ + SD_HAS_BUMP = (1 << 25), + /* Has true displacement. */ + SD_HAS_DISPLACEMENT = (1 << 26), + /* Has constant emission (value stored in __shader_flag) */ + SD_HAS_CONSTANT_EMISSION = (1 << 27), - /* object flags */ - SD_OBJECT_HOLDOUT_MASK = (1 << 24), /* holdout for camera rays */ - SD_OBJECT_MOTION = (1 << 25), /* has object motion blur */ - SD_OBJECT_TRANSFORM_APPLIED = (1 << 26), /* vertices have transform applied */ - SD_OBJECT_NEGATIVE_SCALE_APPLIED = (1 << 27), /* vertices have negative scale applied */ - SD_OBJECT_HAS_VOLUME = (1 << 28), /* object has a volume shader */ - SD_OBJECT_INTERSECTS_VOLUME = (1 << 29), /* object intersects AABB of an object with volume shader */ - SD_OBJECT_HAS_VERTEX_MOTION = (1 << 30), /* has position for motion vertices */ + SD_SHADER_FLAGS = (SD_USE_MIS | + SD_HAS_TRANSPARENT_SHADOW | + SD_HAS_VOLUME | + SD_HAS_ONLY_VOLUME | + SD_HETEROGENEOUS_VOLUME| + SD_HAS_BSSRDF_BUMP | + SD_VOLUME_EQUIANGULAR | + SD_VOLUME_MIS | + SD_VOLUME_CUBIC | + SD_HAS_BUMP | + SD_HAS_DISPLACEMENT | + SD_HAS_CONSTANT_EMISSION) +}; - SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_OBJECT_TRANSFORM_APPLIED| - SD_OBJECT_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME| + /* Object flags. */ +enum ShaderDataObjectFlag { + /* Holdout for camera rays. */ + SD_OBJECT_HOLDOUT_MASK = (1 << 0), + /* Has object motion blur. */ + SD_OBJECT_MOTION = (1 << 1), + /* Vertices have transform applied. */ + SD_OBJECT_TRANSFORM_APPLIED = (1 << 2), + /* Vertices have negative scale applied. */ + SD_OBJECT_NEGATIVE_SCALE_APPLIED = (1 << 3), + /* Object has a volume shader. */ + SD_OBJECT_HAS_VOLUME = (1 << 4), + /* Object intersects AABB of an object with volume shader. */ + SD_OBJECT_INTERSECTS_VOLUME = (1 << 5), + /* Has position for motion vertices. */ + SD_OBJECT_HAS_VERTEX_MOTION = (1 << 6), + + SD_OBJECT_FLAGS = (SD_OBJECT_HOLDOUT_MASK | + SD_OBJECT_MOTION | + SD_OBJECT_TRANSFORM_APPLIED | + SD_OBJECT_NEGATIVE_SCALE_APPLIED | + SD_OBJECT_HAS_VOLUME | SD_OBJECT_INTERSECTS_VOLUME) }; @@ -780,6 +832,8 @@ typedef ccl_addr_space struct ShaderData { ccl_soa_member(int, shader); /* booleans describing shader, see ShaderDataFlag */ ccl_soa_member(int, flag); + /* booleans describing object of the shader, see ShaderDataObjectFlag */ + ccl_soa_member(int, object_flag); /* primitive id if there is one, ~0 otherwise */ ccl_soa_member(int, prim); diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index 2c8acb4e902..58bbdc33920 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -712,7 +712,7 @@ bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderD else motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P); - if(!(sd->flag & SD_OBJECT_TRANSFORM_APPLIED)) { + if(!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { object_position_transform(kg, sd, &P[0]); object_position_transform(kg, sd, &P[1]); object_position_transform(kg, sd, &P[2]); diff --git a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h index fe5899de254..5d951b972ed 100644 --- a/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h +++ b/intern/cycles/kernel/split/kernel_holdout_emission_blurring_pathtermination_ao.h @@ -137,22 +137,22 @@ ccl_device void kernel_holdout_emission_blurring_pathtermination_ao( /* holdout */ #ifdef __HOLDOUT__ - if((ccl_fetch(sd, flag) & (SD_HOLDOUT|SD_OBJECT_HOLDOUT_MASK)) && + if(((ccl_fetch(sd, flag) & SD_HOLDOUT) || + (ccl_fetch(sd, object_flag) & SD_OBJECT_HOLDOUT_MASK)) && (state->flag & PATH_RAY_CAMERA)) { if(kernel_data.background.transparent) { float3 holdout_weight; - - if(ccl_fetch(sd, flag) & SD_OBJECT_HOLDOUT_MASK) + if(ccl_fetch(sd, object_flag) & SD_OBJECT_HOLDOUT_MASK) { holdout_weight = make_float3(1.0f, 1.0f, 1.0f); - else + } + else { holdout_weight = shader_holdout_eval(kg, sd); - + } /* any throughput is ok, should all be identical here */ L_transparent_coop[ray_index] += average(holdout_weight*throughput); } - - if(ccl_fetch(sd, flag) & SD_OBJECT_HOLDOUT_MASK) { + if(ccl_fetch(sd, object_flag) & SD_OBJECT_HOLDOUT_MASK) { ASSIGN_RAY_STATE(ray_state, ray_index, RAY_UPDATE_BUFFER); *enqueue_flag = 1; } diff --git a/intern/cycles/kernel/svm/svm_wireframe.h b/intern/cycles/kernel/svm/svm_wireframe.h index 29af11c36b6..87e40791333 100644 --- a/intern/cycles/kernel/svm/svm_wireframe.h +++ b/intern/cycles/kernel/svm/svm_wireframe.h @@ -57,7 +57,7 @@ ccl_device_inline float wireframe(KernelGlobals *kg, else motion_triangle_vertices(kg, ccl_fetch(sd, object), ccl_fetch(sd, prim), ccl_fetch(sd, time), Co); - if(!(ccl_fetch(sd, flag) & SD_OBJECT_TRANSFORM_APPLIED)) { + if(!(ccl_fetch(sd, object_flag) & SD_OBJECT_TRANSFORM_APPLIED)) { object_position_transform(kg, sd, &Co[0]); object_position_transform(kg, sd, &Co[1]); object_position_transform(kg, sd, &Co[2]); From 39577403d3c421f51735613810ffcb4acc1e3894 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Mon, 23 Jan 2017 18:08:41 +0100 Subject: [PATCH 587/590] Fix compilation error with legacy depsgraph disabled --- source/blender/modifiers/CMakeLists.txt | 4 ++++ source/blender/modifiers/intern/MOD_cloth.c | 8 +++++++- source/blender/modifiers/intern/MOD_dynamicpaint.c | 7 +++++++ source/blender/modifiers/intern/MOD_smoke.c | 8 +++++++- source/blender/modifiers/intern/MOD_softbody.c | 7 +++++++ 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index b8ebb375a48..bacfc177432 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -113,6 +113,10 @@ set(SRC intern/MOD_weightvg_util.h ) +if(WITH_LEGACY_DEPSGRAPH) + add_definitions(-DWITH_LEGACY_DEPSGRAPH) +endif() + if(WITH_ALEMBIC) add_definitions(-DWITH_ALEMBIC) list(APPEND INC diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index d15a6fcb1c8..ac75b4dbee9 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -125,9 +125,15 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, if (clmd) { /* Actual code uses get_collisionobjects */ +#ifdef WITH_LEGACY_DEPSGRAPH dag_add_collision_relations(forest, scene, ob, obNode, clmd->coll_parms->group, ob->lay|scene->lay, eModifierType_Collision, NULL, true, "Cloth Collision"); - dag_add_forcefield_relations(forest, scene, ob, obNode, clmd->sim_parms->effector_weights, true, 0, "Cloth Field"); +#else + (void)forest; + (void)scene; + (void)ob; + (void)obNode; +#endif } } diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c index bde20e56748..b49a407da78 100644 --- a/source/blender/modifiers/intern/MOD_dynamicpaint.c +++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c @@ -129,6 +129,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, /* add relation from canvases to all brush objects */ if (pmd && pmd->canvas) { +#ifdef WITH_LEGACY_DEPSGRAPH for (DynamicPaintSurface *surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { if (surface->effect & MOD_DPAINT_EFFECT_DO_DRIP) { dag_add_forcefield_relations(forest, scene, ob, obNode, surface->effector_weights, true, 0, "Dynamic Paint Field"); @@ -137,6 +138,12 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, /* Actual code uses custom loop over group/scene without layer checks in dynamicPaint_doStep */ dag_add_collision_relations(forest, scene, ob, obNode, surface->brush_group, -1, eModifierType_DynamicPaint, is_brush_cb, false, "Dynamic Paint Brush"); } +#else + (void)forest; + (void)scene; + (void)ob; + (void)obNode; +#endif } } diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c index f04d7432a8f..a7b23ae2403 100644 --- a/source/blender/modifiers/intern/MOD_smoke.c +++ b/source/blender/modifiers/intern/MOD_smoke.c @@ -138,10 +138,16 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) { /* Actual code uses get_collisionobjects */ +#ifdef WITH_LEGACY_DEPSGRAPH dag_add_collision_relations(forest, scene, ob, obNode, smd->domain->fluid_group, ob->lay|scene->lay, eModifierType_Smoke, is_flow_cb, true, "Smoke Flow"); dag_add_collision_relations(forest, scene, ob, obNode, smd->domain->coll_group, ob->lay|scene->lay, eModifierType_Smoke, is_coll_cb, true, "Smoke Coll"); - dag_add_forcefield_relations(forest, scene, ob, obNode, smd->domain->effector_weights, true, PFIELD_SMOKEFLOW, "Smoke Force Field"); +#else + (void)forest; + (void)scene; + (void)ob; + (void)obNode; +#endif } } diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index 17adc7f1520..a0bbe5da04a 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -67,10 +67,17 @@ static void updateDepgraph(ModifierData *UNUSED(md), DagForest *forest, Scene *scene, Object *ob, DagNode *obNode) { if (ob->soft) { +#ifdef WITH_LEGACY_DEPSGRAPH /* Actual code uses ccd_build_deflector_hash */ dag_add_collision_relations(forest, scene, ob, obNode, ob->soft->collision_group, ob->lay, eModifierType_Collision, NULL, false, "Softbody Collision"); dag_add_forcefield_relations(forest, scene, ob, obNode, ob->soft->effector_weights, true, 0, "Softbody Field"); +#else + (void)forest; + (void)scene; + (void)ob; + (void)obNode; +#endif } } From d5c7d22bc2c845a63aa1c9368c854949dcc11bf7 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Mon, 23 Jan 2017 21:10:56 +0100 Subject: [PATCH 588/590] Update script generating/uploading py API doc to new addresses (docs.blender.org). --- doc/python_api/sphinx_doc_update.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/python_api/sphinx_doc_update.py b/doc/python_api/sphinx_doc_update.py index c7f0367a2a0..3d48c1145e1 100755 --- a/doc/python_api/sphinx_doc_update.py +++ b/doc/python_api/sphinx_doc_update.py @@ -41,9 +41,9 @@ import tempfile import zipfile -DEFAULT_RSYNC_SERVER = "www.blender.org" +DEFAULT_RSYNC_SERVER = "docs.blender.org" DEFAULT_RSYNC_ROOT = "/api/" -DEFAULT_SYMLINK_ROOT = "/data/www/vhosts/www.blender.org/api" +DEFAULT_SYMLINK_ROOT = "/data/www/vhosts/docs.blender.org/api" def argparse_create(): From e5d8c2a67f51261b7865a662d95fb5cb248c2959 Mon Sep 17 00:00:00 2001 From: Aaron Carlisle Date: Mon, 23 Jan 2017 19:09:45 -0500 Subject: [PATCH 589/590] Use new manual URL --- doc/python_api/sphinx_doc_gen.py | 10 +++------- intern/cycles/blender/addon/__init__.py | 2 +- intern/cycles/device/device_cuda.cpp | 2 +- release/datafiles/locale | 2 +- release/scripts/addons | 2 +- release/scripts/addons_contrib | 2 +- release/scripts/startup/bl_ui/space_info.py | 2 +- release/scripts/templates_py/addon_add_object.py | 2 +- release/text/readme.html | 2 +- source/blender/makesrna/intern/rna_userdef.c | 2 +- source/blender/windowmanager/intern/wm_operators.c | 3 +-- source/creator/creator_args.c | 2 +- source/tools | 2 +- 13 files changed, 15 insertions(+), 20 deletions(-) diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index e8154f9ea66..ec3131ca19e 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1632,13 +1632,9 @@ def write_sphinx_conf_py(basepath): file = open(filepath, "w", encoding="utf-8") fw = file.write - fw("import sys, os\n") - fw("\n") - fw("extensions = ['sphinx.ext.intersphinx']\n") - fw("\n") - fw("intersphinx_mapping = {'blender_manual': ('https://www.blender.org/manual/', None)}\n") - fw("\n") - + fw("import sys, os\n\n") + fw("extensions = ['sphinx.ext.intersphinx']\n\n") + fw("intersphinx_mapping = {'blender_manual': ('https://docs.blender.org/manual/en/dev/', None)}\n\n") fw("project = 'Blender'\n") # fw("master_doc = 'index'\n") fw("copyright = u'Blender Foundation'\n") diff --git a/intern/cycles/blender/addon/__init__.py b/intern/cycles/blender/addon/__init__.py index 1fc3758ad4d..235d19e91e8 100644 --- a/intern/cycles/blender/addon/__init__.py +++ b/intern/cycles/blender/addon/__init__.py @@ -23,7 +23,7 @@ bl_info = { "location": "Info header, render engine menu", "description": "Cycles Render Engine integration", "warning": "", - "wiki_url": "https://www.blender.org/manual/render/cycles/index.html", + "wiki_url": "https://docs.blender.org/manual/en/dev/render/cycles/", "tracker_url": "", "support": 'OFFICIAL', "category": "Render"} diff --git a/intern/cycles/device/device_cuda.cpp b/intern/cycles/device/device_cuda.cpp index 233f94be1bf..dafac6dfcb3 100644 --- a/intern/cycles/device/device_cuda.cpp +++ b/intern/cycles/device/device_cuda.cpp @@ -130,7 +130,7 @@ public: { if(first_error) { fprintf(stderr, "\nRefer to the Cycles GPU rendering documentation for possible solutions:\n"); - fprintf(stderr, "http://www.blender.org/manual/render/cycles/gpu_rendering.html\n\n"); + fprintf(stderr, "https://docs.blender.org/manual/en/dev/render/cycles/gpu_rendering.html\n\n"); first_error = false; } } diff --git a/release/datafiles/locale b/release/datafiles/locale index dc166057192..88158191df4 160000 --- a/release/datafiles/locale +++ b/release/datafiles/locale @@ -1 +1 @@ -Subproject commit dc166057192ea882b5cc70484d4c8bacd7cb41b4 +Subproject commit 88158191df4da2109bbfd9b0816d891bbc7fc78b diff --git a/release/scripts/addons b/release/scripts/addons index 06dad53c808..a746a84f8aa 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 06dad53c80801e0e0919f086040e3d9c31bbd0a1 +Subproject commit a746a84f8aaf3a4843eb3f4ce3f5a0464872077a diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib index 04af69be141..029103debce 160000 --- a/release/scripts/addons_contrib +++ b/release/scripts/addons_contrib @@ -1 +1 @@ -Subproject commit 04af69be141a5757fc60b44cc1a5b72db524af30 +Subproject commit 029103debce43110f93295d7633931ec100d3017 diff --git a/release/scripts/startup/bl_ui/space_info.py b/release/scripts/startup/bl_ui/space_info.py index 780dc4cf982..2a085b8aada 100644 --- a/release/scripts/startup/bl_ui/space_info.py +++ b/release/scripts/startup/bl_ui/space_info.py @@ -306,7 +306,7 @@ class INFO_MT_help(Menu): layout.operator( "wm.url_open", text="Manual", icon='HELP', - ).url = "https://www.blender.org/manual" + ).url = "https://docs.blender.org/manual/en/dev/" layout.operator( "wm.url_open", text="Release Log", icon='URL', ).url = "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d" % bpy.app.version[:2] diff --git a/release/scripts/templates_py/addon_add_object.py b/release/scripts/templates_py/addon_add_object.py index d294838d3a2..56e6e79b94f 100644 --- a/release/scripts/templates_py/addon_add_object.py +++ b/release/scripts/templates_py/addon_add_object.py @@ -69,7 +69,7 @@ def add_object_button(self, context): # This allows you to right click on a button and link to the manual def add_object_manual_map(): - url_manual_prefix = "https://www.blender.org/manual/" + url_manual_prefix = "https://docs.blender.org/manual/en/dev/" url_manual_mapping = ( ("bpy.ops.mesh.add_object", "editors/3dview/object"), ) diff --git a/release/text/readme.html b/release/text/readme.html index 8e08a8ba027..45bff37b025 100644 --- a/release/text/readme.html +++ b/release/text/readme.html @@ -104,7 +104,7 @@ Full release log wiki.blender.org/index.php/Dev:Ref/Release_Notes/BLENDER_VERSION
    Tutorials www.blender.org/support/tutorials/
    -Manual www.blender.org/manual
    +Manual https://docs.blender.org/manual/en/dev/
    User Forum www.blenderartists.org
    IRC diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index e68e67586e9..0eab38faca8 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -3937,7 +3937,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop = RNA_def_property(srna, "dpi", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "dpi"); - RNA_def_property_range(prop, 48, 144); + RNA_def_property_range(prop, 16, 256); RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display"); RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index b9fd4d2e762..ef69ed31ef6 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1846,7 +1846,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar BLENDER_VERSION / 100, BLENDER_VERSION % 100); uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", url); uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url", - "http://www.blender.org/manual"); + "https://docs.blender.org/manual/en/dev/"); uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org"); if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) { BLI_snprintf(url, sizeof(url), "http://www.blender.org/documentation/blender_python_api_%d_%d" @@ -4558,4 +4558,3 @@ EnumPropertyItem *RNA_mask_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA { return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->mask.first : NULL, true); } - diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 4eb72fb1619..27579e58dba 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -438,7 +438,7 @@ static void arg_py_context_restore( * see: `doc/manpage/blender.1.py` * - Parsed and extracted for the manual, * which converts our ad-hoc formatting to reStructuredText. - * see: http://www.blender.org/manual/advanced/command_line.html + * see: https://docs.blender.org/manual/en/dev/advanced/command_line.html * * \{ */ diff --git a/source/tools b/source/tools index 896c5f78952..6bbb68073bf 160000 --- a/source/tools +++ b/source/tools @@ -1 +1 @@ -Subproject commit 896c5f78952adb2d091d28c65086d46992dabdac +Subproject commit 6bbb68073bfa11e94bb0b3623db38f847037add7 From 520afa2962f1fc97a04f81a5f6a423dd71cf30f3 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Tue, 24 Jan 2017 09:15:41 +0100 Subject: [PATCH 590/590] GPencil: Fix unreported animation data missing when change palette name When a palette was renamed, the animation data was not changed. This fix is related to commit 196520fe7d81 --- source/blender/makesrna/intern/rna_gpencil.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index 25cd7265c3e..6e0d6ad2bcd 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -784,11 +784,16 @@ static void rna_GPencilPalette_info_set(PointerRNA *ptr, const char *value) bGPdata *gpd = ptr->id.data; bGPDpalette *palette = ptr->data; + char oldname[64] = ""; + BLI_strncpy(oldname, palette->info, sizeof(oldname)); + /* copy the new name into the name slot */ BLI_strncpy_utf8(palette->info, value, sizeof(palette->info)); BLI_uniquename(&gpd->palettes, palette, DATA_("GP_Palette"), '.', offsetof(bGPDpalette, info), sizeof(palette->info)); + /* now fix animation paths */ + BKE_animdata_fix_paths_rename_all(&gpd->id, "palettes", oldname, palette->info); } static char *rna_GPencilPalette_path(PointerRNA *ptr)