diff --git a/CMakeLists.txt b/CMakeLists.txt index bfff781e922c07b8ca41344ff6306667f27b75b8..d45cfefcb78c03565f40b365d247888a5fb8dcf8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1461,6 +1461,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC") "/wd4267" # conversion from 'size_t' to 'type', possible loss of data "/wd4305" # truncation from 'type1' to 'type2' "/wd4800" # forcing value to bool 'true' or 'false' + "/wd4828" # The file contains a character that is illegal # errors: "/we4013" # 'function' undefined; assuming extern returning int "/we4133" # incompatible pointer types diff --git a/build_files/build_environment/cmake/boost.cmake b/build_files/build_environment/cmake/boost.cmake index 2c6bf195e07894217f76da7bac7116e47ea5dab2..46840b7ead457a414d18054f258683e7e4552e6f 100644 --- a/build_files/build_environment/cmake/boost.cmake +++ b/build_files/build_environment/cmake/boost.cmake @@ -53,17 +53,20 @@ if(WIN32) if(BUILD_MODE STREQUAL Release) set(BOOST_HARVEST_CMD ${BOOST_HARVEST_CMD} && ${CMAKE_COMMAND} -E copy_directory ${LIBDIR}/boost/include/boost-1_60/ ${HARVEST_TARGET}/boost/include/) endif() + set(BOOST_PATCH_COMMAND ${PATCH_CMD} --verbose -p 1 -N -d ${BUILD_DIR}/boost/src/external_boost < ${PATCH_DIR}/boost.diff) elseif(APPLE) set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh) set(BOOST_BUILD_COMMAND ./bjam) set(BOOST_BUILD_OPTIONS toolset=clang cxxflags=${PLATFORM_CXXFLAGS} linkflags=${PLATFORM_LDFLAGS} --disable-icu boost.locale.icu=off) set(BOOST_HARVEST_CMD echo .) + set(BOOST_PATCH_COMMAND echo .) else() set(BOOST_HARVEST_CMD echo .) set(BOOST_CONFIGURE_COMMAND ./bootstrap.sh) set(BOOST_BUILD_COMMAND ./bjam) set(BOOST_BUILD_OPTIONS cxxflags=${PLATFORM_CXXFLAGS} --disable-icu boost.locale.icu=off) + set(BOOST_PATCH_COMMAND echo .) endif() set(BOOST_OPTIONS @@ -96,6 +99,7 @@ ExternalProject_Add(external_boost URL_HASH MD5=${BOOST_MD5} PREFIX ${BUILD_DIR}/boost UPDATE_COMMAND "" + PATCH_COMMAND ${BOOST_PATCH_COMMAND} CONFIGURE_COMMAND ${BOOST_CONFIGURE_COMMAND} BUILD_COMMAND ${BOOST_BUILD_COMMAND} ${BOOST_BUILD_OPTIONS} -j${MAKE_THREADS} architecture=x86 address-model=${BOOST_ADDRESS_MODEL} variant=${BOOST_BUILD_TYPE} link=static threading=multi ${BOOST_OPTIONS} --prefix=${LIBDIR}/boost install BUILD_IN_SOURCE 1 diff --git a/build_files/build_environment/patches/boost.diff b/build_files/build_environment/patches/boost.diff new file mode 100644 index 0000000000000000000000000000000000000000..ea3ec035518d79a620fbd3629b1b93fb67914baa --- /dev/null +++ b/build_files/build_environment/patches/boost.diff @@ -0,0 +1,15 @@ +--- a/boost/config/compiler/visualc.hpp 2015-12-08 11:55:19 -0700 ++++ b/boost/config/compiler/visualc.hpp 2018-03-17 10:29:52 -0600 +@@ -287,12 +287,3 @@ + # define BOOST_COMPILER "Microsoft Visual C++ version " BOOST_STRINGIZE(BOOST_COMPILER_VERSION) + #endif + +-// +-// last known and checked version is 19.00.23026 (VC++ 2015 RTM): +-#if (_MSC_VER > 1900) +-# if defined(BOOST_ASSERT_CONFIG) +-# error "Unknown compiler version - please run the configure tests and report the results" +-# else +-# pragma message("Unknown compiler version - please run the configure tests and report the results") +-# endif +-#endif diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake index 7db26c3f7c0d6c99b8d1051606c24a087980279f..1a5e6a3158ada50f8c71be94f5b5e8a3cc95da8f 100644 --- a/build_files/cmake/config/blender_lite.cmake +++ b/build_files/cmake/config/blender_lite.cmake @@ -9,6 +9,7 @@ set(WITH_INSTALL_PORTABLE ON CACHE BOOL "" FORCE) set(WITH_SYSTEM_GLEW ON CACHE BOOL "" FORCE) set(WITH_ALEMBIC OFF CACHE BOOL "" FORCE) +set(WITH_BOOST OFF CACHE BOOL "" FORCE) set(WITH_BUILDINFO OFF CACHE BOOL "" FORCE) set(WITH_BULLET OFF CACHE BOOL "" FORCE) set(WITH_CODEC_AVI OFF CACHE BOOL "" FORCE) @@ -54,4 +55,3 @@ set(WITH_RAYOPTIMIZATION OFF CACHE BOOL "" FORCE) set(WITH_SDL OFF CACHE BOOL "" FORCE) set(WITH_X11_XINPUT OFF CACHE BOOL "" FORCE) set(WITH_X11_XF86VMODE OFF CACHE BOOL "" FORCE) - diff --git a/doc/python_api/examples/bpy.props.1.py b/doc/python_api/examples/bpy.props.1.py index 5153462893002245435adb2cd50539facc85f6b4..dd3a3ebc4325bcc09bf0ee594ef995696d8dc7ba 100644 --- a/doc/python_api/examples/bpy.props.1.py +++ b/doc/python_api/examples/bpy.props.1.py @@ -2,30 +2,56 @@ Operator Example ++++++++++++++++ -A common use of custom properties is for python based :class:`Operator` classes. +A common use of custom properties is for python based :class:`Operator` +classes. Test this code by running it in the text editor, or by clicking the +button in the 3D Viewport's Tools panel. The latter will show the properties +in the Redo panel and allow you to change them. """ - import bpy -class DialogOperator(bpy.types.Operator): - bl_idname = "object.dialog_operator" +class OBJECT_OT_property_example(bpy.types.Operator): + bl_idname = "object.property_example" bl_label = "Property Example" + bl_options = {'REGISTER', 'UNDO'} my_float = bpy.props.FloatProperty(name="Some Floating Point") my_bool = bpy.props.BoolProperty(name="Toggle Option") my_string = bpy.props.StringProperty(name="String Value") def execute(self, context): - print("Dialog Runs") + self.report({'INFO'}, 'F: %.2f B: %s S: %r' % + (self.my_float, self.my_bool, self.my_string)) + print('My float:', self.my_float) + print('My bool:', self.my_bool) + print('My string:', self.my_string) return {'FINISHED'} - def invoke(self, context, event): - wm = context.window_manager - return wm.invoke_props_dialog(self) - -bpy.utils.register_class(DialogOperator) - -# test call -bpy.ops.object.dialog_operator('INVOKE_DEFAULT') +class OBJECT_PT_property_example(bpy.types.Panel): + bl_idname = "object_PT_property_example" + bl_label = "Property Example" + bl_space_type = 'VIEW_3D' + bl_region_type = 'TOOLS' + bl_category = "Tools" + + def draw(self, context): + # You can set the property values that should be used when the user + # presses the button in the UI. + props = self.layout.operator('object.property_example') + props.my_bool = True + props.my_string = "Shouldn't that be 47?" + + # You can set properties dynamically: + if context.object: + props.my_float = context.object.location.x + else: + props.my_float = 327 + + +bpy.utils.register_class(OBJECT_OT_property_example) +bpy.utils.register_class(OBJECT_PT_property_example) + +# Demo call. Be sure to also test in the 3D Viewport. +bpy.ops.object.property_example(my_float=47, my_bool=True, + my_string="Shouldn't that be 327?") diff --git a/doc/python_api/examples/bpy.props.5.py b/doc/python_api/examples/bpy.props.5.py index 87741cbab8ab3a0b887798c7d9e2bed644013985..a9e79fa0272459692f4550c3c07fa79e8eea1033 100644 --- a/doc/python_api/examples/bpy.props.5.py +++ b/doc/python_api/examples/bpy.props.5.py @@ -1,13 +1,12 @@ """ -Get/Set Example -+++++++++++++++ +Getter/Setter Example ++++++++++++++++++++++ -Get/Set functions can be used for boolean, int, float, string and enum properties. +Getter/setter functions can be used for boolean, int, float, string and enum properties. If these callbacks are defined the property will not be stored in the ID properties -automatically, instead the get/set functions will be called when the property is -read or written from the API. +automatically. Instead, the `get` and `set` functions will be called when the property +is respectively read or written from the API. """ - import bpy @@ -65,25 +64,24 @@ def set_enum(self, value): bpy.types.Scene.test_enum = bpy.props.EnumProperty(items=test_items, get=get_enum, set=set_enum) -# Testing - +# Testing the properties: scene = bpy.context.scene scene.test_float = 12.34 -print(scene.test_float) +print('test_float:', scene.test_float) scene.test_array = (True, False) -print([x for x in scene.test_array]) +print('test_array:', tuple(scene.test_array)) # scene.test_date = "blah" # this would fail, property is read-only -print(scene.test_date) +print('test_date:', scene.test_date) scene.test_enum = 'BLUE' -print(scene.test_enum) - - -# >>> 12.34000015258789 -# >>> [True, False] -# >>> 2013-01-05 16:33:52.135340 -# >>> setting value 3 -# >>> GREEN +print('test_enum:', scene.test_enum) + +# The above outputs: +# test_float: 12.34000015258789 +# test_array: (True, False) +# test_date: 2018-03-14 11:36:53.158653 +# setting value 3 +# test_enum: GREEN diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp index 2d4b0d35e548a87bd45982a7fd55b3bb6fac988e..c682744f5fafb8ca1d92a9ab53d8e749fd99cfde 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -51,6 +51,7 @@ struct Options { SessionParams session_params; bool quiet; bool show_help, interactive, pause; + string output_path; } options; static void session_print(const string& str) @@ -86,6 +87,34 @@ static void session_print_status() session_print(status); } +static bool write_render(const uchar *pixels, int w, int h, int channels) +{ + string msg = string_printf("Writing image %s", options.output_path.c_str()); + session_print(msg); + + ImageOutput *out = ImageOutput::create(options.output_path); + if(!out) { + return false; + } + + ImageSpec spec(w, h, channels, TypeDesc::UINT8); + if(!out->open(options.output_path, spec)) { + return false; + } + + /* conversion for different top/bottom convention */ + out->write_image(TypeDesc::UINT8, + pixels + (h - 1) * w * channels, + AutoStride, + -w * channels, + AutoStride); + + out->close(); + delete out; + + return true; +} + static BufferParams& session_buffer_params() { static BufferParams buffer_params; @@ -120,6 +149,7 @@ static void scene_init() static void session_init() { + options.session_params.write_render_cb = write_render; options.session = new Session(options.session_params); if(options.session_params.background && !options.quiet) @@ -364,7 +394,7 @@ static void options_parse(int argc, const char **argv) "--background", &options.session_params.background, "Render in background, without user interface", "--quiet", &options.quiet, "In background mode, don't print progress messages", "--samples %d", &options.session_params.samples, "Number of samples to render", - "--output %s", &options.session_params.output_path, "File path to write output image", + "--output %s", &options.output_path, "File path to write output image", "--threads %d", &options.session_params.threads, "CPU Rendering Threads", "--width %d", &options.width, "Window width in pixel", "--height %d", &options.height, "Window height in pixel", diff --git a/intern/cycles/render/buffers.cpp b/intern/cycles/render/buffers.cpp index e4931a6317cd1390a2080d9545f4d763957c75d5..91b739741bbdbe18867efc8137a2405a907033cb 100644 --- a/intern/cycles/render/buffers.cpp +++ b/intern/cycles/render/buffers.cpp @@ -21,7 +21,6 @@ #include "util/util_foreach.h" #include "util/util_hash.h" -#include "util/util_image.h" #include "util/util_math.h" #include "util/util_opengl.h" #include "util/util_time.h" @@ -452,37 +451,5 @@ bool DisplayBuffer::draw_ready() return (draw_width != 0 && draw_height != 0); } -void DisplayBuffer::write(const string& filename) -{ - int w = draw_width; - int h = draw_height; - - if(w == 0 || h == 0) - return; - - if(half_float) - return; - - /* read buffer from device */ - uchar4 *pixels = rgba_byte.copy_from_device(0, w, h); - - /* write image */ - ImageOutput *out = ImageOutput::create(filename); - ImageSpec spec(w, h, 4, TypeDesc::UINT8); - - out->open(filename, spec); - - /* conversion for different top/bottom convention */ - out->write_image(TypeDesc::UINT8, - (uchar*)(pixels + (h-1)*w), - AutoStride, - -w*sizeof(uchar4), - AutoStride); - - out->close(); - - delete out; -} - CCL_NAMESPACE_END diff --git a/intern/cycles/render/buffers.h b/intern/cycles/render/buffers.h index 028bfb83735d549062449de8e21f5bf2f768d055..dfc98fe20619e40707a7d89a58728d284819c928 100644 --- a/intern/cycles/render/buffers.h +++ b/intern/cycles/render/buffers.h @@ -113,7 +113,6 @@ public: ~DisplayBuffer(); void reset(BufferParams& params); - void write(const string& filename); void draw_set(int width, int height); void draw(Device *device, const DeviceDrawParams& draw_params); diff --git a/intern/cycles/render/session.cpp b/intern/cycles/render/session.cpp index 4115603855840dbf5d4af04bec7dcf7410393538..bb636dd962abbc5e9c1a26ad700ba14a67367bc5 100644 --- a/intern/cycles/render/session.cpp +++ b/intern/cycles/render/session.cpp @@ -55,7 +55,7 @@ Session::Session(const SessionParams& params_) device = Device::create(params.device, stats, params.background); - if(params.background && params.output_path.empty()) { + if(params.background && !params.write_render_cb) { buffers = NULL; display = NULL; } @@ -101,7 +101,7 @@ Session::~Session() wait(); } - if(!params.output_path.empty()) { + if(params.write_render_cb) { /* tonemap and write out image if requested */ delete display; @@ -109,8 +109,10 @@ Session::~Session() display->reset(buffers->params); tonemap(params.samples); - progress.set_status("Writing Image", params.output_path); - display->write(params.output_path); + int w = display->draw_width; + int h = display->draw_height; + uchar4 *pixels = display->rgba_byte.copy_from_device(0, w, h); + params.write_render_cb((uchar*)pixels, w, h, 4); } /* clean up */ diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h index 8495d95666b772b598a77b4f213c06a371611701..e63cad0d9777c8b6dfebc533efad3df8905b1309 100644 --- a/intern/cycles/render/session.h +++ b/intern/cycles/render/session.h @@ -45,7 +45,6 @@ public: DeviceInfo device; bool background; bool progressive_refine; - string output_path; bool progressive; bool experimental; @@ -71,11 +70,15 @@ public: ShadingSystem shadingsystem; + function<bool(const uchar *pixels, + int width, + int height, + int channels)> write_render_cb; + SessionParams() { background = false; progressive_refine = false; - output_path = ""; progressive = false; experimental = false; @@ -106,7 +109,6 @@ public: { return !(device == params.device && background == params.background && progressive_refine == params.progressive_refine - && output_path == params.output_path /* && samples == params.samples */ && progressive == params.progressive && experimental == params.experimental diff --git a/intern/gawain/gawain/gwn_element.h b/intern/gawain/gawain/gwn_element.h index 3081305769ff40a76dd4d2309cc1a8f9b37c7c17..7a28ab183f82be51c9baec410bab1ccb233292af 100644 --- a/intern/gawain/gawain/gwn_element.h +++ b/intern/gawain/gawain/gwn_element.h @@ -15,6 +15,8 @@ #define GWN_TRACK_INDEX_RANGE 1 +#define GWN_PRIM_RESTART 0xFFFFFFFF + typedef enum { GWN_INDEX_U8, // GL has this, Vulkan does not GWN_INDEX_U16, @@ -30,8 +32,8 @@ typedef struct Gwn_IndexBuf { unsigned max_index; unsigned base_index; #endif - void* data; // NULL indicates data in VRAM (unmapped) or not yet allocated GLuint vbo_id; // 0 indicates not yet sent to VRAM + bool use_prim_restart; } Gwn_IndexBuf; void GWN_indexbuf_use(Gwn_IndexBuf*); @@ -43,17 +45,18 @@ typedef struct Gwn_IndexBufBuilder { unsigned index_ct; Gwn_PrimType prim_type; unsigned* data; + bool use_prim_restart; } Gwn_IndexBufBuilder; -// supported primitives: -// GWN_PRIM_POINTS -// GWN_PRIM_LINES -// GWN_PRIM_TRIS +// supports all primitive types. +void GWN_indexbuf_init_ex(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned index_ct, unsigned vertex_ct, bool use_prim_restart); + +// supports only GWN_PRIM_POINTS, GWN_PRIM_LINES and GWN_PRIM_TRIS. void GWN_indexbuf_init(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned prim_ct, unsigned vertex_ct); -//void GWN_indexbuf_init_custom(Gwn_IndexBufBuilder*, Gwn_PrimType, unsigned index_ct, unsigned vertex_ct); void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder*, unsigned v); +void GWN_indexbuf_add_primitive_restart(Gwn_IndexBufBuilder*); void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder*, unsigned v); void GWN_indexbuf_add_line_verts(Gwn_IndexBufBuilder*, unsigned v1, unsigned v2); diff --git a/intern/gawain/gawain/gwn_vertex_buffer.h b/intern/gawain/gawain/gwn_vertex_buffer.h index 34f12754f40e46a53af7097d531562ca68de0c61..d9faae4f55f794067d91ca6ae568b1fd1758a93b 100644 --- a/intern/gawain/gawain/gwn_vertex_buffer.h +++ b/intern/gawain/gawain/gwn_vertex_buffer.h @@ -22,33 +22,41 @@ // Is Gwn_VertBuf always used as part of a Gwn_Batch? +typedef enum { + // can be extended to support more types + GWN_USAGE_STREAM, + GWN_USAGE_STATIC, + GWN_USAGE_DYNAMIC +} Gwn_UsageType; + typedef struct Gwn_VertBuf { Gwn_VertFormat format; unsigned vertex_ct; - unsigned alloc_ct; // size in vertex of alloced data -#if VRAM_USAGE - unsigned vram_size; // size in byte of data present in the VRAM -#endif - unsigned data_dirty : 1; // does the data has been touched since last transfert - unsigned data_dynamic : 1; // do we keep the RAM allocation for further updates? - unsigned data_resized : 1; // does the data has been resized since last transfert - GLubyte* data; // NULL indicates data in VRAM (unmapped) or not yet allocated - GLuint vbo_id; // 0 indicates not yet sent to VRAM + GLubyte* data; // NULL indicates data in VRAM (unmapped) + GLuint vbo_id; // 0 indicates not yet allocated + Gwn_UsageType usage; // usage hint for GL optimisation } Gwn_VertBuf; -Gwn_VertBuf* GWN_vertbuf_create(void); -Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat*); -Gwn_VertBuf* GWN_vertbuf_create_dynamic_with_format(const Gwn_VertFormat*); +Gwn_VertBuf* GWN_vertbuf_create(Gwn_UsageType); +Gwn_VertBuf* GWN_vertbuf_create_with_format_ex(const Gwn_VertFormat*, Gwn_UsageType); + +#define GWN_vertbuf_create_with_format(format) \ + GWN_vertbuf_create_with_format_ex(format, GWN_USAGE_STATIC) -void GWN_vertbuf_clear(Gwn_VertBuf*); void GWN_vertbuf_discard(Gwn_VertBuf*); -void GWN_vertbuf_init(Gwn_VertBuf*); -void GWN_vertbuf_init_with_format(Gwn_VertBuf*, const Gwn_VertFormat*); +void GWN_vertbuf_init(Gwn_VertBuf*, Gwn_UsageType); +void GWN_vertbuf_init_with_format_ex(Gwn_VertBuf*, const Gwn_VertFormat*, Gwn_UsageType); + +#define GWN_vertbuf_init_with_format(verts, format) \ + GWN_vertbuf_init_with_format_ex(verts, format, GWN_USAGE_STATIC) unsigned GWN_vertbuf_size_get(const Gwn_VertBuf*); void GWN_vertbuf_data_alloc(Gwn_VertBuf*, unsigned v_ct); -void GWN_vertbuf_data_resize(Gwn_VertBuf*, unsigned v_ct); +void GWN_vertbuf_data_resize_ex(Gwn_VertBuf*, unsigned v_ct, bool keep_data); + +#define GWN_vertbuf_data_resize(verts, v_ct) \ + GWN_vertbuf_data_resize_ex(verts, v_ct, true) // The most important set_attrib variant is the untyped one. Get it right first. // It takes a void* so the app developer is responsible for matching their app data types diff --git a/intern/gawain/src/gwn_batch.c b/intern/gawain/src/gwn_batch.c index 9dab2a4d7d9a3e8a7dc0cf3e13a5fd58980f057c..c720ba967b598145c008e0f8b46b22690b533f45 100644 --- a/intern/gawain/src/gwn_batch.c +++ b/intern/gawain/src/gwn_batch.c @@ -211,7 +211,7 @@ static GLuint batch_vao_get(Gwn_Batch *batch) batch->context = GWN_context_active_get(); gwn_context_add_batch(batch->context, batch); } -#if TRUST_NO_ONE && 0 // disabled until we use a separate single context for UI. +#if TRUST_NO_ONE else // Make sure you are not trying to draw this batch in another context. assert(batch->context == GWN_context_active_get()); #endif @@ -489,6 +489,27 @@ void GWN_batch_uniform_4fv(Gwn_Batch* batch, const char* name, const float data[ glUniform4fv(uniform->location, 1, data); } +static void primitive_restart_enable(const Gwn_IndexBuf *el) +{ + // TODO(fclem) Replace by GL_PRIMITIVE_RESTART_FIXED_INDEX when we have ogl 4.3 + glEnable(GL_PRIMITIVE_RESTART); + GLuint restart_index = (GLuint)0xFFFFFFFF; + +#if GWN_TRACK_INDEX_RANGE + if (el->index_type == GWN_INDEX_U8) + restart_index = (GLuint)0xFF; + else if (el->index_type == GWN_INDEX_U16) + restart_index = (GLuint)0xFFFF; +#endif + + glPrimitiveRestartIndex(restart_index); +} + +static void primitive_restart_disable(void) +{ + glDisable(GL_PRIMITIVE_RESTART); +} + void GWN_batch_draw(Gwn_Batch* batch) { #if TRUST_NO_ONE @@ -508,9 +529,10 @@ void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool fo #if TRUST_NO_ONE assert(!(force_instance && (batch->inst == NULL)) || v_count > 0); // we cannot infer length if force_instance #endif + const bool do_instance = (force_instance || batch->inst); // If using offset drawing, use the default VAO and redo bindings. - if (v_first != 0) + if (v_first != 0 && (do_instance || batch->elem)) { glBindVertexArray(GWN_vao_default()); batch_update_program_bindings(batch, v_first); @@ -518,7 +540,7 @@ void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool fo else glBindVertexArray(batch->vao_id); - if (force_instance || batch->inst) + if (do_instance) { // Infer length if vertex count is not given if (v_count == 0) @@ -528,11 +550,16 @@ void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool fo { const Gwn_IndexBuf* el = batch->elem; + if (el->use_prim_restart) + primitive_restart_enable(el); + #if GWN_TRACK_INDEX_RANGE glDrawElementsInstancedBaseVertex(batch->gl_prim_type, el->index_ct, el->gl_index_type, 0, v_count, el->base_index); #else glDrawElementsInstanced(batch->gl_prim_type, el->index_ct, GL_UNSIGNED_INT, 0, v_count); #endif + if (el->use_prim_restart) + primitive_restart_disable(); } else glDrawArraysInstanced(batch->gl_prim_type, 0, batch->verts[0]->vertex_ct, v_count); @@ -547,6 +574,9 @@ void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool fo { const Gwn_IndexBuf* el = batch->elem; + if (el->use_prim_restart) + primitive_restart_enable(el); + #if GWN_TRACK_INDEX_RANGE if (el->base_index) glDrawRangeElementsBaseVertex(batch->gl_prim_type, el->min_index, el->max_index, v_count, el->gl_index_type, 0, el->base_index); @@ -555,13 +585,16 @@ void GWN_batch_draw_range_ex(Gwn_Batch* batch, int v_first, int v_count, bool fo #else glDrawElements(batch->gl_prim_type, v_count, GL_UNSIGNED_INT, 0); #endif + if (el->use_prim_restart) + primitive_restart_disable(); } else - glDrawArrays(batch->gl_prim_type, 0, v_count); + glDrawArrays(batch->gl_prim_type, v_first, v_count); } - - glBindVertexArray(0); + // Performance hog if you are drawing with the same vao multiple time. + // Only activate for debugging. + // glBindVertexArray(0); } // just draw some vertices and let shader place them where we want. @@ -573,5 +606,7 @@ void GWN_draw_primitive(Gwn_PrimType prim_type, int v_count) GLenum type = convert_prim_type_to_gl(prim_type); glDrawArrays(type, 0, v_count); - glBindVertexArray(0); + // Performance hog if you are drawing with the same vao multiple time. + // Only activate for debugging. + // glBindVertexArray(0); } diff --git a/intern/gawain/src/gwn_element.c b/intern/gawain/src/gwn_element.c index f31b64fa2324cf0beda5ca174b3699e5d0b930d7..0b7dc675f87f53ad383b4e19601abbcfbf95032e 100644 --- a/intern/gawain/src/gwn_element.c +++ b/intern/gawain/src/gwn_element.c @@ -39,26 +39,14 @@ unsigned GWN_indexbuf_size_get(const Gwn_IndexBuf* elem) #endif } -static void ElementList_prime(Gwn_IndexBuf* elem) +void GWN_indexbuf_init_ex(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, unsigned index_ct, unsigned vertex_ct, bool use_prim_restart) { - elem->vbo_id = GWN_buf_id_alloc(); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); - // fill with delicious data & send to GPU the first time only - glBufferData(GL_ELEMENT_ARRAY_BUFFER, GWN_indexbuf_size_get(elem), elem->data, GL_STATIC_DRAW); - -#if KEEP_SINGLE_COPY - // now that GL has a copy, discard original - free(elem->data); - elem->data = NULL; -#endif - } - -void GWN_indexbuf_use(Gwn_IndexBuf* elem) - { - if (elem->vbo_id) - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); - else - ElementList_prime(elem); + builder->use_prim_restart = use_prim_restart; + builder->max_allowed_index = vertex_ct - 1; + builder->max_index_ct = index_ct; + builder->index_ct = 0; // start empty + builder->prim_type = prim_type; + builder->data = calloc(builder->max_index_ct, sizeof(unsigned)); } void GWN_indexbuf_init(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, unsigned prim_ct, unsigned vertex_ct) @@ -82,11 +70,7 @@ void GWN_indexbuf_init(Gwn_IndexBufBuilder* builder, Gwn_PrimType prim_type, uns return; } - builder->max_allowed_index = vertex_ct - 1; - builder->max_index_ct = prim_ct * verts_per_prim; - builder->index_ct = 0; // start empty - builder->prim_type = prim_type; - builder->data = calloc(builder->max_index_ct, sizeof(unsigned)); + GWN_indexbuf_init_ex(builder, prim_type, prim_ct * verts_per_prim, vertex_ct, false); } void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder* builder, unsigned v) @@ -100,6 +84,17 @@ void GWN_indexbuf_add_generic_vert(Gwn_IndexBufBuilder* builder, unsigned v) builder->data[builder->index_ct++] = v; } +void GWN_indexbuf_add_primitive_restart(Gwn_IndexBufBuilder* builder) + { +#if TRUST_NO_ONE + assert(builder->data != NULL); + assert(builder->index_ct < builder->max_index_ct); + assert(builder->use_prim_restart); +#endif + + builder->data[builder->index_ct++] = GWN_PRIM_RESTART; + } + void GWN_indexbuf_add_point_vert(Gwn_IndexBufBuilder* builder, unsigned v) { #if TRUST_NO_ONE @@ -149,7 +144,9 @@ static unsigned index_range(const unsigned values[], unsigned value_ct, unsigned for (unsigned i = 1; i < value_ct; ++i) { const unsigned value = values[i]; - if (value < min_value) + if (value == GWN_PRIM_RESTART) + continue; + else if (value < min_value) min_value = value; else if (value > max_value) max_value = value; @@ -159,10 +156,14 @@ static unsigned index_range(const unsigned values[], unsigned value_ct, unsigned return max_value - min_value; } -static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem) +static void squeeze_indices_byte(Gwn_IndexBufBuilder *builder, Gwn_IndexBuf* elem) { + const unsigned *values = builder->data; const unsigned index_ct = elem->index_ct; - GLubyte* data = malloc(index_ct * sizeof(GLubyte)); + + // data will never be *larger* than builder->data... + // converting in place to avoid extra allocation + GLubyte *data = (GLubyte *)builder->data; if (elem->max_index > 0xFF) { @@ -173,7 +174,7 @@ static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem) elem->max_index -= base; for (unsigned i = 0; i < index_ct; ++i) - data[i] = (GLubyte)(values[i] - base); + data[i] = (values[i] == GWN_PRIM_RESTART) ? 0xFF : (GLubyte)(values[i] - base); } else { @@ -182,14 +183,16 @@ static void squeeze_indices_byte(const unsigned values[], Gwn_IndexBuf* elem) for (unsigned i = 0; i < index_ct; ++i) data[i] = (GLubyte)(values[i]); } - - elem->data = data; } -static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem) +static void squeeze_indices_short(Gwn_IndexBufBuilder *builder, Gwn_IndexBuf* elem) { + const unsigned *values = builder->data; const unsigned index_ct = elem->index_ct; - GLushort* data = malloc(index_ct * sizeof(GLushort)); + + // data will never be *larger* than builder->data... + // converting in place to avoid extra allocation + GLushort *data = (GLushort *)builder->data; if (elem->max_index > 0xFFFF) { @@ -200,7 +203,7 @@ static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem) elem->max_index -= base; for (unsigned i = 0; i < index_ct; ++i) - data[i] = (GLushort)(values[i] - base); + data[i] = (values[i] == GWN_PRIM_RESTART) ? 0xFFFF : (GLushort)(values[i] - base); } else { @@ -209,8 +212,6 @@ static void squeeze_indices_short(const unsigned values[], Gwn_IndexBuf* elem) for (unsigned i = 0; i < index_ct; ++i) data[i] = (GLushort)(values[i]); } - - elem->data = data; } #endif // GWN_TRACK_INDEX_RANGE @@ -229,67 +230,56 @@ void GWN_indexbuf_build_in_place(Gwn_IndexBufBuilder* builder, Gwn_IndexBuf* ele #endif elem->index_ct = builder->index_ct; + elem->use_prim_restart = builder->use_prim_restart; #if GWN_TRACK_INDEX_RANGE - const unsigned range = index_range(builder->data, builder->index_ct, &elem->min_index, &elem->max_index); + unsigned range = index_range(builder->data, builder->index_ct, &elem->min_index, &elem->max_index); + + // count the primitive restart index. + if (elem->use_prim_restart) + range += 1; if (range <= 0xFF) { elem->index_type = GWN_INDEX_U8; - squeeze_indices_byte(builder->data, elem); + squeeze_indices_byte(builder, elem); } else if (range <= 0xFFFF) { elem->index_type = GWN_INDEX_U16; - squeeze_indices_short(builder->data, elem); + squeeze_indices_short(builder, elem); } else { elem->index_type = GWN_INDEX_U32; elem->base_index = 0; - - if (builder->index_ct < builder->max_index_ct) - { - builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned)); - // TODO: realloc only if index_ct is much smaller than max_index_ct - } - - elem->data = builder->data; } elem->gl_index_type = convert_index_type_to_gl(elem->index_type); -#else - if (builder->index_ct < builder->max_index_ct) - { - builder->data = realloc(builder->data, builder->index_ct * sizeof(unsigned)); - // TODO: realloc only if index_ct is much smaller than max_index_ct - } - - elem->data = builder->data; #endif - // elem->data will never be *larger* than builder->data... how about converting - // in place to avoid extra allocation? + if (elem->vbo_id == 0) + elem->vbo_id = GWN_buf_id_alloc(); - elem->vbo_id = 0; - // TODO: create GL buffer object directly, based on an input flag + // send data to GPU + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, GWN_indexbuf_size_get(elem), builder->data, GL_STATIC_DRAW); // discard builder (one-time use) - if (builder->data != elem->data) - free(builder->data); + free(builder->data); builder->data = NULL; // other fields are safe to leave } +void GWN_indexbuf_use(Gwn_IndexBuf* elem) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem->vbo_id); + } + void GWN_indexbuf_discard(Gwn_IndexBuf* elem) { if (elem->vbo_id) GWN_buf_id_free(elem->vbo_id); -#if KEEP_SINGLE_COPY - else -#endif - if (elem->data) - free(elem->data); free(elem); } diff --git a/intern/gawain/src/gwn_immediate.c b/intern/gawain/src/gwn_immediate.c index f063665b423c9f108f39e0bec7085fc1a5139ee2..c6df3ada0185baf3d8ca365c7030a91533decc0e 100644 --- a/intern/gawain/src/gwn_immediate.c +++ b/intern/gawain/src/gwn_immediate.c @@ -277,8 +277,6 @@ Gwn_Batch* immBeginBatch(Gwn_PrimType prim_type, unsigned vertex_ct) imm.batch = GWN_batch_create(prim_type, verts, NULL); imm.batch->phase = GWN_BATCH_BUILDING; - GWN_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface); - return imm.batch; } @@ -398,6 +396,7 @@ void immEnd(void) // TODO: resize only if vertex count is much smaller } + GWN_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface); imm.batch->phase = GWN_BATCH_READY_TO_DRAW; imm.batch = NULL; // don't free, batch belongs to caller } diff --git a/intern/gawain/src/gwn_vertex_buffer.c b/intern/gawain/src/gwn_vertex_buffer.c index 32bef765390c163ac776cb7cb8fb3dde84f18320..35538342c2dbbd9fab08df151c3c7a9d14a90150 100644 --- a/intern/gawain/src/gwn_vertex_buffer.c +++ b/intern/gawain/src/gwn_vertex_buffer.c @@ -19,16 +19,26 @@ static unsigned vbo_memory_usage; -Gwn_VertBuf* GWN_vertbuf_create(void) +static GLenum convert_usage_type_to_gl(Gwn_UsageType type) + { + static const GLenum table[] = { + [GWN_USAGE_STREAM] = GL_STREAM_DRAW, + [GWN_USAGE_STATIC] = GL_STATIC_DRAW, + [GWN_USAGE_DYNAMIC] = GL_DYNAMIC_DRAW + }; + return table[type]; + } + +Gwn_VertBuf* GWN_vertbuf_create(Gwn_UsageType usage) { Gwn_VertBuf* verts = malloc(sizeof(Gwn_VertBuf)); - GWN_vertbuf_init(verts); + GWN_vertbuf_init(verts, usage); return verts; } -Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat* format) +Gwn_VertBuf* GWN_vertbuf_create_with_format_ex(const Gwn_VertFormat* format, Gwn_UsageType usage) { - Gwn_VertBuf* verts = GWN_vertbuf_create(); + Gwn_VertBuf* verts = GWN_vertbuf_create(usage); GWN_vertformat_copy(&verts->format, format); if (!format->packed) VertexFormat_pack(&verts->format); @@ -38,61 +48,30 @@ Gwn_VertBuf* GWN_vertbuf_create_with_format(const Gwn_VertFormat* format) // TODO: implement those memory savings } -Gwn_VertBuf* GWN_vertbuf_create_dynamic_with_format(const Gwn_VertFormat* format) - { - Gwn_VertBuf* verts = GWN_vertbuf_create_with_format(format); - verts->data_dynamic = true; - return verts; - } - -void GWN_vertbuf_init(Gwn_VertBuf* verts) +void GWN_vertbuf_init(Gwn_VertBuf* verts, Gwn_UsageType usage) { memset(verts, 0, sizeof(Gwn_VertBuf)); + verts->usage = usage; } -void GWN_vertbuf_init_with_format(Gwn_VertBuf* verts, const Gwn_VertFormat* format) +void GWN_vertbuf_init_with_format_ex(Gwn_VertBuf* verts, const Gwn_VertFormat* format, Gwn_UsageType usage) { - GWN_vertbuf_init(verts); + GWN_vertbuf_init(verts, usage); GWN_vertformat_copy(&verts->format, format); if (!format->packed) VertexFormat_pack(&verts->format); } -/** - * Like #GWN_vertbuf_discard but doesn't free. - */ -void GWN_vertbuf_clear(Gwn_VertBuf* verts) - { - if (verts->vbo_id) { - GWN_buf_id_free(verts->vbo_id); -#if VRAM_USAGE - vbo_memory_usage -= verts->vram_size; -#endif - } - - if (verts->data) - { - free(verts->data); - verts->data = NULL; - } - } - void GWN_vertbuf_discard(Gwn_VertBuf* verts) { if (verts->vbo_id) { GWN_buf_id_free(verts->vbo_id); #if VRAM_USAGE - vbo_memory_usage -= verts->vram_size; + vbo_memory_usage -= GWN_vertbuf_size_get(verts); #endif } - if (verts->data) - { - free(verts->data); - } - - free(verts); } @@ -109,25 +88,82 @@ void GWN_vertbuf_data_alloc(Gwn_VertBuf* verts, unsigned v_ct) verts->vertex_ct = v_ct; - // Data initially lives in main memory. Will be transferred to VRAM when we "prime" it. - verts->data = malloc(GWN_vertbuf_size_get(verts)); +#if TRUST_NO_ONE + assert(verts->vbo_id == 0); +#endif + + unsigned buffer_sz = GWN_vertbuf_size_get(verts); +#if VRAM_USAGE + vbo_memory_usage += buffer_sz; +#endif + + // create an array buffer and map it to memory + verts->vbo_id = GWN_buf_id_alloc(); + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + glBufferData(GL_ARRAY_BUFFER, buffer_sz, NULL, convert_usage_type_to_gl(verts->usage)); + verts->data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); } -void GWN_vertbuf_data_resize(Gwn_VertBuf* verts, unsigned v_ct) +void GWN_vertbuf_data_resize_ex(Gwn_VertBuf* verts, unsigned v_ct, bool keep_data) { #if TRUST_NO_ONE - assert(verts->vertex_ct != v_ct); // allow this? - assert(verts->data != NULL); // has already been allocated - assert(verts->vbo_id == 0 || verts->data_dynamic); // has not been sent to VRAM + assert(verts->vbo_id != 0); #endif - // for dynamic buffers - verts->data_resized = true; + if (verts->vertex_ct == v_ct) + return; + unsigned old_buf_sz = GWN_vertbuf_size_get(verts); verts->vertex_ct = v_ct; - verts->data = realloc(verts->data, GWN_vertbuf_size_get(verts)); - // TODO: skip realloc if v_ct < existing vertex count - // extra space will be reclaimed, and never sent to VRAM (see VertexBuffer_prime) + unsigned new_buf_sz = GWN_vertbuf_size_get(verts); +#if VRAM_USAGE + vbo_memory_usage += new_buf_sz - old_buf_sz; +#endif + + if (keep_data) + { + // we need to do a copy to keep the existing data + GLuint vbo_tmp; + glGenBuffers(1, &vbo_tmp); + // only copy the data that can fit in the new buffer + unsigned copy_sz = (old_buf_sz < new_buf_sz) ? old_buf_sz : new_buf_sz; + glBindBuffer(GL_COPY_WRITE_BUFFER, vbo_tmp); + glBufferData(GL_COPY_WRITE_BUFFER, copy_sz, NULL, GL_STREAM_COPY); + + glBindBuffer(GL_COPY_READ_BUFFER, verts->vbo_id); + // we cannot copy from/to a mapped buffer + if (verts->data) + glUnmapBuffer(GL_COPY_READ_BUFFER); + + // save data, resize the buffer, restore data + glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, copy_sz); + glBufferData(GL_COPY_READ_BUFFER, new_buf_sz, NULL, convert_usage_type_to_gl(verts->usage)); + glCopyBufferSubData(GL_COPY_WRITE_BUFFER, GL_COPY_READ_BUFFER, 0, 0, copy_sz); + + glDeleteBuffers(1, &vbo_tmp); + } + else + { + glBindBuffer(GL_COPY_READ_BUFFER, verts->vbo_id); + glBufferData(GL_COPY_READ_BUFFER, new_buf_sz, NULL, convert_usage_type_to_gl(verts->usage)); + } + + // if the buffer was mapped, update it's pointer + if (verts->data) + verts->data = glMapBuffer(GL_COPY_READ_BUFFER, GL_WRITE_ONLY); + } + +static void VertexBuffer_map(Gwn_VertBuf* verts) + { + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + verts->data = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY); + } + +static void VertexBuffer_unmap(Gwn_VertBuf* verts) + { + glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); + glUnmapBuffer(GL_ARRAY_BUFFER); + verts->data = NULL; } void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, unsigned a_idx, unsigned v_idx, const void* data) @@ -135,14 +171,14 @@ void GWN_vertbuf_attr_set(Gwn_VertBuf* verts, unsigned a_idx, unsigned v_idx, co const Gwn_VertFormat* format = &verts->format; const Gwn_VertAttr* a = format->attribs + a_idx; - verts->data_dirty = true; - #if TRUST_NO_ONE assert(a_idx < format->attrib_ct); assert(v_idx < verts->vertex_ct); - assert(verts->data != NULL); // data must be in main mem #endif + if (verts->data == NULL) + VertexBuffer_map(verts); + memcpy((GLubyte*)verts->data + a->offset + v_idx * format->stride, data, a->sz); } @@ -151,8 +187,6 @@ void GWN_vertbuf_attr_fill(Gwn_VertBuf* verts, unsigned a_idx, const void* data) const Gwn_VertFormat* format = &verts->format; const Gwn_VertAttr* a = format->attribs + a_idx; - verts->data_dirty = true; - #if TRUST_NO_ONE assert(a_idx < format->attrib_ct); #endif @@ -167,15 +201,15 @@ void GWN_vertbuf_attr_fill_stride(Gwn_VertBuf* verts, unsigned a_idx, unsigned s const Gwn_VertFormat* format = &verts->format; const Gwn_VertAttr* a = format->attribs + a_idx; - verts->data_dirty = true; - #if TRUST_NO_ONE assert(a_idx < format->attrib_ct); - assert(verts->data != NULL); // data must be in main mem #endif const unsigned vertex_ct = verts->vertex_ct; + if (verts->data == NULL) + VertexBuffer_map(verts); + if (format->attrib_ct == 1 && stride == format->stride) { // we can copy it all at once @@ -196,9 +230,11 @@ void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, unsigned a_idx, Gwn_VertB #if TRUST_NO_ONE assert(a_idx < format->attrib_ct); - assert(verts->data != NULL); // data must be in main mem #endif + if (verts->data == NULL) + VertexBuffer_map(verts); + access->size = a->sz; access->stride = format->stride; access->data = (GLubyte*)verts->data + a->offset; @@ -208,59 +244,11 @@ void GWN_vertbuf_attr_get_raw_data(Gwn_VertBuf* verts, unsigned a_idx, Gwn_VertB #endif } - -static void VertexBuffer_prime(Gwn_VertBuf* verts) - { - unsigned buffer_sz = GWN_vertbuf_size_get(verts); - -#if VRAM_USAGE - vbo_memory_usage += buffer_sz; - verts->vram_size = buffer_sz; -#endif - - verts->vbo_id = GWN_buf_id_alloc(); - glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); - // fill with delicious data & send to GPU the first time only - glBufferData(GL_ARRAY_BUFFER, verts->vram_size, verts->data, (verts->data_dynamic) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); - - // now that GL has a copy, discard original - if (!verts->data_dynamic) - { - free(verts->data); - verts->data = NULL; - } - - verts->data_dirty = false; - } - -static void VertexBuffer_update(Gwn_VertBuf* verts) - { - unsigned buffer_sz = GWN_vertbuf_size_get(verts); - -#if VRAM_USAGE - vbo_memory_usage -= verts->vram_size; - vbo_memory_usage += buffer_sz; - verts->vram_size = buffer_sz; -#endif - - glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); - - // fill with delicious data & send to GPU ... AGAIN - if (verts->data_resized) - glBufferData(GL_ARRAY_BUFFER, buffer_sz, verts->data, GL_DYNAMIC_DRAW); - else - glBufferSubData(GL_ARRAY_BUFFER, 0, buffer_sz, verts->data); // .. todo try glMapBuffer - - verts->data_dirty = false; - verts->data_resized = false; - } - void GWN_vertbuf_use(Gwn_VertBuf* verts) { - if (!verts->vbo_id) - VertexBuffer_prime(verts); - else if (verts->data_dirty) - VertexBuffer_update(verts); + if (verts->data) + // this also calls glBindBuffer + VertexBuffer_unmap(verts); else glBindBuffer(GL_ARRAY_BUFFER, verts->vbo_id); } diff --git a/intern/ghost/CMakeLists.txt b/intern/ghost/CMakeLists.txt index 7771af93d4fc7baa09851d96193cd7df447b7cf4..e4b74ae24af73ed2bf3dc16e10a170ea53699e91 100644 --- a/intern/ghost/CMakeLists.txt +++ b/intern/ghost/CMakeLists.txt @@ -178,10 +178,12 @@ elseif(WITH_X11) intern/GHOST_DisplayManagerX11.cpp intern/GHOST_SystemX11.cpp intern/GHOST_WindowX11.cpp + intern/GHOST_TaskbarX11.cpp intern/GHOST_DisplayManagerX11.h intern/GHOST_SystemX11.h intern/GHOST_WindowX11.h + intern/GHOST_TaskbarX11.h ) if(NOT WITH_GL_EGL) diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index a23c0b0b26cb18ff2ad5cc4e846c3ec191ede055..58ade795e3f8adc2c74526d7e77a4a35700a6908 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -363,7 +363,8 @@ void GHOST_ContextWGL::initContextWGLEW(PIXELFORMATDESCRIPTOR &preferredPFD) dummyHDC = GetDC(dummyHWND); } else { - dummyhBuffer = wglCreatePbufferARB(m_hDC, iPixelFormat, 1, 1, 0); + int iAttribList[] = {0}; + dummyhBuffer = wglCreatePbufferARB(m_hDC, iPixelFormat, 1, 1, iAttribList); dummyHDC = wglGetPbufferDCARB(dummyhBuffer); } @@ -812,7 +813,8 @@ GHOST_TSuccess GHOST_ContextWGL::initializeDrawingContext() if (create_hDC) { /* create an off-screen pixel buffer (Pbuffer) */ - m_dummyPbuffer = wglCreatePbufferARB(m_hDC, iPixelFormat, 1, 1, 0); + int iAttribList[] = {0}; + m_dummyPbuffer = wglCreatePbufferARB(m_hDC, iPixelFormat, 1, 1, iAttribList); m_hDC = wglGetPbufferDCARB(m_dummyPbuffer); } diff --git a/intern/ghost/intern/GHOST_TaskbarX11.cpp b/intern/ghost/intern/GHOST_TaskbarX11.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b47068df39f51517d23f3eac521e2be349baaf08 --- /dev/null +++ b/intern/ghost/intern/GHOST_TaskbarX11.cpp @@ -0,0 +1,130 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): + * Lukas Stockner + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_TaskbarX11.cpp + * \ingroup GHOST + */ + +#include "GHOST_TaskbarX11.h" + +#include <dlfcn.h> +#include <cstdio> +#include <cassert> +#include <cstdlib> + +typedef void*(*unity_get_entry_t)(const char*); +typedef void(*unity_set_progress_t)(void*, double); +typedef void(*unity_set_progress_visible_t)(void*, int); +typedef int(*unity_event_loop_t)(void*, int); + +static unity_get_entry_t unity_get_entry; +static unity_set_progress_t unity_set_progress; +static unity_set_progress_visible_t unity_set_progress_visible; +static unity_event_loop_t unity_event_loop; + +static bool libunity_initialized = false; +static bool libunity_available = false; +void* libunity_handle = NULL; + +void GHOST_TaskBarX11::free() +{ + if(libunity_handle) { + dlclose(libunity_handle); + libunity_handle = NULL; + } +} + +bool GHOST_TaskBarX11::init() +{ + if(libunity_initialized) { + return libunity_available; + } + + libunity_initialized = true; + + const char *libunity_names[] = {"libunity.so.4", "libunity.so.6", "libunity.so.9", "libunity.so", NULL}; + for(int i = 0; libunity_names[i]; i++) { + libunity_handle = dlopen(libunity_names[i], RTLD_LAZY); + if(libunity_handle) { + break; + } + } + + if(!libunity_handle) { + return false; + } + + unity_get_entry = (unity_get_entry_t) dlsym(libunity_handle, "unity_launcher_entry_get_for_desktop_id"); + if(!unity_get_entry) { + fprintf(stderr, "failed to load libunity: %s\n", dlerror()); + return false; + } + unity_set_progress = (unity_set_progress_t) dlsym(libunity_handle, "unity_launcher_entry_set_progress"); + if(!unity_set_progress) { + fprintf(stderr, "failed to load libunity: %s\n", dlerror()); + return false; + } + unity_set_progress_visible = (unity_set_progress_visible_t) dlsym(libunity_handle, "unity_launcher_entry_set_progress_visible"); + if(!unity_set_progress_visible) { + fprintf(stderr, "failed to load libunity: %s\n", dlerror()); + return false; + } + unity_event_loop = (unity_event_loop_t) dlsym(libunity_handle, "g_main_context_iteration"); + if(!unity_event_loop) { + fprintf(stderr, "failed to load libunity: %s\n", dlerror()); + return false; + } + + atexit(GHOST_TaskBarX11::free); + + libunity_available = true; + return true; +} + +GHOST_TaskBarX11::GHOST_TaskBarX11(const char *name) +{ + if(GHOST_TaskBarX11::init()) { + handle = unity_get_entry(name); + } + else { + handle = NULL; + } +} + +bool GHOST_TaskBarX11::is_valid() +{ + return (handle != NULL); +} + +void GHOST_TaskBarX11::set_progress(double progress) +{ + assert(is_valid()); + unity_set_progress(handle, progress); +} + +void GHOST_TaskBarX11::set_progress_enabled(bool enabled) +{ + assert(is_valid()); + unity_set_progress_visible(handle, enabled ? 1 : 0); + unity_event_loop(NULL, 0); +} \ No newline at end of file diff --git a/intern/ghost/intern/GHOST_TaskbarX11.h b/intern/ghost/intern/GHOST_TaskbarX11.h new file mode 100644 index 0000000000000000000000000000000000000000..ed0e5f9b3295cd6043c0b46c63b66235b7a2b77c --- /dev/null +++ b/intern/ghost/intern/GHOST_TaskbarX11.h @@ -0,0 +1,45 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): + * Lukas Stockner + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ghost/intern/GHOST_TaskbarX11.h + * \ingroup GHOST + */ +#ifndef __GHOST_TASKBARX11_H__ +#define __GHOST_TASKBARX11_H__ + +class GHOST_TaskBarX11 +{ +public: + static bool init(); + static void free(); + + GHOST_TaskBarX11(const char *name); + + bool is_valid(); + void set_progress(double progress); + void set_progress_enabled(bool enabled); +private: + void *handle; +}; + +#endif /*__GHOST_TASKBARX11_H__*/ diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index 78a1c841934cbc8941e65be740c63731a9affa46..3c291bd5ec6513748a08382ba6e2c3f19e675c31 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -334,6 +334,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system, m_empty_cursor(None), m_custom_cursor(None), m_visible_cursor(None), + m_taskbar("blender.desktop"), #ifdef WITH_XDND m_dropTarget(NULL), #endif @@ -1697,3 +1698,24 @@ getDPIHint() int dpi = pixelDiagonal / inchDiagonal; return dpi; } + +GHOST_TSuccess GHOST_WindowX11::setProgressBar(float progress) +{ + if (m_taskbar.is_valid()) { + m_taskbar.set_progress(progress); + m_taskbar.set_progress_enabled(true); + return GHOST_kSuccess; + } + + return GHOST_kFailure; +} + +GHOST_TSuccess GHOST_WindowX11::endProgressBar() +{ + if (m_taskbar.is_valid()) { + m_taskbar.set_progress_enabled(false); + return GHOST_kSuccess; + } + + return GHOST_kFailure; +} diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 5c54c1e8162bb3746ca20f12a90234db2c43c6a3..236fe0b76b00cce36d3dce00b133a0473c34ffbd 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -41,6 +41,8 @@ # include <X11/extensions/XInput.h> #endif +#include "GHOST_TaskbarX11.h" + #include <map> class STR_String; @@ -166,6 +168,9 @@ public: invalidate( ); + GHOST_TSuccess setProgressBar(float progress); + GHOST_TSuccess endProgressBar(); + /** * Destructor. * Closes the window and disposes resources allocated. @@ -347,6 +352,8 @@ private: /** Cache of XC_* ID's to XCursor structures */ std::map<unsigned int, Cursor> m_standard_cursors; + GHOST_TaskBarX11 m_taskbar; + #ifdef WITH_XDND GHOST_DropTargetX11 *m_dropTarget; #endif diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 2b670cdf9ddd23ffafc42e7087f34e81f0df1936..9adc00a67e66ad9b647b1ad162cbd543b974012c 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -127,15 +127,16 @@ enum { G_DEBUG_DEPSGRAPH_TAG = (1 << 10), /* depsgraph tagging messages */ G_DEBUG_DEPSGRAPH_TIME = (1 << 11), /* depsgraph timing statistics and messages */ G_DEBUG_DEPSGRAPH_NO_THREADS = (1 << 12), /* single threaded depsgraph */ + G_DEBUG_DEPSGRAPH_PRETTY = (1 << 13), /* use pretty colors in depsgraph messages */ G_DEBUG_DEPSGRAPH = (G_DEBUG_DEPSGRAPH_BUILD | G_DEBUG_DEPSGRAPH_EVAL | G_DEBUG_DEPSGRAPH_TAG | G_DEBUG_DEPSGRAPH_TIME), - G_DEBUG_SIMDATA = (1 << 13), /* sim debug data display */ - G_DEBUG_GPU_MEM = (1 << 14), /* gpu memory in status bar */ - G_DEBUG_GPU = (1 << 15), /* gpu debug */ - G_DEBUG_IO = (1 << 13), /* IO Debugging (for Collada, ...)*/ - G_DEBUG_GPU_SHADERS = (1 << 16), /* GLSL shaders */ + G_DEBUG_SIMDATA = (1 << 14), /* sim debug data display */ + G_DEBUG_GPU_MEM = (1 << 15), /* gpu memory in status bar */ + G_DEBUG_GPU = (1 << 16), /* gpu debug */ + G_DEBUG_IO = (1 << 17), /* IO Debugging (for Collada, ...)*/ + G_DEBUG_GPU_SHADERS = (1 << 18), /* GLSL shaders */ }; #define G_DEBUG_ALL (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \ diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index 39e6b1457552f24eab047b73a448d60e7d090baa..a9ca5cc8bbbc32d1d484f63aedf998adfe3e1551 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -58,19 +58,19 @@ int BKE_icon_id_ensure(struct ID *id); int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview); /* retrieve icon for id */ -struct Icon *BKE_icon_get(int icon_id); +struct Icon *BKE_icon_get(const int icon_id); /* set icon for id if not already defined */ /* used for inserting the internal icons */ -void BKE_icon_set(int icon_id, struct Icon *icon); +void BKE_icon_set(const int icon_id, struct Icon *icon); /* remove icon and free data if library object becomes invalid */ void BKE_icon_id_delete(struct ID *id); -void BKE_icon_delete(int icon_id); +void BKE_icon_delete(const int icon_id); /* report changes - icon needs to be recalculated */ -void BKE_icon_changed(int icon_id); +void BKE_icon_changed(const int icon_id); /* free all icons */ void BKE_icons_free(void); diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index b79a8d5cbed5cecbf899d9135e857d537074a0f8..ecdb180d2ede39e2b8d5bc1aa6bb57eca6d39cba 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -77,6 +77,8 @@ #include "atomic_ops.h" +#include "DEG_depsgraph.h" + /* ***************************************** */ /* AnimData API */ @@ -2879,18 +2881,34 @@ void BKE_animsys_evaluate_all_animation(Main *main, Scene *scene, float ctime) /* ************** */ /* Evaluation API */ -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf - void BKE_animsys_eval_animdata(const EvaluationContext *eval_ctx, ID *id) { AnimData *adt = BKE_animdata_from_id(id); Scene *scene = NULL; /* XXX: this is only needed for flushing RNA updates, * which should get handled as part of the dependency graph instead... */ - DEBUG_PRINT("%s on %s, time=%f\n\n", __func__, id->name, (double)eval_ctx->ctime); + DEG_debug_print_eval_time(__func__, id->name, id, eval_ctx->ctime); BKE_animsys_evaluate_animdata(scene, id, adt, eval_ctx->ctime, ADT_RECALC_ANIM); } +/* TODO(sergey): This is slow lookup of driver from CoW datablock. + * Keep this for until we've got something smarter for depsgraph + * building.\ + */ +static FCurve *find_driver_from_evaluated_id(ID *id, FCurve *fcu) +{ + /* We've got non-CoW datablock, can use f-curve as-is. */ + if (id->orig_id == NULL) { + return fcu; + } + /*const*/ ID *id_orig = id->orig_id; + const AnimData *adt_orig = BKE_animdata_from_id(id_orig); + const AnimData *adt_cow = BKE_animdata_from_id(id); + const int fcu_index = BLI_findindex(&adt_orig->drivers, fcu); + BLI_assert(fcu_index != -1); + return BLI_findlink(&adt_cow->drivers, fcu_index); +} + void BKE_animsys_eval_driver(const EvaluationContext *eval_ctx, ID *id, FCurve *fcu) @@ -2900,11 +2918,10 @@ void BKE_animsys_eval_driver(const EvaluationContext *eval_ctx, PointerRNA id_ptr; bool ok = false; - DEBUG_PRINT("%s on %s (%s[%d])\n", - __func__, - id->name, - fcu->rna_path, - fcu->array_index); + fcu = find_driver_from_evaluated_id(id, fcu); + + DEG_debug_print_eval_subdata_index( + __func__, id->name, id, "fcu", fcu->rna_path, fcu, fcu->array_index); RNA_id_pointer_create(id, &id_ptr); @@ -2937,5 +2954,3 @@ void BKE_animsys_eval_driver(const EvaluationContext *eval_ctx, } } } - -#undef DEBUG_PRINT diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 203dcbf247cbf0bf3a6e175cdae1258e64bd3a0b..bf065ef992c8931bf2cda5403ed33a3ad71f8183 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -50,7 +50,7 @@ #include "BKE_global.h" #include "BKE_main.h" -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf +#include "DEG_depsgraph.h" /* ********************** SPLINE IK SOLVER ******************* */ @@ -566,7 +566,7 @@ void BKE_pose_eval_init(const struct EvaluationContext *UNUSED(eval_ctx), { bPoseChannel *pchan; - DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + DEG_debug_print_eval(__func__, ob->id.name, ob); BLI_assert(ob->type == OB_ARMATURE); @@ -588,7 +588,7 @@ void BKE_pose_eval_init_ik(const struct EvaluationContext *eval_ctx, Object *ob, bPose *UNUSED(pose)) { - DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + DEG_debug_print_eval(__func__, ob->id.name, ob); BLI_assert(ob->type == OB_ARMATURE); const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ bArmature *arm = (bArmature *)ob->data; @@ -609,7 +609,8 @@ void BKE_pose_eval_bone(const struct EvaluationContext *eval_ctx, Object *ob, bPoseChannel *pchan) { - DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name); + DEG_debug_print_eval_subdata( + __func__, ob->id.name, ob, "pchan", pchan->name, pchan); BLI_assert(ob->type == OB_ARMATURE); bArmature *arm = (bArmature *)ob->data; if (arm->edbo || (arm->flag & ARM_RESTPOS)) { @@ -644,7 +645,8 @@ void BKE_pose_constraints_evaluate(const struct EvaluationContext *eval_ctx, Object *ob, bPoseChannel *pchan) { - DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, pchan->name); + DEG_debug_print_eval_subdata( + __func__, ob->id.name, ob, "pchan", pchan->name, pchan); bArmature *arm = (bArmature *)ob->data; if (arm->flag & ARM_RESTPOS) { return; @@ -664,7 +666,7 @@ void BKE_pose_bone_done(const struct EvaluationContext *UNUSED(eval_ctx), bPoseChannel *pchan) { float imat[4][4]; - DEBUG_PRINT("%s on pchan %s\n", __func__, pchan->name); + DEG_debug_print_eval(__func__, pchan->name, pchan); if (pchan->bone) { invert_m4_m4(imat, pchan->bone->arm_mat); mul_m4_m4m4(pchan->chan_mat, pchan->pose_mat, imat); @@ -676,7 +678,8 @@ void BKE_pose_iktree_evaluate(const struct EvaluationContext *eval_ctx, Object *ob, bPoseChannel *rootchan) { - DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name); + DEG_debug_print_eval_subdata( + __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan); BLI_assert(ob->type == OB_ARMATURE); const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ bArmature *arm = (bArmature *)ob->data; @@ -690,8 +693,10 @@ void BKE_pose_splineik_evaluate(const struct EvaluationContext *eval_ctx, Scene *scene, Object *ob, bPoseChannel *rootchan) + { - DEBUG_PRINT("%s on %s pchan %s\n", __func__, ob->id.name, rootchan->name); + DEG_debug_print_eval_subdata( + __func__, ob->id.name, ob, "rootchan", rootchan->name, rootchan); BLI_assert(ob->type == OB_ARMATURE); const float ctime = BKE_scene_frame_get(scene); /* not accurate... */ bArmature *arm = (bArmature *)ob->data; @@ -707,7 +712,7 @@ void BKE_pose_eval_flush(const struct EvaluationContext *UNUSED(eval_ctx), bPose *UNUSED(pose)) { float ctime = BKE_scene_frame_get(scene); /* not accurate... */ - DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + DEG_debug_print_eval(__func__, ob->id.name, ob); BLI_assert(ob->type == OB_ARMATURE); /* 6. release the IK tree */ @@ -717,7 +722,7 @@ void BKE_pose_eval_flush(const struct EvaluationContext *UNUSED(eval_ctx), void BKE_pose_eval_proxy_copy(const struct EvaluationContext *UNUSED(eval_ctx), Object *ob) { BLI_assert(ID_IS_LINKED(ob) && ob->proxy_from != NULL); - DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); + DEG_debug_print_eval(__func__, ob->id.name, ob); if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { printf("Proxy copy error, lib Object: %s proxy Object: %s\n", ob->id.name + 2, ob->proxy_from->id.name + 2); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index b5ad2bcef4e56fa1e12a86802dc2addb8c945153..0c4dbdf7763d76ed94059697c92976bcee27b8d7 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -5258,9 +5258,7 @@ void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *t void BKE_curve_eval_geometry(const EvaluationContext *UNUSED(eval_ctx), Curve *curve) { - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s on %s\n", __func__, curve->id.name); - } + DEG_debug_print_eval(__func__, curve->id.name, curve); if (curve->bb == NULL || (curve->bb->flag & BOUNDBOX_DIRTY)) { BKE_curve_texspace_calc(curve); } diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index c3fe586bbbbab78a94d5b1add237832eae4aa599..20da1e7b7ac3c34ee0aec82e36b5da9cd2d31935 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -55,7 +55,7 @@ #include "BKE_object.h" #include "BKE_scene.h" -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf +#include "DEG_depsgraph.h" /** Free (or release) any data used by this group (does not free the group itself). */ void BKE_group_free(Group *group) @@ -403,7 +403,7 @@ static void group_eval_layer_collections( void BKE_group_eval_view_layers(const struct EvaluationContext *eval_ctx, Group *group) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, group->id.name, group); + DEG_debug_print_eval(__func__, group->id.name, group); BKE_layer_eval_layer_collection_pre(eval_ctx, &group->id, group->view_layer); group_eval_layer_collections(eval_ctx, group, diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index a407fd0bae8c874bf5a3cbe1ba82c25e6dd605dd..f3ff2c4425afc759c42fec7cfbf04b08d270e77c 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -433,23 +433,28 @@ void BKE_previewimg_ensure(PreviewImage *prv, const int size) } } -void BKE_icon_changed(int id) +void BKE_icon_changed(const int icon_id) { Icon *icon = NULL; - if (!id || G.background) return; + if (!icon_id || G.background) return; - icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(id)); + icon = BLI_ghash_lookup(gIcons, SET_INT_IN_POINTER(icon_id)); if (icon) { - PreviewImage *prv = BKE_previewimg_id_ensure((ID *)icon->obj); + /* We *only* expect ID-tied icons here, not non-ID icon/preview! */ + BLI_assert(icon->type != 0); + + /* Do not enforce creation of previews for valid ID types using BKE_previewimg_id_ensure() here , + * we only want to ensure *existing* preview images are properly tagged as changed/invalid, that's all. */ + PreviewImage **p_prv = BKE_previewimg_id_get_p((ID *)icon->obj); - /* all previews changed */ - if (prv) { + /* If we have previews, they all are now invalid changed. */ + if (p_prv && *p_prv) { int i; for (i = 0; i < NUM_ICON_SIZES; ++i) { - prv->flag[i] |= PRV_CHANGED; - prv->changed_timestamp[i]++; + (*p_prv)->flag[i] |= PRV_CHANGED; + (*p_prv)->changed_timestamp[i]++; } } } @@ -549,7 +554,7 @@ int BKE_icon_preview_ensure(ID *id, PreviewImage *preview) return preview->icon_id; } -Icon *BKE_icon_get(int icon_id) +Icon *BKE_icon_get(const int icon_id) { Icon *icon = NULL; @@ -563,7 +568,7 @@ Icon *BKE_icon_get(int icon_id) return icon; } -void BKE_icon_set(int icon_id, struct Icon *icon) +void BKE_icon_set(const int icon_id, struct Icon *icon) { void **val_p; @@ -586,7 +591,7 @@ void BKE_icon_id_delete(struct ID *id) /** * Remove icon and free data. */ -void BKE_icon_delete(int icon_id) +void BKE_icon_delete(const int icon_id) { Icon *icon; diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 33a665ba06e39c371b8426e6e48a750b32e0b30b..87e5ed8cc1e7f22757ff500cefd52736bea5c312 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -905,9 +905,10 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is if (prop1->len != prop2->len) return false; - for (i = 0; i < prop1->len; i++) - if (!IDP_EqualsProperties(&array1[i], &array2[i])) + for (i = 0; i < prop1->len; i++) { + if (!IDP_EqualsProperties_ex(&array1[i], &array2[i], is_strict)) return false; + } return true; } case IDP_ID: diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 6d5ac08398c738e32c1044b976af8b04dc0169dd..662f724da937a965ee02014f94daf42202f6285b 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -59,8 +59,6 @@ #include "MEM_guardedalloc.h" -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf - /* prototype */ struct EngineSettingsCB_Type; static void layer_collections_sync_flags(ListBase *layer_collections_dst, const ListBase *layer_collections_src); @@ -2300,7 +2298,7 @@ static void idproperty_reset(IDProperty **props, IDProperty *props_ref) void BKE_layer_eval_layer_collection_pre(const struct EvaluationContext *UNUSED(eval_ctx), ID *owner_id, ViewLayer *view_layer) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, view_layer->name, view_layer); + DEG_debug_print_eval(__func__, view_layer->name, view_layer); Scene *scene = (GS(owner_id->name) == ID_SCE) ? (Scene *)owner_id : NULL; for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) { @@ -2344,14 +2342,17 @@ void BKE_layer_eval_layer_collection(const EvaluationContext *eval_ctx, LayerCollection *layer_collection, LayerCollection *parent_layer_collection) { - DEBUG_PRINT("%s on %s (%p) [%s], parent %s (%p) [%s]\n", - __func__, - layer_collection->scene_collection->name, - layer_collection->scene_collection, - collection_type_lookup[layer_collection->scene_collection->type], - (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE", - (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL, - (parent_layer_collection != NULL) ? collection_type_lookup[parent_layer_collection->scene_collection->type] : ""); + if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { + /* TODO)sergey): Try to make it more generic and handled by depsgraph messaging. */ + printf("%s on %s (%p) [%s], parent %s (%p) [%s]\n", + __func__, + layer_collection->scene_collection->name, + layer_collection->scene_collection, + collection_type_lookup[layer_collection->scene_collection->type], + (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection->name : "NONE", + (parent_layer_collection != NULL) ? parent_layer_collection->scene_collection : NULL, + (parent_layer_collection != NULL) ? collection_type_lookup[parent_layer_collection->scene_collection->type] : ""); + } BLI_assert(layer_collection != parent_layer_collection); /* visibility */ @@ -2400,7 +2401,7 @@ void BKE_layer_eval_layer_collection(const EvaluationContext *eval_ctx, void BKE_layer_eval_layer_collection_post(const struct EvaluationContext *UNUSED(eval_ctx), ViewLayer *view_layer) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, view_layer->name, view_layer); + DEG_debug_print_eval(__func__, view_layer->name, view_layer); /* if base is not selectabled, clear select */ for (Base *base = view_layer->object_bases.first; base; base = base->next) { if ((base->flag & BASE_SELECTABLED) == 0) { diff --git a/source/blender/blenkernel/intern/mask_evaluate.c b/source/blender/blenkernel/intern/mask_evaluate.c index 841008d1accec918f4a1db86e7b9f628681cbe07..7d977463abf0b3fb8357485205f3a8b8ec75acb1 100644 --- a/source/blender/blenkernel/intern/mask_evaluate.c +++ b/source/blender/blenkernel/intern/mask_evaluate.c @@ -47,7 +47,6 @@ #include "DEG_depsgraph.h" - unsigned int BKE_mask_spline_resolution(MaskSpline *spline, int width, int height) { float max_segment = 0.01f; @@ -898,11 +897,9 @@ void BKE_mask_layer_evaluate_deform(MaskLayer *masklay, const float ctime) } } -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf - void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask); + DEG_debug_print_eval(__func__, mask->id.name, mask); for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer != NULL; mask_layer = mask_layer->next) @@ -913,7 +910,7 @@ void BKE_mask_eval_animation(struct EvaluationContext *eval_ctx, Mask *mask) void BKE_mask_eval_update(struct EvaluationContext *eval_ctx, Mask *mask) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, mask->id.name, mask); + DEG_debug_print_eval(__func__, mask->id.name, mask); for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer != NULL; mask_layer = mask_layer->next) diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 87a57e2973ac024813b80aee91993efb516833fa..a0059a99473f246b80f60f23423dbc487d1d08e8 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -72,6 +72,7 @@ #include "BKE_editmesh.h" #include "BKE_font.h" +#include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" #include "GPU_material.h" @@ -1774,9 +1775,7 @@ bool BKE_object_material_edit_image_set(Object *ob, short mat_nr, Image *image) void BKE_material_eval(const struct EvaluationContext *UNUSED(eval_ctx), Material *material) { - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s on %s (%p)\n", __func__, material->id.name, material); - } + DEG_debug_print_eval(__func__, material->id.name, material); if ((BLI_listbase_is_empty(&material->gpumaterial) == false)) { GPU_material_uniform_buffer_tag_dirty(&material->gpumaterial); } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 9f346d10272f52364e53779ca742c68114744276..abbf073f6463d3be3085e7e3476bcb55000c6553 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -2670,9 +2670,7 @@ Mesh *BKE_mesh_new_from_object( void BKE_mesh_eval_geometry(const EvaluationContext *UNUSED(eval_ctx), Mesh *mesh) { - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s on %s\n", __func__, mesh->id.name); - } + DEG_debug_print_eval(__func__, mesh->id.name, mesh); if (mesh->bb == NULL || (mesh->bb->flag & BOUNDBOX_DIRTY)) { BKE_mesh_texspace_calc(mesh); } diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index 607307554da383c754c6cf626921cea2789f9420..9ed715d75910d360d625b4c3b57e38af3839ea2c 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -73,12 +73,12 @@ #include "IMB_imbuf.h" #include "IMB_moviecache.h" +#include "DEG_depsgraph.h" + #ifdef WITH_OPENEXR # include "intern/openexr/openexr_multi.h" #endif -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf - /*********************** movieclip buffer loaders *************************/ static int sequence_guess_offset(const char *full_name, int head_len, unsigned short numlen) @@ -1611,6 +1611,6 @@ bool BKE_movieclip_put_frame_if_possible(MovieClip *clip, void BKE_movieclip_eval_update(struct EvaluationContext *UNUSED(eval_ctx), MovieClip *clip) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, clip->id.name, clip); + DEG_debug_print_eval(__func__, clip->id.name, clip); BKE_tracking_dopesheet_tag_update(&clip->tracking); } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 1e41c276de4a99f4dbcf700abfcef6525c3ed889..41b7cd1f48e8feaefbffae0b3a32a26f487c90b2 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -75,6 +75,8 @@ #include "NOD_shader.h" #include "NOD_texture.h" +#include "DEG_depsgraph.h" + #define NODE_DEFAULT_MAX_WIDTH 700 /* Fallback types for undefined tree, nodes, sockets */ @@ -3871,8 +3873,6 @@ void BKE_nodetree_shading_params_eval(const struct EvaluationContext *UNUSED(eva bNodeTree *ntree_dst, const bNodeTree *ntree_src) { - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s on %s (%p)\n", __func__, ntree_src->id.name, ntree_dst); - } + DEG_debug_print_eval(__func__, ntree_src->id.name, ntree_dst); BKE_nodetree_copy_default_values(ntree_dst, ntree_src); } diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index e9af3a3d74e6e4b9478346f8507806d3c96fd52d..199e91a3dd994cbb34a56b4eb850852509792f33 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -65,12 +65,11 @@ #include "MEM_guardedalloc.h" #include "DEG_depsgraph.h" -#define DEBUG_PRINT if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) printf void BKE_object_eval_local_transform(const EvaluationContext *UNUSED(eval_ctx), Object *ob) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); /* calculate local matrix */ BKE_object_to_mat4(ob, ob->obmat); @@ -88,7 +87,7 @@ void BKE_object_eval_parent(const EvaluationContext *UNUSED(eval_ctx), float tmat[4][4]; float locmat[4][4]; - DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); /* get local matrix (but don't calculate it, as that was done already!) */ // XXX: redundant? @@ -117,7 +116,7 @@ void BKE_object_eval_constraints(const EvaluationContext *eval_ctx, bConstraintOb *cob; float ctime = BKE_scene_frame_get(scene); - DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); /* evaluate constraints stack */ /* TODO: split this into: @@ -135,7 +134,7 @@ void BKE_object_eval_constraints(const EvaluationContext *eval_ctx, void BKE_object_eval_done(const EvaluationContext *UNUSED(eval_ctx), Object *ob) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); /* Set negative scale flag in object. */ if (is_negative_m4(ob->obmat)) ob->transflag |= OB_NEG_SCALE; @@ -313,7 +312,7 @@ void BKE_object_eval_uber_data(const EvaluationContext *eval_ctx, Scene *scene, Object *ob) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, ob->id.name, ob); + DEG_debug_print_eval(__func__, ob->id.name, ob); BLI_assert(ob->type != OB_ARMATURE); BKE_object_handle_data_update(eval_ctx, scene, ob); @@ -391,7 +390,7 @@ void BKE_object_eval_cloth(const EvaluationContext *UNUSED(eval_ctx), Scene *scene, Object *object) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object); + DEG_debug_print_eval(__func__, object->id.name, object); BKE_ptcache_object_reset(scene, object, PTCACHE_RESET_DEPSGRAPH); } @@ -414,7 +413,7 @@ void BKE_object_eval_transform_all(const EvaluationContext *eval_ctx, void BKE_object_eval_update_shading(const EvaluationContext *UNUSED(eval_ctx), Object *object) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object); + DEG_debug_print_eval(__func__, object->id.name, object); if (object->type == OB_MESH) { BKE_mesh_batch_cache_dirty(object->data, BKE_MESH_BATCH_DIRTY_SHADING); } @@ -423,7 +422,7 @@ void BKE_object_eval_update_shading(const EvaluationContext *UNUSED(eval_ctx), void BKE_object_data_select_update(const EvaluationContext *UNUSED(eval_ctx), struct ID *object_data) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, object_data->name, object_data); + DEG_debug_print_eval(__func__, object_data->name, object_data); switch (GS(object_data->name)) { case ID_ME: BKE_mesh_batch_cache_dirty((Mesh *)object_data, @@ -445,7 +444,7 @@ void BKE_object_data_select_update(const EvaluationContext *UNUSED(eval_ctx), void BKE_object_eval_flush_base_flags(const EvaluationContext *UNUSED(eval_ctx), Object *object, Base *base, bool is_from_set) { - DEBUG_PRINT("%s on %s (%p)\n", __func__, object->id.name, object); + DEG_debug_print_eval(__func__, object->id.name, object); /* Make sure we have the base collection settings is already populated. * This will fail when BKE_layer_eval_layer_collection_pre hasn't run yet. diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index 4cf8533d843e767d7e8395d2b2b42d86aa18c928..f27a570ca29e4bd73573f244b4865d651e0ef8a9 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -95,6 +95,7 @@ #include "PIL_time.h" #include "RE_shader_ext.h" +#include "DEG_depsgraph.h" /* fluid sim particle import */ #ifdef WITH_MOD_FLUID @@ -4419,18 +4420,14 @@ void BKE_particlesystem_id_loop(ParticleSystem *psys, ParticleSystemIDFunc func, void BKE_particle_system_settings_eval(const struct EvaluationContext *UNUSED(eval_ctx), ParticleSystem *psys) { - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s on %s (%p)\n", __func__, psys->name, psys); - } + DEG_debug_print_eval(__func__, psys->name, psys); psys->recalc |= psys->part->recalc; } void BKE_particle_system_settings_recalc_clear(struct EvaluationContext *UNUSED(eval_ctx), ParticleSettings *particle_settings) { - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s on %s (%p)\n", __func__, particle_settings->id.name, particle_settings); - } + DEG_debug_print_eval(__func__, particle_settings->id.name, particle_settings); particle_settings->recalc = 0; } @@ -4438,8 +4435,6 @@ void BKE_particle_system_eval_init(const struct EvaluationContext *UNUSED(eval_c Scene *scene, Object *ob) { - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s on %s (%p)\n", __func__, ob->id.name, ob); - } + DEG_debug_print_eval(__func__, ob->id.name, ob); BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH); } diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index 12a53f5f3e5a1f798ba958e5d4193a96c52e86fd..69e36f66dad05af30dc4ae938931df2723569682 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -66,6 +66,8 @@ #include "BKE_rigidbody.h" #include "BKE_scene.h" +#include "DEG_depsgraph.h" + /* ************************************** */ /* Memory Management */ @@ -1688,11 +1690,7 @@ void BKE_rigidbody_rebuild_sim(const struct EvaluationContext *eval_ctx, Scene *scene) { float ctime = BKE_scene_frame_get(scene); - - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s at %f\n", __func__, ctime); - } - + DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime); /* rebuild sim data (i.e. after resetting to start of timeline) */ if (BKE_scene_check_rigidbody_active(scene)) { BKE_rigidbody_rebuild_world(eval_ctx, scene, ctime); @@ -1703,11 +1701,7 @@ void BKE_rigidbody_eval_simulation(const struct EvaluationContext *eval_ctx, Scene *scene) { float ctime = BKE_scene_frame_get(scene); - - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s at %f\n", __func__, ctime); - } - + DEG_debug_print_eval_time(__func__, scene->id.name, scene, ctime); /* evaluate rigidbody sim */ if (BKE_scene_check_rigidbody_active(scene)) { BKE_rigidbody_do_simulation(eval_ctx, scene, ctime); @@ -1720,11 +1714,7 @@ void BKE_rigidbody_object_sync_transforms(const struct EvaluationContext *UNUSED { RigidBodyWorld *rbw = scene->rigidbody_world; float ctime = BKE_scene_frame_get(scene); - - if (G.debug & G_DEBUG_DEPSGRAPH_EVAL) { - printf("%s on %s\n", __func__, ob->id.name); - } - + DEG_debug_print_eval_time(__func__, ob->id.name, ob, ctime); /* read values pushed into RBO from sim/cache... */ BKE_rigidbody_sync_transforms(rbw, ob, ctime); } diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h index 825acb18e91c97252648616b566b1e0e14130609..8e94b8197ef495ede23ad31f1b1d41231c426bc6 100644 --- a/source/blender/blenlib/BLI_array.h +++ b/source/blender/blenlib/BLI_array.h @@ -62,9 +62,10 @@ * Doing the realloc in a macro isn't so simple, * so use a function the macros can use. */ -void _bli_array_grow_func(void **arr_p, const void *arr_static, - const int sizeof_arr_p, const int arr_count, const int num, - const char *alloc_str); +void _bli_array_grow_func( + void **arr_p, const void *arr_static, + const int sizeof_arr_p, const int arr_len, const int num, + const char *alloc_str); /* -------------------------------------------------------------------- */ @@ -74,18 +75,18 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, /** use ``sizeof(*(arr))`` to ensure the array exists and is an array */ #define BLI_array_declare(arr) \ - int _##arr##_count = ((void)(sizeof(*(arr))), 0); \ + int _##arr##_len = ((void)(sizeof(*(arr))), 0); \ void *_##arr##_static = NULL /** * this will use stack space, up to maxstatic array elements, before * switching to dynamic heap allocation */ #define BLI_array_staticdeclare(arr, maxstatic) \ - int _##arr##_count = 0; \ + int _##arr##_len = 0; \ char _##arr##_static[maxstatic * sizeof(*(arr))] /** returns the logical size of the array, not including buffering. */ -#define BLI_array_count(arr) ((void)0, _##arr##_count) +#define BLI_array_len(arr) ((void)0, _##arr##_len) /** * Grow the array by a fixed number of items. @@ -95,23 +96,23 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, #define BLI_array_reserve(arr, num) (void)( \ (((void *)(arr) == NULL) && \ ((void *)(_##arr##_static) != NULL) && \ - /* don't add _##arr##_count below because it must be zero */ \ - (_bli_array_totalsize_static(arr) >= _##arr##_count + (num))) ? \ + /* don't add _##arr##_len below because it must be zero */ \ + (_bli_array_totalsize_static(arr) >= _##arr##_len + (num))) ? \ /* we have an empty array and a static var big enough */ \ (void)(arr = (void *)_##arr##_static) \ : \ /* use existing static array or allocate */ \ - (LIKELY(_bli_array_totalsize(arr) >= _##arr##_count + (num)) ? \ + (LIKELY(_bli_array_totalsize(arr) >= _##arr##_len + (num)) ? \ (void)0 /* do nothing */ : \ _bli_array_grow_func((void **)&(arr), _##arr##_static, \ - sizeof(*(arr)), _##arr##_count, num, \ + sizeof(*(arr)), _##arr##_len, num, \ "BLI_array." #arr)) \ ) /** returns length of array */ #define BLI_array_grow_items(arr, num) \ - (BLI_array_reserve(arr, num), (_##arr##_count += num)) + (BLI_array_reserve(arr, num), (_##arr##_len += num)) #define BLI_array_grow_one(arr) \ BLI_array_grow_items(arr, 1) @@ -119,7 +120,7 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, /** appends an item to the array. */ #define BLI_array_append(arr, item) ( \ (void) BLI_array_grow_one(arr), \ - (void) (arr[_##arr##_count - 1] = item) \ + (void) (arr[_##arr##_len - 1] = item) \ ) /** @@ -127,13 +128,13 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, * item is not a pointer, but actual data value.*/ #define BLI_array_append_r(arr, item) ( \ (void) BLI_array_grow_one(arr), \ - (void) (arr[_##arr##_count - 1] = item), \ - (&arr[_##arr##_count - 1]) \ + (void) (arr[_##arr##_len - 1] = item), \ + (&arr[_##arr##_len - 1]) \ ) /** appends (grows) & returns a pointer to the uninitialized memory */ #define BLI_array_append_ret(arr) \ - (BLI_array_reserve(arr, 1), &arr[(_##arr##_count++)]) + (BLI_array_reserve(arr, 1), &arr[(_##arr##_len++)]) #define BLI_array_free(arr) { \ if (arr && (char *)arr != _##arr##_static) { \ @@ -143,26 +144,26 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, } ((void)0) #define BLI_array_pop(arr) ( \ - (arr && _##arr##_count) ? \ - arr[--_##arr##_count] : \ + (arr && _##arr##_len) ? \ + arr[--_##arr##_len] : \ NULL \ ) /** - * resets the logical size of an array to zero, but doesn't + * Resets the logical size of an array to zero, but doesn't * free the memory. */ #define BLI_array_clear(arr) \ - { _##arr##_count = 0; } (void)0 + { _##arr##_len = 0; } ((void)0) /** - * set the count of the array, doesn't actually increase the allocated array + * Set the length of the array, doesn't actually increase the allocated array * size. don't use this unless you know what you're doing. */ -#define BLI_array_count_set(arr, count) \ - { _##arr##_count = (count); }(void)0 +#define BLI_array_len_set(arr, len) \ + { _##arr##_len = (len); } ((void)0) /** only to prevent unused warnings */ #define BLI_array_fake_user(arr) \ - ((void)_##arr##_count, \ + ((void)_##arr##_len, \ (void)_##arr##_static) /** \} */ @@ -191,7 +192,7 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, #define BLI_array_fixedstack_free(arr) \ if (_##arr##_is_static) { \ MEM_freeN(arr); \ - } (void)0 + } ((void)0) /** \} */ diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h new file mode 100644 index 0000000000000000000000000000000000000000..9fb0954e77fee5daaf20465b05320b2b534cc76e --- /dev/null +++ b/source/blender/blenlib/BLI_assert.h @@ -0,0 +1,111 @@ +/* + * ***** 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_ASSERT_H__ +#define __BLI_ASSERT_H__ + +/** \file BLI_assert.h + * \ingroup bli + * + * Defines: + * - #BLI_assert + * - #BLI_STATIC_ASSERT + * - #BLI_STATIC_ASSERT_ALIGN + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NDEBUG /* for BLI_assert */ +#include <stdio.h> +#endif + +/* BLI_assert(), default only to print + * for aborting need to define WITH_ASSERT_ABORT + */ +/* For 'abort' only. */ +#include <stdlib.h> + +#ifndef NDEBUG +# include "BLI_system.h" +# ifdef WITH_ASSERT_ABORT +# define _BLI_DUMMY_ABORT abort +# else +# define _BLI_DUMMY_ABORT() (void)0 +# endif +# if defined(__GNUC__) || defined(_MSC_VER) /* check __func__ is available */ +# define BLI_assert(a) \ + (void)((!(a)) ? ( \ + ( \ + BLI_system_backtrace(stderr), \ + fprintf(stderr, \ + "BLI_assert failed: %s:%d, %s(), at \'%s\'\n", \ + __FILE__, __LINE__, __func__, "" #a), \ + _BLI_DUMMY_ABORT(), \ + NULL)) : NULL) +# else +# define BLI_assert(a) \ + (void)((!(a)) ? ( \ + ( \ + fprintf(stderr, \ + "BLI_assert failed: %s:%d, at \'%s\'\n", \ + __FILE__, __LINE__, "" #a), \ + _BLI_DUMMY_ABORT(), \ + NULL)) : NULL) +# endif +#else +# define BLI_assert(a) (void)0 +#endif + +/* C++ can't use _Static_assert, expects static_assert() but c++0x only, + * Coverity also errors out. */ +#if (!defined(__cplusplus)) && \ + (!defined(__COVERITY__)) && \ + (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) /* gcc4.6+ only */ +# define BLI_STATIC_ASSERT(a, msg) __extension__ _Static_assert(a, msg); +#else +/* Code adapted from http://www.pixelbeat.org/programming/gcc/static_assert.html */ +/* Note we need the two concats below because arguments to ## are not expanded, so we need to + * expand __LINE__ with one indirection before doing the actual concatenation. */ +# define ASSERT_CONCAT_(a, b) a##b +# define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b) + /* These can't be used after statements in c89. */ +# if defined(__COUNTER__) /* MSVC */ +# define BLI_STATIC_ASSERT(a, msg) \ + ; enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1 / (int)(!!(a)) }; +# else /* older gcc, clang... */ + /* This can't be used twice on the same line so ensure if using in headers + * that the headers are not included twice (by wrapping in #ifndef...#endif) + * Note it doesn't cause an issue when used on same line of separate modules + * compiled with gcc -combine -fwhole-program. */ +# define BLI_STATIC_ASSERT(a, msg) \ + ; enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1 / (int)(!!(a)) }; +# endif +#endif + +#define BLI_STATIC_ASSERT_ALIGN(st, align) \ + BLI_STATIC_ASSERT((sizeof(st) % (align) == 0), "Structure must be strictly aligned") + +#ifdef __cplusplus +} +#endif + +#endif /* __BLI_ASSERT_H__ */ diff --git a/source/blender/blenlib/BLI_console.h b/source/blender/blenlib/BLI_console.h new file mode 100644 index 0000000000000000000000000000000000000000..bf433f78f70010be83786a34ccbc29694942bd31 --- /dev/null +++ b/source/blender/blenlib/BLI_console.h @@ -0,0 +1,42 @@ +/* + * ***** 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) 2018 Blender Foundation. + * All rights reserved. + * + * Contributor(s): Srrgey Sharybin. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#ifndef __BLI_CONSOLE_H__ +#define __BLI_CONSOLE_H__ + +/** \file BLI_console.h + * \ingroup bli + * \brief Set of utility functions and constants to work with consoles. + */ + +/* Format string where one could BLI_snprintf() R, G and B values + * and get proper marker to start colored output in the console. + */ +#define TRUECOLOR_ANSI_COLOR_FORMAT "\x1b[38;2;%d;%d;%dm" + +/* Marker which indicates that colored output is finished. */ +#define TRUECOLOR_ANSI_COLOR_FINISH "\x1b[0m" + +#endif /* __BLI_CONSOLE_H__ */ diff --git a/source/blender/blenlib/BLI_hash.h b/source/blender/blenlib/BLI_hash.h index fa79481e25cbc87b3c25fc82dc22ac2669770b39..9ca7898d6b89616351362712a9704900cbc85f1b 100644 --- a/source/blender/blenlib/BLI_hash.h +++ b/source/blender/blenlib/BLI_hash.h @@ -68,4 +68,16 @@ BLI_INLINE float BLI_hash_int_01(unsigned int k) return (float)BLI_hash_int(k) * (1.0f / (float)0xFFFFFFFF); } +BLI_INLINE void BLI_hash_pointer_to_color(const void *ptr, int *r, int *g, int *b) +{ + size_t val = (size_t)ptr; + const size_t hash_a = BLI_hash_int(val & 0x0000ffff); + const size_t hash_b = BLI_hash_int((val & 0xffff0000) >> 32); + const size_t hash = + hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2)); + *r = (hash & 0xff0000) >> 16; + *g = (hash & 0x00ff00) >> 8; + *b = hash & 0x0000ff; +} + #endif // __BLI_HASH_H__ diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index 3b24cae018d21ed90c088f10b1c3b145738d1b35..6f8e48d83b22c062d3e31d2b11bbdb31ea88b3d0 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -35,6 +35,7 @@ #endif #include <math.h> +#include "BLI_assert.h" #include "BLI_math_inline.h" #ifndef M_PI diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index ee1acc5afddb1e7e812194b700ed20cd28ebe0ab..11c8a586784076290604fde538d13baea7c3aecd 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -41,9 +41,8 @@ extern "C" { #include "BLI_compiler_compat.h" #include "BLI_utildefines_variadic.h" -#ifndef NDEBUG /* for BLI_assert */ -#include <stdio.h> -#endif +/* We could remove in future. */ +#include "BLI_assert.h" /* useful for finding bad use of min/max */ #if 0 @@ -615,74 +614,6 @@ extern bool BLI_memory_is_zero(const void *arr, const size_t arr_size); # define UNUSED_VARS_NDEBUG UNUSED_VARS #endif - -/* BLI_assert(), default only to print - * for aborting need to define WITH_ASSERT_ABORT - */ -/* For 'abort' only. */ -#include <stdlib.h> - -#ifndef NDEBUG -# include "BLI_system.h" -# ifdef WITH_ASSERT_ABORT -# define _BLI_DUMMY_ABORT abort -# else -# define _BLI_DUMMY_ABORT() (void)0 -# endif -# if defined(__GNUC__) || defined(_MSC_VER) /* check __func__ is available */ -# define BLI_assert(a) \ - (void)((!(a)) ? ( \ - ( \ - BLI_system_backtrace(stderr), \ - fprintf(stderr, \ - "BLI_assert failed: %s:%d, %s(), at \'%s\'\n", \ - __FILE__, __LINE__, __func__, STRINGIFY(a)), \ - _BLI_DUMMY_ABORT(), \ - NULL)) : NULL) -# else -# define BLI_assert(a) \ - (void)((!(a)) ? ( \ - ( \ - fprintf(stderr, \ - "BLI_assert failed: %s:%d, at \'%s\'\n", \ - __FILE__, __LINE__, STRINGIFY(a)), \ - _BLI_DUMMY_ABORT(), \ - NULL)) : NULL) -# endif -#else -# define BLI_assert(a) (void)0 -#endif - -/* C++ can't use _Static_assert, expects static_assert() but c++0x only, - * Coverity also errors out. */ -#if (!defined(__cplusplus)) && \ - (!defined(__COVERITY__)) && \ - (defined(__GNUC__) && ((__GNUC__ * 100 + __GNUC_MINOR__) >= 406)) /* gcc4.6+ only */ -# define BLI_STATIC_ASSERT(a, msg) __extension__ _Static_assert(a, msg); -#else -/* Code adapted from http://www.pixelbeat.org/programming/gcc/static_assert.html */ -/* Note we need the two concats below because arguments to ## are not expanded, so we need to - * expand __LINE__ with one indirection before doing the actual concatenation. */ -# define ASSERT_CONCAT_(a, b) a##b -# define ASSERT_CONCAT(a, b) ASSERT_CONCAT_(a, b) - /* These can't be used after statements in c89. */ -# if defined(__COUNTER__) /* MSVC */ -# define BLI_STATIC_ASSERT(a, msg) \ - ; enum { ASSERT_CONCAT(static_assert_, __COUNTER__) = 1 / (int)(!!(a)) }; -# else /* older gcc, clang... */ - /* This can't be used twice on the same line so ensure if using in headers - * that the headers are not included twice (by wrapping in #ifndef...#endif) - * Note it doesn't cause an issue when used on same line of separate modules - * compiled with gcc -combine -fwhole-program. */ -# define BLI_STATIC_ASSERT(a, msg) \ - ; enum { ASSERT_CONCAT(assert_line_, __LINE__) = 1 / (int)(!!(a)) }; -# endif -#endif - - -#define BLI_STATIC_ASSERT_ALIGN(st, align) \ - BLI_STATIC_ASSERT((sizeof(st) % (align) == 0), "Structure must be strictly aligned") - /* hints for branch prediction, only use in code that runs a _lot_ where */ #ifdef __GNUC__ # define LIKELY(x) __builtin_expect(!!(x), 1) diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index ef36b5ac6bd0efa26e4556f55e5a0a051b0627fc..5bcf4303a841563bc1a273f1d108d5b5dcad1ff1 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -139,6 +139,7 @@ set(SRC BLI_compiler_attrs.h BLI_compiler_compat.h BLI_compiler_typecheck.h + BLI_console.h BLI_convexhull_2d.h BLI_dial_2d.h BLI_dlrbTree.h diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c index f681d222e695789c3307db595b0f7c9ac7e78964..d16dd36763da2391b914270391070090145a5ac2 100644 --- a/source/blender/blenlib/intern/BLI_array.c +++ b/source/blender/blenlib/intern/BLI_array.c @@ -66,21 +66,23 @@ /** * This function is only to be called via macros. * - * \note The caller must adjust \a arr_count + * \note The caller must adjust \a arr_len */ -void _bli_array_grow_func(void **arr_p, const void *arr_static, - const int sizeof_arr_p, const int arr_count, const int num, - const char *alloc_str) +void _bli_array_grow_func( + void **arr_p, const void *arr_static, + const int sizeof_arr_p, const int arr_len, const int num, + const char *alloc_str) { void *arr = *arr_p; void *arr_tmp; - arr_tmp = MEM_mallocN(sizeof_arr_p * - ((num < arr_count) ? - (arr_count * 2 + 2) : (arr_count + num)), alloc_str); + arr_tmp = MEM_mallocN( + sizeof_arr_p * + ((num < arr_len) ? + (arr_len * 2 + 2) : (arr_len + num)), alloc_str); if (arr) { - memcpy(arr_tmp, arr, sizeof_arr_p * arr_count); + memcpy(arr_tmp, arr, sizeof_arr_p * arr_len); if (arr != arr_static) { MEM_freeN(arr); @@ -91,6 +93,6 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static, /* caller must do */ #if 0 - arr_count += num; + arr_len += num; #endif } diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index c1187fdd8bb54c4e8fa9b1c0594f85c4ee15b786..06e8ade68a218f7665524f92c03d4063a8c07ab4 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -856,9 +856,8 @@ static void non_recursive_bvh_div_nodes_task_cb( else { break; } - - parent->totnode = (char)(k + 1); } + parent->totnode = (char)k; } /** diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c index 1f517471407ef272d628b6bd8e48d22b1081bdc3..eed06c7841b3dc69173462990e044d0e9b2c455c 100644 --- a/source/blender/blenlib/intern/math_base_inline.c +++ b/source/blender/blenlib/intern/math_base_inline.c @@ -368,10 +368,8 @@ MINLINE int compare_ff_relative(float a, float b, const float max_diff, const in { union {float f; int i;} ua, ub; -#if 0 /* No BLI_assert in INLINE :/ */ BLI_assert(sizeof(float) == sizeof(int)); BLI_assert(max_ulps < (1 << 22)); -#endif if (fabsf(a - b) <= max_diff) { return 1; diff --git a/source/blender/blenlib/intern/math_bits_inline.c b/source/blender/blenlib/intern/math_bits_inline.c index 37fdcd7878a5f45f6f77946ad15078cfcb44436d..9b16756134e3285820104db3a44a2de1c2edf1af 100644 --- a/source/blender/blenlib/intern/math_bits_inline.c +++ b/source/blender/blenlib/intern/math_bits_inline.c @@ -34,7 +34,7 @@ MINLINE int bitscan_forward_i(int a) { BLI_assert(a != 0); -# ifdef _MSC_VER +#ifdef _MSC_VER unsigned long ctz; _BitScanForward(&ctz, a); return ctz; @@ -63,7 +63,7 @@ MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a) MINLINE int bitscan_reverse_i(int a) { BLI_assert(a != 0); -# ifdef _MSC_VER +#ifdef _MSC_VER unsigned long clz; _BitScanReverse(&clz, a); return clz; diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index aba0160622f714ab206721e7fa4d896ec4239cca..c4b29e91fb421b9af01e61f5d8e81838786d8430 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -1282,8 +1282,8 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) } /* create region face */ - f_new = BLI_array_count(edges) ? - BM_face_create_ngon(bm, v1, v2, edges, BLI_array_count(edges), faces[0], BM_CREATE_NOP) : NULL; + f_new = BLI_array_len(edges) ? + BM_face_create_ngon(bm, v1, v2, edges, BLI_array_len(edges), faces[0], BM_CREATE_NOP) : NULL; if (UNLIKELY(f_new == NULL)) { /* Invalid boundary region to join faces */ goto error; @@ -1347,11 +1347,11 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del) /* delete old geometry */ if (do_del) { - for (i = 0; i < BLI_array_count(deledges); i++) { + for (i = 0; i < BLI_array_len(deledges); i++) { BM_edge_kill(bm, deledges[i]); } - for (i = 0; i < BLI_array_count(delverts); i++) { + for (i = 0; i < BLI_array_len(delverts); i++) { BM_vert_kill(bm, delverts[i]); } } diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c index 1cd51528e0620b39e401944d042e1c42fd1a2da4..961cc4587840bd4abcfab486bf8475185ba14955 100644 --- a/source/blender/bmesh/intern/bmesh_mods.c +++ b/source/blender/bmesh/intern/bmesh_mods.c @@ -482,8 +482,8 @@ BMEdge *BM_vert_collapse_faces( BLI_array_append(faces, f); } - if (BLI_array_count(faces) >= 2) { - BMFace *f2 = BM_faces_join(bm, faces, BLI_array_count(faces), true); + if (BLI_array_len(faces) >= 2) { + BMFace *f2 = BM_faces_join(bm, faces, BLI_array_len(faces), true); if (f2) { BMLoop *l_a, *l_b; @@ -499,7 +499,7 @@ BMEdge *BM_vert_collapse_faces( } } - BLI_assert(BLI_array_count(faces) < 8); + BLI_assert(BLI_array_len(faces) < 8); BLI_array_free(faces); } @@ -608,7 +608,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) } while (l != e->l); /* flag existing faces so we can differentiate oldfaces from new faces */ - for (i = 0; i < BLI_array_count(oldfaces); i++) { + for (i = 0; i < BLI_array_len(oldfaces); i++) { BM_ELEM_API_FLAG_ENABLE(oldfaces[i], _FLAG_OVERLAP); oldfaces[i] = BM_face_copy(bm, bm, oldfaces[i], true, true); BM_ELEM_API_FLAG_DISABLE(oldfaces[i], _FLAG_OVERLAP); @@ -639,7 +639,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) int i, j; /* interpolate new/changed loop data from copied old faces */ - for (i = 0; i < BLI_array_count(oldfaces); i++) { + for (i = 0; i < BLI_array_len(oldfaces); i++) { float f_center_old[3]; BM_face_calc_center_mean(oldfaces[i], f_center_old); @@ -671,7 +671,7 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac) } /* destroy the old faces */ - for (i = 0; i < BLI_array_count(oldfaces); i++) { + for (i = 0; i < BLI_array_len(oldfaces); i++) { BM_face_verts_kill(bm, oldfaces[i]); } diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index 37e68f1d5ff73188f83cf7dae525bc0efe4a6c3a..85dfd3f58e28348498664d38bb005a2fd06ab56f 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -665,7 +665,7 @@ bool BM_face_split_edgenet( BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_VISIT); } while ((l_iter = l_iter->next) != l_first); - if (BLI_array_count(face_arr)) { + if (BLI_array_len(face_arr)) { bmesh_face_swap_data(f, face_arr[0]); BM_face_kill(bm, face_arr[0]); face_arr[0] = f; @@ -674,13 +674,13 @@ bool BM_face_split_edgenet( BM_ELEM_API_FLAG_DISABLE(f, FACE_NET); } - for (i = 0; i < BLI_array_count(face_arr); i++) { + for (i = 0; i < BLI_array_len(face_arr); i++) { BM_ELEM_API_FLAG_DISABLE(face_arr[i], FACE_NET); } if (r_face_arr) { *r_face_arr = face_arr; - *r_face_arr_len = BLI_array_count(face_arr); + *r_face_arr_len = BLI_array_len(face_arr); } else { if (face_arr) { diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index 5a2f07be70a1a7603d638d356f4124f335f3bb90..816d2e8d009c7fc68b3cad179ac081914a2838d6 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -179,7 +179,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) } BMW_end(®walker); - for (i = 0; i < BLI_array_count(faces); i++) { + for (i = 0; i < BLI_array_len(faces); i++) { f_iter = faces[i]; BMO_face_flag_disable(bm, f_iter, FACE_TAG); BMO_face_flag_enable(bm, f_iter, FACE_ORIG); @@ -198,7 +198,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) /* track how many faces we should end up with */ int totface_target = bm->totface; - for (i = 0; i < BLI_array_count(regions); i++) { + for (i = 0; i < BLI_array_len(regions); i++) { BMFace *f_new; int tot = 0; @@ -259,7 +259,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) cleanup: /* free/cleanup */ - for (i = 0; i < BLI_array_count(regions); i++) { + for (i = 0; i < BLI_array_len(regions); i++) { if (regions[i]) MEM_freeN(regions[i]); } diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c index 744ef866128b6766932e4bd2a9cfad2d254954f1..931ac684b07156b5aa97a59e3f2ccb1fe723bbd0 100644 --- a/source/blender/bmesh/operators/bmo_edgenet.c +++ b/source/blender/bmesh/operators/bmo_edgenet.c @@ -179,22 +179,22 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) if (!count) { edges1 = edges; - BLI_array_count_set(edges1, BLI_array_count(edges)); + BLI_array_len_set(edges1, BLI_array_len(edges)); } else { edges2 = edges; - BLI_array_count_set(edges2, BLI_array_count(edges)); + BLI_array_len_set(edges2, BLI_array_len(edges)); } BLI_array_clear(edges); count++; } - if (edges1 && BLI_array_count(edges1) > 2 && - BM_edge_share_vert_check(edges1[0], edges1[BLI_array_count(edges1) - 1])) + if (edges1 && BLI_array_len(edges1) > 2 && + BM_edge_share_vert_check(edges1[0], edges1[BLI_array_len(edges1) - 1])) { - if (edges2 && BLI_array_count(edges2) > 2 && - BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1])) + if (edges2 && BLI_array_len(edges2) > 2 && + BM_edge_share_vert_check(edges2[0], edges2[BLI_array_len(edges2) - 1])) { BLI_array_free(edges1); BLI_array_free(edges2); @@ -206,8 +206,8 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) } } - if (edges2 && BLI_array_count(edges2) > 2 && - BM_edge_share_vert_check(edges2[0], edges2[BLI_array_count(edges2) - 1])) + if (edges2 && BLI_array_len(edges2) > 2 && + BM_edge_share_vert_check(edges2[0], edges2[BLI_array_len(edges2) - 1])) { edges2 = NULL; } @@ -218,23 +218,23 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) float dvec1[3]; float dvec2[3]; - if (BLI_array_count(edges1) == 1) { + if (BLI_array_len(edges1) == 1) { v1 = edges1[0]->v1; v2 = edges1[0]->v2; } else { v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1; - i = BLI_array_count(edges1) - 1; + i = BLI_array_len(edges1) - 1; v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; } - if (BLI_array_count(edges2) == 1) { + if (BLI_array_len(edges2) == 1) { v3 = edges2[0]->v1; v4 = edges2[0]->v2; } else { v3 = BM_vert_in_edge(edges2[1], edges2[0]->v1) ? edges2[0]->v2 : edges2[0]->v1; - i = BLI_array_count(edges2) - 1; + i = BLI_array_len(edges2) - 1; v4 = BM_vert_in_edge(edges2[i - 1], edges2[i]->v1) ? edges2[i]->v2 : edges2[i]->v1; } @@ -265,9 +265,9 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) else if (edges1) { BMVert *v1, *v2; - if (BLI_array_count(edges1) > 1) { + if (BLI_array_len(edges1) > 1) { v1 = BM_vert_in_edge(edges1[1], edges1[0]->v1) ? edges1[0]->v2 : edges1[0]->v1; - i = BLI_array_count(edges1) - 1; + i = BLI_array_len(edges1) - 1; v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE); BMO_edge_flag_enable(bm, e, ELE_NEW); diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c index 7d3419b591014c5064e59d62b92ef574185d8df5..8f998797a16c81890b19c56e4133c346e7c374b4 100644 --- a/source/blender/bmesh/operators/bmo_subdivide.c +++ b/source/blender/bmesh/operators/bmo_subdivide.c @@ -1157,7 +1157,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) loops[a] = l; } - vlen = BLI_array_count(loops); + vlen = BLI_array_len(loops); /* find the boundary of one of the split edges */ for (a = 1; a < vlen; a++) { @@ -1236,9 +1236,9 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) * - concave corner of an ngon. * - 2 edges being used in 2+ ngons. */ -// BM_face_splits_check_legal(bm, face, loops_split, BLI_array_count(loops_split)); +// BM_face_splits_check_legal(bm, face, loops_split, BLI_array_len(loops_split)); - for (j = 0; j < BLI_array_count(loops_split); j++) { + for (j = 0; j < BLI_array_len(loops_split); j++) { if (loops_split[j][0]) { BMFace *f_new; BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL); diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index beee9065eceeb6316143e346cdcf1389e40b666d..457e74ce1aa020cadea1b308e4e983b113ae5501 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -3209,7 +3209,7 @@ static void build_center_ngon(BMesh *bm, BevVert *bv, int mat_nr) BLI_array_append(ve, NULL); } } while ((v = v->next) != vm->boundstart); - bev_create_ngon(bm, vv, BLI_array_count(vv), vf, frep, ve, mat_nr, true); + bev_create_ngon(bm, vv, BLI_array_len(vv), vf, frep, ve, mat_nr, true); BLI_array_free(vv); BLI_array_free(vf); @@ -3960,7 +3960,7 @@ static int bevel_edge_order_extend(BMesh *bm, BevVert *bv, int i) BLI_array_append(sucs, bme2); } } - nsucs = BLI_array_count(sucs); + nsucs = BLI_array_len(sucs); bestj = j = i; for (sucindex = 0; sucindex < nsucs; sucindex++) { @@ -4500,15 +4500,15 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f) } } if (do_rebuild) { - n = BLI_array_count(vv); + n = BLI_array_len(vv); f_new = bev_create_ngon(bm, vv, n, NULL, f, NULL, -1, true); - for (k = 0; k < BLI_array_count(vv_fix); k++) { + for (k = 0; k < BLI_array_len(vv_fix); k++) { bev_merge_uvs(bm, vv_fix[k]); } /* copy attributes from old edges */ - BLI_assert(n == BLI_array_count(ee)); + BLI_assert(n == BLI_array_len(ee)); bme_prev = ee[n - 1]; for (k = 0; k < n; k++) { bme_new = BM_edge_exists(vv[k], vv[(k + 1) % n]); diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp index 53c1afd173f32df2f2c7a14395383992715c00d3..1df0705c855f96c5e5086a75be4f78caf8bc751d 100644 --- a/source/blender/collada/AnimationExporter.cpp +++ b/source/blender/collada/AnimationExporter.cpp @@ -772,7 +772,7 @@ void AnimationExporter::dae_baked_animation(std::vector<float> &fra, Object *ob_ addSampler(sampler); - std::string target = get_joint_id(bone, ob_arm) + "/transform"; + std::string target = get_joint_id(ob_arm, bone) + "/transform"; addChannel(COLLADABU::URI(empty, sampler_id), target); closeAnimation(); diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp index 844be2dd60bd76a57609c399f390168a15209816..fbceb6e077f200436149a796c336ea3239b9f7f7 100644 --- a/source/blender/collada/ArmatureExporter.cpp +++ b/source/blender/collada/ArmatureExporter.cpp @@ -89,7 +89,7 @@ void ArmatureExporter::add_armature_bones(const EvaluationContext *eval_ctx, Obj void ArmatureExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone) { if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) - ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm))); + ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone))); else { for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { write_bone_URLs(ins, ob_arm, child); @@ -162,9 +162,9 @@ void ArmatureExporter::add_bone_node(const EvaluationContext *eval_ctx, Bone *bo std::list<Object *>& child_objects) { if (!(this->export_settings->deform_bones_only && bone->flag & BONE_NO_DEFORM)) { - std::string node_id = get_joint_id(bone, ob_arm); + std::string node_id = get_joint_id(ob_arm, bone); std::string node_name = std::string(bone->name); - std::string node_sid = get_joint_sid(bone, ob_arm); + std::string node_sid = get_joint_sid(bone); COLLADASW::Node node(mSW); diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp index ae99e6bafdece1e9d4bdb09827bdff3cbe2a26a2..f32cb624f780a7d5ddb8cd7598d467b8964bc09f 100644 --- a/source/blender/collada/ControllerExporter.cpp +++ b/source/blender/collada/ControllerExporter.cpp @@ -71,7 +71,7 @@ bool ControllerExporter::is_skinned_mesh(Object *ob) void ControllerExporter::write_bone_URLs(COLLADASW::InstanceController &ins, Object *ob_arm, Bone *bone) { if (bc_is_root_bone(bone, this->export_settings->deform_bones_only)) - ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(bone, ob_arm))); + ins.addSkeleton(COLLADABU::URI(COLLADABU::Utils::EMPTY_STRING, get_joint_id(ob_arm, bone))); else { for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { write_bone_URLs(ins, ob_arm, child); @@ -456,7 +456,7 @@ std::string ControllerExporter::add_joints_source(Object *ob_arm, ListBase *defb for (def = (bDeformGroup *)defbase->first; def; def = def->next) { Bone *bone = get_bone_from_defgroup(ob_arm, def); if (bone) - source.appendValues(get_joint_sid(bone, ob_arm)); + source.appendValues(get_joint_sid(bone)); } source.finish(); diff --git a/source/blender/collada/collada_internal.cpp b/source/blender/collada/collada_internal.cpp index 6ebde6bd773a7cd4457af782fe485329cf46c6f4..cf4dcb5eb4232af51d75baa269895a9b349b5fae 100644 --- a/source/blender/collada/collada_internal.cpp +++ b/source/blender/collada/collada_internal.cpp @@ -327,12 +327,12 @@ std::string get_light_id(Object *ob) return translate_id(id_name(ob)) + "-light"; } -std::string get_joint_id(Bone *bone, Object *ob_arm) +std::string get_joint_id(Object *ob, Bone *bone) { - return translate_id(id_name(ob_arm) + "_" + bone->name); + return translate_id(id_name(ob) + "_" + bone->name); } -std::string get_joint_sid(Bone *bone, Object *ob_arm) +std::string get_joint_sid(Bone *bone) { return translate_id(bone->name); } diff --git a/source/blender/collada/collada_internal.h b/source/blender/collada/collada_internal.h index 1c7aa160f5782b4c0c5aacfdbcfde51d8ec50e75..299e13326ce8aba18bcda1bf32d7ea97de180d1c 100644 --- a/source/blender/collada/collada_internal.h +++ b/source/blender/collada/collada_internal.h @@ -97,8 +97,8 @@ extern std::string get_geometry_id(Object *ob, bool use_instantiation); extern std::string get_light_id(Object *ob); -extern std::string get_joint_id(Bone *bone, Object *ob_arm); -extern std::string get_joint_sid(Bone *bone, Object *ob_arm); +extern std::string get_joint_id(Object *ob, Bone *bone); +extern std::string get_joint_sid(Bone *bone); extern std::string get_camera_id(Object *ob); diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index 477c0dd36ea2570ed1b0075e288c59234f30e843..5cd1b48e80e332bf7477fd3661ad215bf1f3ec0f 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -280,6 +280,32 @@ typedef void (*DEG_EditorUpdateSceneCb)( void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG_EditorUpdateSceneCb scene_func); +/* Evaluation Debug ------------------------------ */ + +void DEG_debug_print_eval(const char* function_name, + const char* object_name, + const void* object_address); + +void DEG_debug_print_eval_subdata(const char *function_name, + const char *object_name, + const void *object_address, + const char *subdata_comment, + const char *subdata_name, + const void *subdata_address); + +void DEG_debug_print_eval_subdata_index(const char *function_name, + const char *object_name, + const void *object_address, + const char *subdata_comment, + const char *subdata_name, + const void *subdata_address, + const int subdata_index); + +void DEG_debug_print_eval_time(const char* function_name, + const char* object_name, + const void* object_address, + float time); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc index ee4ffee772e6daa415f81969633c195868c84293..a2e6993e44262991f3faede453c9ffecee06a15e 100644 --- a/source/blender/depsgraph/intern/depsgraph.cc +++ b/source/blender/depsgraph/intern/depsgraph.cc @@ -35,6 +35,8 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" +#include "BLI_console.h" +#include "BLI_hash.h" #include "BLI_ghash.h" #include "BLI_listbase.h" @@ -526,6 +528,31 @@ void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, } } +bool deg_terminal_do_color(void) +{ + return (G.debug & G_DEBUG_DEPSGRAPH_PRETTY) != 0; +} + +string deg_color_for_pointer(const void *pointer) +{ + if (!deg_terminal_do_color()) { + return ""; + } + int r, g, b; + BLI_hash_pointer_to_color(pointer, &r, &g, &b); + char buffer[64]; + BLI_snprintf(buffer, sizeof(buffer), TRUECOLOR_ANSI_COLOR_FORMAT, r, g, b); + return string(buffer); +} + +string deg_color_end(void) +{ + if (!deg_terminal_do_color()) { + return ""; + } + return string(TRUECOLOR_ANSI_COLOR_FINISH); +} + } // namespace DEG /* **************** */ @@ -553,3 +580,85 @@ void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func, DEG::deg_editor_update_id_cb = id_func; DEG::deg_editor_update_scene_cb = scene_func; } + +/* Evaluation and debug */ + +void DEG_debug_print_eval(const char *function_name, + const char *object_name, + const void *object_address) +{ + if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) { + return; + } + printf("%s on %s %s(%p)%s\n", + function_name, + object_name, + DEG::deg_color_for_pointer(object_address).c_str(), + object_address, + DEG::deg_color_end().c_str()); +} + +void DEG_debug_print_eval_subdata(const char *function_name, + const char *object_name, + const void *object_address, + const char *subdata_comment, + const char *subdata_name, + const void *subdata_address) +{ + if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) { + return; + } + printf("%s on %s %s(%p)%s %s %s %s(%p)%s\n", + function_name, + object_name, + DEG::deg_color_for_pointer(object_address).c_str(), + object_address, + DEG::deg_color_end().c_str(), + subdata_comment, + subdata_name, + DEG::deg_color_for_pointer(subdata_address).c_str(), + subdata_address, + DEG::deg_color_end().c_str()); +} + +void DEG_debug_print_eval_subdata_index(const char *function_name, + const char *object_name, + const void *object_address, + const char *subdata_comment, + const char *subdata_name, + const void *subdata_address, + const int subdata_index) +{ + if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) { + return; + } + printf("%s on %s %s(%p)^%s %s %s[%d] %s(%p)%s\n", + function_name, + object_name, + DEG::deg_color_for_pointer(object_address).c_str(), + object_address, + DEG::deg_color_end().c_str(), + subdata_comment, + subdata_name, + subdata_index, + DEG::deg_color_for_pointer(subdata_address).c_str(), + subdata_address, + DEG::deg_color_end().c_str()); +} + +void DEG_debug_print_eval_time(const char *function_name, + const char *object_name, + const void *object_address, + float time) +{ + if ((G.debug & G_DEBUG_DEPSGRAPH_EVAL) == 0) { + return; + } + printf("%s on %s %s(%p)%s at time %f\n", + function_name, + object_name, + DEG::deg_color_for_pointer(object_address).c_str(), + object_address, + DEG::deg_color_end().c_str(), + time); +} diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h index e310608b25e430906a8160505ff848012808d0af..9961723ed175452e0a36b3ad2d05e27dd938297b 100644 --- a/source/blender/depsgraph/intern/depsgraph_intern.h +++ b/source/blender/depsgraph/intern/depsgraph_intern.h @@ -125,4 +125,8 @@ void deg_editors_scene_update(const DEGEditorUpdateContext *update_ctx, fflush(stderr); \ } while (0) +bool deg_terminal_do_color(void); +string deg_color_for_pointer(const void *pointer); +string deg_color_end(void); + } // namespace DEG diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index f9e99227337ea847972423d7765104110b6c2db0..5be955438010a3e6064a4e6cda152b6ffcf635db 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -870,6 +870,22 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, gpumaterial_ptr = &world->gpumaterial; break; } + case ID_NT: + { + /* Node trees should try to preserve their socket pointers + * as much as possible. This is due to UBOs code in GPU, + * which references sockets from trees. + * + * These flags CURRENTLY don't need full datablock update, + * everything is done by node tree update function which + * only copies socket values. + */ + const int ignore_flag = (ID_RECALC_DRAW | ID_RECALC_ANIMATION); + if ((id_cow->recalc & ~ignore_flag) == 0) { + return id_cow; + } + break; + } case ID_OB: { Object *object = (Object *)id_cow; diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 6618aaea4f4786b8c1f57dd89db06dca6cbb2be5..733e4b0b52412113d42076f4ffe88975003dec7a 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -132,6 +132,9 @@ if(WITH_CLAY_ENGINE) endif() data_to_c_simple(engines/clay/shaders/clay_frag.glsl SRC) +data_to_c_simple(engines/clay/shaders/clay_fxaa.glsl SRC) +data_to_c_simple(engines/clay/shaders/clay_copy.glsl SRC) +data_to_c_simple(engines/clay/shaders/clay_prepass_frag.glsl SRC) data_to_c_simple(engines/clay/shaders/clay_vert.glsl SRC) data_to_c_simple(engines/clay/shaders/clay_particle_vert.glsl SRC) data_to_c_simple(engines/clay/shaders/clay_particle_strand_frag.glsl SRC) diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c index 655031b83b819b9a22fcc23869d363f9662ce5bd..382551b16e40df596b2c08baa20b806a272220b2 100644 --- a/source/blender/draw/engines/clay/clay_engine.c +++ b/source/blender/draw/engines/clay/clay_engine.c @@ -20,7 +20,7 @@ */ #include "BLI_utildefines.h" -#include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "BLI_rand.h" #include "DNA_particle_types.h" @@ -51,17 +51,24 @@ #define MAX_CLAY_MAT 512 /* 512 = 9 bit material id */ -#define SHADER_DEFINES \ +#define SHADER_DEFINES_NO_AO \ "#define MAX_MATERIAL " STRINGIFY(MAX_CLAY_MAT) "\n" \ "#define USE_ROTATION\n" \ - "#define USE_AO\n" \ "#define USE_HSV\n" +#define SHADER_DEFINES \ + SHADER_DEFINES_NO_AO \ + "#define USE_AO\n" + extern char datatoc_clay_frag_glsl[]; +extern char datatoc_clay_prepass_frag_glsl[]; +extern char datatoc_clay_copy_glsl[]; extern char datatoc_clay_vert_glsl[]; +extern char datatoc_clay_fxaa_glsl[]; extern char datatoc_clay_particle_vert_glsl[]; extern char datatoc_clay_particle_strand_frag_glsl[]; extern char datatoc_ssao_alchemy_glsl[]; +extern char datatoc_common_fxaa_lib_glsl[]; /* *********** LISTS *********** */ @@ -111,6 +118,8 @@ typedef struct CLAY_Storage { int hair_ubo_current_id; DRWShadingGroup *shgrps[MAX_CLAY_MAT]; DRWShadingGroup *shgrps_flat[MAX_CLAY_MAT]; + DRWShadingGroup *shgrps_pre[MAX_CLAY_MAT]; + DRWShadingGroup *shgrps_pre_flat[MAX_CLAY_MAT]; DRWShadingGroup *hair_shgrps[MAX_CLAY_MAT]; } CLAY_Storage; @@ -120,24 +129,33 @@ typedef struct CLAY_StorageList { } CLAY_StorageList; typedef struct CLAY_FramebufferList { - /* default */ - struct GPUFrameBuffer *default_fb; - /* engine specific */ - struct GPUFrameBuffer *dupli_depth; + struct GPUFrameBuffer *antialias_fb; + struct GPUFrameBuffer *prepass_fb; } CLAY_FramebufferList; typedef struct CLAY_PassList { - struct DRWPass *depth_pass; - struct DRWPass *depth_pass_cull; - struct DRWPass *clay_pass; - struct DRWPass *clay_pass_flat; + struct DRWPass *clay_ps; + struct DRWPass *clay_cull_ps; + struct DRWPass *clay_flat_ps; + struct DRWPass *clay_flat_cull_ps; + struct DRWPass *clay_pre_ps; + struct DRWPass *clay_pre_cull_ps; + struct DRWPass *clay_flat_pre_ps; + struct DRWPass *clay_flat_pre_cull_ps; + struct DRWPass *clay_deferred_ps; + struct DRWPass *fxaa_ps; + struct DRWPass *copy_ps; struct DRWPass *hair_pass; } CLAY_PassList; +typedef struct CLAY_TextureList { + struct GPUTexture *color_copy; /* only used if fxaa */ +} CLAY_TextureList; + typedef struct CLAY_Data { void *engine_type; CLAY_FramebufferList *fbl; - DRWViewportEmptyList *txl; + CLAY_TextureList *txl; CLAY_PassList *psl; CLAY_StorageList *stl; } CLAY_Data; @@ -154,27 +172,22 @@ typedef struct CLAY_ViewLayerData { /* *********** STATIC *********** */ static struct { - /* Depth Pre Pass */ - struct GPUShader *depth_sh; /* Shading Pass */ struct GPUShader *clay_sh; struct GPUShader *clay_flat_sh; + struct GPUShader *clay_prepass_flat_sh; + struct GPUShader *clay_prepass_sh; + struct GPUShader *clay_deferred_shading_sh; + struct GPUShader *fxaa_sh; + struct GPUShader *copy_sh; struct GPUShader *hair_sh; - /* Matcap textures */ struct GPUTexture *matcap_array; float matcap_colors[24][4]; - - /* Ssao */ - float winmat[4][4]; - float viewvecs[3][4]; - float ssao_params[4]; - /* Just a serie of int from 0 to MAX_CLAY_MAT-1 */ int ubo_mat_idxs[MAX_CLAY_MAT]; - - /* engine specific */ - struct GPUTexture *depth_dup; + /* To avoid useless texture and ubo binds. */ + bool first_shgrp; } e_data = {NULL}; /* Engine data */ typedef struct CLAY_PrivateData { @@ -184,7 +197,15 @@ typedef struct CLAY_PrivateData { DRWShadingGroup *depth_shgrp_cull; DRWShadingGroup *depth_shgrp_cull_select; DRWShadingGroup *depth_shgrp_cull_active; - bool enable_ao; + /* Deferred shading */ + struct GPUTexture *depth_tx; /* ref only, not alloced */ + struct GPUTexture *normal_tx; /* ref only, not alloced */ + struct GPUTexture *id_tx; /* ref only, not alloced */ + bool enable_deferred_path; + /* Ssao */ + float winmat[4][4]; + float viewvecs[3][4]; + float ssao_params[4]; } CLAY_PrivateData; /* Transient data */ /* Functions */ @@ -330,6 +351,7 @@ static struct GPUTexture *create_jitter_texture(int num_samples) static void clay_engine_init(void *vedata) { CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; + CLAY_TextureList *txl = ((CLAY_Data *)vedata)->txl; CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl; CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get(); @@ -366,31 +388,44 @@ static void clay_engine_init(void *vedata) e_data.matcap_array = load_matcaps(prv, 24); } - /* Depth prepass */ - if (!e_data.depth_sh) { - e_data.depth_sh = DRW_shader_create_3D_depth_only(); - } - /* Shading pass */ if (!e_data.clay_sh) { - DynStr *ds = BLI_dynstr_new(); - char *matcap_with_ao; - - BLI_dynstr_append(ds, datatoc_clay_frag_glsl); - BLI_dynstr_append(ds, datatoc_ssao_alchemy_glsl); - - matcap_with_ao = BLI_dynstr_get_cstring(ds); + char *matcap_with_ao = BLI_string_joinN( + datatoc_clay_frag_glsl, + datatoc_ssao_alchemy_glsl); e_data.clay_sh = DRW_shader_create( - datatoc_clay_vert_glsl, NULL, matcap_with_ao, - SHADER_DEFINES); + datatoc_clay_vert_glsl, NULL, datatoc_clay_frag_glsl, + SHADER_DEFINES_NO_AO); e_data.clay_flat_sh = DRW_shader_create( - datatoc_clay_vert_glsl, NULL, matcap_with_ao, + datatoc_clay_vert_glsl, NULL, datatoc_clay_frag_glsl, + SHADER_DEFINES_NO_AO + "#define USE_FLAT_NORMAL\n"); + + e_data.clay_prepass_sh = DRW_shader_create( + datatoc_clay_vert_glsl, NULL, datatoc_clay_prepass_frag_glsl, + SHADER_DEFINES); + e_data.clay_prepass_flat_sh = DRW_shader_create( + datatoc_clay_vert_glsl, NULL, datatoc_clay_prepass_frag_glsl, SHADER_DEFINES "#define USE_FLAT_NORMAL\n"); - BLI_dynstr_free(ds); + e_data.clay_deferred_shading_sh = DRW_shader_create_fullscreen( + matcap_with_ao, + SHADER_DEFINES + "#define DEFERRED_SHADING\n"); + MEM_freeN(matcap_with_ao); + + char *fxaa_str = BLI_string_joinN( + datatoc_common_fxaa_lib_glsl, + datatoc_clay_fxaa_glsl); + + e_data.fxaa_sh = DRW_shader_create_fullscreen(fxaa_str, NULL); + + MEM_freeN(fxaa_str); + + e_data.copy_sh = DRW_shader_create_fullscreen(datatoc_clay_copy_glsl, NULL); } if (!e_data.hair_sh) { @@ -403,6 +438,12 @@ static void clay_engine_init(void *vedata) stl->storage = MEM_callocN(sizeof(CLAY_Storage), "CLAY_Storage"); } + if (!stl->g_data) { + stl->g_data = MEM_mallocN(sizeof(*stl->g_data), "CLAY_PrivateStorage"); + } + + CLAY_PrivateData *g_data = stl->g_data; + if (!sldata->mat_ubo) { sldata->mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL); } @@ -424,8 +465,15 @@ static void clay_engine_init(void *vedata) if (DRW_state_is_fbo()) { const float *viewport_size = DRW_viewport_size_get(); - DRWFboTexture tex = {&e_data.depth_dup, DRW_TEX_DEPTH_24_STENCIL_8, DRW_TEX_TEMP}; - DRW_framebuffer_init(&fbl->dupli_depth, &draw_engine_clay_type, + DRWFboTexture texs[2] = {{&g_data->normal_tx, DRW_TEX_RG_8, DRW_TEX_TEMP}, + {&g_data->id_tx, DRW_TEX_R_16I, DRW_TEX_TEMP}}; + DRW_framebuffer_init(&fbl->prepass_fb, &draw_engine_clay_type, + (int)viewport_size[0], (int)viewport_size[1], + texs, 2); + + /* For FXAA */ + DRWFboTexture tex = {&txl->color_copy, DRW_TEX_RGBA_8, DRW_TEX_FILTER}; + DRW_framebuffer_init(&fbl->antialias_fb, &draw_engine_clay_type, (int)viewport_size[0], (int)viewport_size[1], &tex, 1); } @@ -453,14 +501,14 @@ static void clay_engine_init(void *vedata) DRW_state_dfdy_factors_get(dfdyfacs); - e_data.ssao_params[0] = ssao_samples; - e_data.ssao_params[1] = size[0] / 64.0; - e_data.ssao_params[2] = size[1] / 64.0; - e_data.ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */ + g_data->ssao_params[0] = ssao_samples; + g_data->ssao_params[1] = size[0] / 64.0; + g_data->ssao_params[2] = size[1] / 64.0; + g_data->ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */ /* invert the view matrix */ - DRW_viewport_matrix_get(e_data.winmat, DRW_MAT_WIN); - invert_m4_m4(invproj, e_data.winmat); + DRW_viewport_matrix_get(g_data->winmat, DRW_MAT_WIN); + invert_m4_m4(invproj, g_data->winmat); /* convert the view vectors to view space */ for (i = 0; i < 3; i++) { @@ -472,19 +520,19 @@ static void clay_engine_init(void *vedata) mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); viewvecs[i][3] = 1.0; - copy_v4_v4(e_data.viewvecs[i], viewvecs[i]); + copy_v4_v4(g_data->viewvecs[i], viewvecs[i]); } /* we need to store the differences */ - e_data.viewvecs[1][0] -= e_data.viewvecs[0][0]; - e_data.viewvecs[1][1] = e_data.viewvecs[2][1] - e_data.viewvecs[0][1]; + g_data->viewvecs[1][0] -= g_data->viewvecs[0][0]; + g_data->viewvecs[1][1] = g_data->viewvecs[2][1] - g_data->viewvecs[0][1]; /* calculate a depth offset as well */ if (!is_persp) { float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; mul_m4_v4(invproj, vec_far); mul_v3_fl(vec_far, 1.0f / vec_far[3]); - e_data.viewvecs[1][2] = vec_far[2] - e_data.viewvecs[0][2]; + g_data->viewvecs[1][2] = vec_far[2] - g_data->viewvecs[0][2]; } /* AO Samples Tex */ @@ -503,37 +551,56 @@ static void clay_engine_init(void *vedata) } } -static DRWShadingGroup *CLAY_shgroup_create(CLAY_Data *UNUSED(vedata), DRWPass *pass, int *material_id, bool use_flat) +static DRWShadingGroup *CLAY_shgroup_create(DRWPass *pass, GPUShader *sh, int id) { CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get(); - DRWShadingGroup *grp = DRW_shgroup_create(use_flat ? e_data.clay_flat_sh : e_data.clay_sh, pass); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_int(grp, "mat_id", &e_data.ubo_mat_idxs[id], 1); + if (e_data.first_shgrp) { + DRW_shgroup_uniform_texture_persistent(grp, "matcaps", e_data.matcap_array); + DRW_shgroup_uniform_block_persistent(grp, "material_block", sldata->mat_ubo); + DRW_shgroup_uniform_block_persistent(grp, "matcaps_block", sldata->matcaps_ubo); + } + return grp; +} - DRW_shgroup_uniform_vec2(grp, "screenres", DRW_viewport_size_get(), 1); - DRW_shgroup_uniform_buffer(grp, "depthtex", &e_data.depth_dup); - DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array); - DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)e_data.winmat); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)e_data.viewvecs, 3); - DRW_shgroup_uniform_vec4(grp, "ssao_params", e_data.ssao_params, 1); +static DRWShadingGroup *CLAY_shgroup_deferred_prepass_create(DRWPass *pass, GPUShader *sh, int id) +{ + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_int(grp, "mat_id", &e_data.ubo_mat_idxs[id], 1); - DRW_shgroup_uniform_int(grp, "mat_id", material_id, 1); + return grp; +} +static DRWShadingGroup *CLAY_shgroup_deferred_shading_create(DRWPass *pass, CLAY_PrivateData *g_data) +{ + CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get(); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.clay_deferred_shading_sh, pass); + DRW_shgroup_uniform_buffer(grp, "depthtex", &g_data->depth_tx); + DRW_shgroup_uniform_buffer(grp, "normaltex", &g_data->normal_tx); + DRW_shgroup_uniform_buffer(grp, "idtex", &g_data->id_tx); + DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array); DRW_shgroup_uniform_texture(grp, "ssao_jitter", sldata->jitter_tx); DRW_shgroup_uniform_block(grp, "samples_block", sldata->sampling_ubo); DRW_shgroup_uniform_block(grp, "material_block", sldata->mat_ubo); DRW_shgroup_uniform_block(grp, "matcaps_block", sldata->matcaps_ubo); - + /* TODO put in ubo */ + DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)g_data->winmat); + DRW_shgroup_uniform_vec2(grp, "invscreenres", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)g_data->viewvecs, 3); + DRW_shgroup_uniform_vec4(grp, "ssao_params", g_data->ssao_params, 1); return grp; } -static DRWShadingGroup *CLAY_hair_shgroup_create(CLAY_Data *UNUSED(vedata), DRWPass *pass, int *material_id) +static DRWShadingGroup *CLAY_hair_shgroup_create(DRWPass *pass, int id) { CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get(); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.hair_sh, pass); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.hair_sh, pass); DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array); - DRW_shgroup_uniform_int(grp, "mat_id", material_id, 1); DRW_shgroup_uniform_block(grp, "material_block", sldata->mat_ubo); DRW_shgroup_uniform_block(grp, "matcaps_block", sldata->matcaps_ubo); + DRW_shgroup_uniform_int(grp, "mat_id", &e_data.ubo_mat_idxs[id], 1); return grp; } @@ -568,25 +635,17 @@ static int search_hair_mat_to_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Mat static int push_mat_to_ubo(CLAY_Storage *storage, const CLAY_UBO_Material *mat_ubo_test) { - int id = storage->ubo_current_id; - CLAY_UBO_Material *ubo = &storage->mat_storage.materials[id]; - - *ubo = *mat_ubo_test; - - storage->ubo_current_id++; - + int id = storage->ubo_current_id++; + id = min_ii(MAX_CLAY_MAT, id); + storage->mat_storage.materials[id] = *mat_ubo_test; return id; } static int push_hair_mat_to_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material *hair_mat_ubo_test) { - int id = storage->hair_ubo_current_id; - CLAY_HAIR_UBO_Material *ubo = &storage->hair_mat_storage.materials[id]; - - *ubo = *hair_mat_ubo_test; - - storage->hair_ubo_current_id++; - + int id = storage->hair_ubo_current_id++; + id = min_ii(MAX_CLAY_MAT, id); + storage->hair_mat_storage.materials[id] = *hair_mat_ubo_test; return id; } @@ -616,11 +675,11 @@ static int hair_mat_in_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material * return id; } -static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo, bool *r_needs_ao) +static void ubo_mat_from_object(CLAY_Storage *storage, Object *ob, bool *r_needs_ao, int *r_id) { IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY); - /* Default Settings */ + int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon"); float matcap_rot = BKE_collection_engine_property_value_get_float(props, "matcap_rotation"); float matcap_hue = BKE_collection_engine_property_value_get_float(props, "matcap_hue"); float matcap_sat = BKE_collection_engine_property_value_get_float(props, "matcap_saturation"); @@ -629,41 +688,45 @@ static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo, bool *r_ne float ssao_factor_cavity = BKE_collection_engine_property_value_get_float(props, "ssao_factor_cavity"); float ssao_factor_edge = BKE_collection_engine_property_value_get_float(props, "ssao_factor_edge"); float ssao_attenuation = BKE_collection_engine_property_value_get_float(props, "ssao_attenuation"); - int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon"); + + CLAY_UBO_Material r_ubo = {{0.0f}}; if (((ssao_factor_cavity > 0.0) || (ssao_factor_edge > 0.0)) && (ssao_distance > 0.0)) { *r_needs_ao = true; + + r_ubo.ssao_params_var[0] = ssao_distance; + r_ubo.ssao_params_var[1] = ssao_factor_cavity; + r_ubo.ssao_params_var[2] = ssao_factor_edge; + r_ubo.ssao_params_var[3] = ssao_attenuation; + } + else { + *r_needs_ao = false; } - memset(r_ubo, 0x0, sizeof(*r_ubo)); + r_ubo.matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f); + r_ubo.matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f); - r_ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f); - r_ubo->matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f); + r_ubo.matcap_hsv[0] = matcap_hue + 0.5f; + r_ubo.matcap_hsv[1] = matcap_sat * 2.0f; + r_ubo.matcap_hsv[2] = matcap_val * 2.0f; - r_ubo->matcap_hsv[0] = matcap_hue + 0.5f; - r_ubo->matcap_hsv[1] = matcap_sat * 2.0f; - r_ubo->matcap_hsv[2] = matcap_val * 2.0f; + r_ubo.matcap_id = matcap_to_index(matcap_icon); - r_ubo->ssao_params_var[0] = ssao_distance; - r_ubo->ssao_params_var[1] = ssao_factor_cavity; - r_ubo->ssao_params_var[2] = ssao_factor_edge; - r_ubo->ssao_params_var[3] = ssao_attenuation; - r_ubo->matcap_id = matcap_to_index(matcap_icon); + *r_id = mat_in_ubo(storage, &r_ubo); } -static void hair_ubo_mat_from_object(Object *ob, CLAY_HAIR_UBO_Material *r_ubo) +static void hair_ubo_mat_from_object(Object *ob, CLAY_HAIR_UBO_Material *r_ubo) { IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY); - /* Default Settings */ + int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon"); float matcap_rot = BKE_collection_engine_property_value_get_float(props, "matcap_rotation"); float matcap_hue = BKE_collection_engine_property_value_get_float(props, "matcap_hue"); float matcap_sat = BKE_collection_engine_property_value_get_float(props, "matcap_saturation"); float matcap_val = BKE_collection_engine_property_value_get_float(props, "matcap_value"); float hair_randomness = BKE_collection_engine_property_value_get_float(props, "hair_brightness_randomness"); - int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon"); memset(r_ubo, 0x0, sizeof(*r_ubo)); @@ -676,25 +739,56 @@ static void hair_ubo_mat_from_object(Object *ob, CLAY_HAIR_UBO_Material *r_ubo) r_ubo->matcap_id = matcap_to_index(matcap_icon); } -static DRWShadingGroup *CLAY_object_shgrp_get( - CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl, bool use_flat) +static DRWShadingGroup *CLAY_object_shgrp_get(CLAY_Data *vedata, Object *ob, bool use_flat, bool cull) { - DRWShadingGroup **shgrps = use_flat ? stl->storage->shgrps_flat : stl->storage->shgrps; - CLAY_UBO_Material mat_ubo_test; + bool prepass; int id; + CLAY_PassList *psl = vedata->psl; + CLAY_Storage *storage = vedata->stl->storage; + DRWShadingGroup **shgrps; + DRWPass *pass; GPUShader *sh; + + ubo_mat_from_object(storage, ob, &prepass, &id); + + if (prepass) { + if (use_flat) { + shgrps = storage->shgrps_pre_flat; + pass = (cull) ? psl->clay_flat_pre_cull_ps : psl->clay_flat_pre_ps; + sh = e_data.clay_prepass_flat_sh; + } + else { + shgrps = storage->shgrps_pre; + pass = (cull) ? psl->clay_pre_cull_ps : psl->clay_pre_ps; + sh = e_data.clay_prepass_sh; + } - ubo_mat_from_object(ob, &mat_ubo_test, &stl->g_data->enable_ao); + if (shgrps[id] == NULL) { + shgrps[id] = CLAY_shgroup_deferred_prepass_create(pass, sh, id); + } - int id = mat_in_ubo(stl->storage, &mat_ubo_test); + vedata->stl->g_data->enable_deferred_path = true; + } + else { + if (use_flat) { + shgrps = storage->shgrps_flat; + pass = (cull) ? psl->clay_flat_cull_ps : psl->clay_flat_ps; + sh = e_data.clay_flat_sh; + } + else { + shgrps = storage->shgrps; + pass = (cull) ? psl->clay_cull_ps : psl->clay_ps; + sh = e_data.clay_sh; + } - if (shgrps[id] == NULL) { - shgrps[id] = CLAY_shgroup_create( - vedata, use_flat ? psl->clay_pass_flat : psl->clay_pass, &e_data.ubo_mat_idxs[id], use_flat); + if (shgrps[id] == NULL) { + shgrps[id] = CLAY_shgroup_create(pass, sh, id); + e_data.first_shgrp = false; + } } return shgrps[id]; } -static DRWShadingGroup *CLAY_hair_shgrp_get(CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl) +static DRWShadingGroup *CLAY_hair_shgrp_get(CLAY_Data *UNUSED(vedata), Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl) { DRWShadingGroup **hair_shgrps = stl->storage->hair_shgrps; @@ -704,54 +798,44 @@ static DRWShadingGroup *CLAY_hair_shgrp_get(CLAY_Data *vedata, Object *ob, CLAY_ int hair_id = hair_mat_in_ubo(stl->storage, &hair_mat_ubo_test); if (hair_shgrps[hair_id] == NULL) { - hair_shgrps[hair_id] = CLAY_hair_shgroup_create(vedata, psl->hair_pass, &e_data.ubo_mat_idxs[hair_id]); + hair_shgrps[hair_id] = CLAY_hair_shgroup_create(psl->hair_pass, hair_id); } return hair_shgrps[hair_id]; } -static DRWShadingGroup *CLAY_object_shgrp_default_mode_get( - CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl) -{ - bool use_flat = DRW_object_is_flat_normal(ob); - return CLAY_object_shgrp_get(vedata, ob, stl, psl, use_flat); -} - static void clay_cache_init(void *vedata) { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; - - if (!stl->g_data) { - /* Alloc transient pointers */ - stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); - } + CLAY_TextureList *txl = ((CLAY_Data *)vedata)->txl; /* Disable AO unless a material needs it. */ - stl->g_data->enable_ao = false; + stl->g_data->enable_deferred_path = false; - /* Depth Pass */ - { - psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); - stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass); - - psl->depth_pass_cull = DRW_pass_create( - "Depth Pass Cull", - DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK); - stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass_cull); - } + /* Reset UBO datas, shgrp pointers and material id counters. */ + memset(stl->storage, 0, sizeof(*stl->storage)); + e_data.first_shgrp = true; - /* Clay Pass */ + /* Solid Passes */ { - psl->clay_pass = DRW_pass_create("Clay Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); - stl->storage->ubo_current_id = 0; - memset(stl->storage->shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT); - } - - /* Clay Pass (Flat) */ - { - psl->clay_pass_flat = DRW_pass_create("Clay Pass Flat", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); - memset(stl->storage->shgrps_flat, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + psl->clay_ps = DRW_pass_create("Clay", state); + psl->clay_cull_ps = DRW_pass_create("Clay Culled", state | DRW_STATE_CULL_BACK); + psl->clay_flat_ps = DRW_pass_create("Clay Flat", state); + psl->clay_flat_cull_ps = DRW_pass_create("Clay Flat Culled", state | DRW_STATE_CULL_BACK); + + DRWState prepass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + DRWState prepass_cull_state = prepass_state | DRW_STATE_CULL_BACK; + psl->clay_pre_ps = DRW_pass_create("Clay Deferred Pre", prepass_state); + psl->clay_pre_cull_ps = DRW_pass_create("Clay Deferred Pre Culled", prepass_cull_state); + psl->clay_flat_pre_ps = DRW_pass_create("Clay Deferred Flat Pre", prepass_state); + psl->clay_flat_pre_cull_ps = DRW_pass_create("Clay Deferred Flat Pre Culled", prepass_cull_state); + + psl->clay_deferred_ps = DRW_pass_create("Clay Deferred Shading", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = CLAY_shgroup_deferred_shading_create(psl->clay_deferred_ps, stl->g_data); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } /* Hair Pass */ @@ -759,8 +843,19 @@ static void clay_cache_init(void *vedata) psl->hair_pass = DRW_pass_create( "Hair Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE); - stl->storage->hair_ubo_current_id = 0; - memset(stl->storage->hair_shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT); + } + + { + psl->fxaa_ps = DRW_pass_create("Fxaa", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.fxaa_sh, psl->fxaa_ps); + DRW_shgroup_uniform_buffer(grp, "colortex", &dtxl->color); + DRW_shgroup_uniform_vec2(grp, "invscreenres", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + + psl->copy_ps = DRW_pass_create("Copy", DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(e_data.copy_sh, psl->copy_ps); + DRW_shgroup_uniform_buffer(grp, "colortex", &txl->color_copy); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } } @@ -795,9 +890,6 @@ static void clay_cache_populate_particles(void *vedata, Object *ob) static void clay_cache_populate(void *vedata, Object *ob) { - CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; - CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; - DRWShadingGroup *clay_shgrp; if (!DRW_object_is_renderable(ob)) @@ -825,26 +917,9 @@ static void clay_cache_populate(void *vedata, Object *ob) IDProperty *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, ""); const bool do_cull = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_backface_culling"); const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0; - const bool is_default_mode_shader = is_sculpt_mode; + const bool use_flat = is_sculpt_mode && DRW_object_is_flat_normal(ob); - /* Depth Prepass */ - { - DRWShadingGroup *depth_shgrp = do_cull ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp; - if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_add(depth_shgrp, ob, ob->obmat); - } - else { - DRW_shgroup_call_object_add(depth_shgrp, geom, ob); - } - } - - /* Shading */ - if (is_default_mode_shader) { - clay_shgrp = CLAY_object_shgrp_default_mode_get(vedata, ob, stl, psl); - } - else { - clay_shgrp = CLAY_object_shgrp_get(vedata, ob, stl, psl, false); - } + clay_shgrp = CLAY_object_shgrp_get(vedata, ob, use_flat, do_cull); if (is_sculpt_mode) { DRW_shgroup_call_sculpt_add(clay_shgrp, ob, ob->obmat); @@ -870,37 +945,50 @@ static void clay_draw_scene(void *vedata) CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + stl->g_data->depth_tx = dtxl->depth; + + /* Passes are ordered to have less _potential_ overdraw */ + DRW_draw_pass(psl->clay_cull_ps); + DRW_draw_pass(psl->clay_flat_cull_ps); + DRW_draw_pass(psl->clay_ps); + DRW_draw_pass(psl->clay_flat_ps); + DRW_draw_pass(psl->hair_pass); - /* Pass 1 : Depth pre-pass */ - if (stl->g_data->enable_ao) { - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); - } - else { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; - DRW_pass_state_set(psl->clay_pass, state); - DRW_pass_state_set(psl->clay_pass_flat, state); - } + if (stl->g_data->enable_deferred_path) { + if (DRW_state_is_fbo()) { + DRW_framebuffer_texture_detach(dtxl->depth); + DRW_framebuffer_texture_attach(fbl->prepass_fb, dtxl->depth, 0, 0); + DRW_framebuffer_texture_attach(fbl->prepass_fb, stl->g_data->normal_tx, 0, 0); + DRW_framebuffer_texture_attach(fbl->prepass_fb, stl->g_data->id_tx, 1, 0); + DRW_framebuffer_bind(fbl->prepass_fb); + /* We need to clear the id texture unfortunately. */ + DRW_framebuffer_clear(true, false, false, (float[4]){0.0f, 0.0f, 0.0f, 0.0f}, 0.0f); + } - /* Pass 2 : Duplicate depth */ - /* Unless we go for deferred shading we need this to avoid manual depth test and artifacts */ - if (DRW_state_is_fbo() && stl->g_data->enable_ao) { - /* attach temp textures */ - DRW_framebuffer_texture_attach(fbl->dupli_depth, e_data.depth_dup, 0, 0); + DRW_draw_pass(psl->clay_pre_cull_ps); + DRW_draw_pass(psl->clay_flat_pre_cull_ps); + DRW_draw_pass(psl->clay_pre_ps); + DRW_draw_pass(psl->clay_flat_pre_ps); - DRW_framebuffer_blit(dfbl->default_fb, fbl->dupli_depth, true, false); + if (DRW_state_is_fbo()) { + DRW_framebuffer_texture_detach(dtxl->depth); + DRW_framebuffer_bind(dfbl->default_fb); - /* detach temp textures */ - DRW_framebuffer_texture_detach(e_data.depth_dup); + DRW_draw_pass(psl->clay_deferred_ps); - /* restore default fb */ - DRW_framebuffer_bind(dfbl->default_fb); + DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); + DRW_framebuffer_bind(dfbl->default_fb); + } } - /* Pass 3 : Shading */ - DRW_draw_pass(psl->clay_pass); - DRW_draw_pass(psl->clay_pass_flat); - DRW_draw_pass(psl->hair_pass); + if (true) { /* Always on for now. We might want a parameter for this. */ + DRW_framebuffer_bind(fbl->antialias_fb); + DRW_draw_pass(psl->fxaa_ps); + + DRW_framebuffer_bind(dfbl->default_fb); + DRW_draw_pass(psl->copy_ps); + } } static void clay_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) @@ -935,6 +1023,11 @@ static void clay_engine_free(void) { DRW_SHADER_FREE_SAFE(e_data.clay_sh); DRW_SHADER_FREE_SAFE(e_data.clay_flat_sh); + DRW_SHADER_FREE_SAFE(e_data.clay_prepass_flat_sh); + DRW_SHADER_FREE_SAFE(e_data.clay_prepass_sh); + DRW_SHADER_FREE_SAFE(e_data.clay_deferred_shading_sh); + DRW_SHADER_FREE_SAFE(e_data.fxaa_sh); + DRW_SHADER_FREE_SAFE(e_data.copy_sh); DRW_SHADER_FREE_SAFE(e_data.hair_sh); DRW_TEXTURE_FREE_SAFE(e_data.matcap_array); } diff --git a/source/blender/draw/engines/clay/shaders/clay_copy.glsl b/source/blender/draw/engines/clay/shaders/clay_copy.glsl new file mode 100644 index 0000000000000000000000000000000000000000..ec462978e67c3f1e4623e1dbfcef9e4219e65e16 --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_copy.glsl @@ -0,0 +1,10 @@ + +in vec4 uvcoordsvar; +out vec4 fragColor; + +uniform sampler2D colortex; + +void main() +{ + fragColor = texture(colortex, uvcoordsvar.st); +} diff --git a/source/blender/draw/engines/clay/shaders/clay_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_frag.glsl index 619843e2a02d3b9f92a7be9fae51eaa260ba9984..f2c6cd5f78079dcaa0b22000d17f15d4d9ddb87d 100644 --- a/source/blender/draw/engines/clay/shaders/clay_frag.glsl +++ b/source/blender/draw/engines/clay/shaders/clay_frag.glsl @@ -1,5 +1,4 @@ -uniform vec2 screenres; -uniform sampler2D depthtex; +uniform vec2 invscreenres; uniform mat4 WinMatrix; /* Matcap */ @@ -33,7 +32,14 @@ layout(std140) uniform material_block { Material matcaps_param[MAX_MATERIAL]; }; +#ifdef DEFERRED_SHADING +uniform sampler2D depthtex; +uniform sampler2D normaltex; +uniform isampler2D idtex; +int mat_id; /* global */ +#else uniform int mat_id; +#endif /* Aliases */ #define ssao_samples_num ssao_params.x @@ -44,10 +50,12 @@ uniform int mat_id; #define matcap_index matcaps_param[mat_id].matcap_hsv_id.w #define matcap_rotation matcaps_param[mat_id].matcap_rot.xy -#ifdef USE_FLAT_NORMAL +#ifndef DEFERRED_SHADING +# ifdef USE_FLAT_NORMAL flat in vec3 normal; -#else +# else in vec3 normal; +# endif #endif out vec4 fragColor; @@ -169,24 +177,33 @@ void ssao_factors( out float cavities, out float edges); #endif -void main() { - vec2 screenco = vec2(gl_FragCoord.xy) / screenres; - float depth = texture(depthtex, screenco).r; - - vec3 position = get_view_space_from_depth(screenco, depth); +/* From http://aras-p.info/texts/CompactNormalStorage.html + * Using Method #4: Spheremap Transform */ +vec3 normal_decode(vec2 enc) +{ + vec2 fenc = enc * 4.0 - 2.0; + float f = dot(fenc, fenc); + float g = sqrt(1.0 - f / 4.0); + vec3 n; + n.xy = fenc*g; + n.z = 1 - f / 2; + return n; +} +vec3 shade(vec3 N, vec3 position, float depth, vec2 screenco) +{ #ifdef USE_ROTATION /* Rotate texture coordinates */ vec2 rotY = vec2(-matcap_rotation.y, matcap_rotation.x); - vec2 texco = abs(vec2(dot(normal.xy, matcap_rotation), dot(normal.xy, rotY)) * .49 + 0.5); + vec2 texco = abs(vec2(dot(N.xy, matcap_rotation), dot(N.xy, rotY)) * .49 + 0.5); #else - vec2 texco = abs(normal.xy * .49 + 0.5); + vec2 texco = abs(N.xy * .49 + 0.5); #endif vec3 col = texture(matcaps, vec3(texco, matcap_index)).rgb; #ifdef USE_AO - float cavity, edges; - ssao_factors(depth, normal, position, screenco, cavity, edges); + float cavity = 0.0, edges = 0.0; + ssao_factors(depth, N, position, screenco, cavity, edges); col *= mix(vec3(1.0), matcaps_color[int(matcap_index)].rgb, cavity); #endif @@ -200,5 +217,35 @@ void main() { col *= edges + 1.0; #endif + return col; +} + +void main() +{ + vec2 screenco = vec2(gl_FragCoord.xy) * invscreenres; + +#ifdef DEFERRED_SHADING + mat_id = texture(idtex, screenco).r; + + /* early out (manual stencil test) */ + if (mat_id == 0) + discard; + + float depth = texture(depthtex, screenco).r; + vec3 N = normal_decode(texture(normaltex, screenco).rg); + /* see the prepass for explanations. */ + if (mat_id < 0) { + N = -N; + } + mat_id = abs(mat_id) - 1; +#else + float depth = gl_FragCoord.z; + vec3 N = normal; +#endif + + vec3 position = get_view_space_from_depth(screenco, depth); + + vec3 col = shade(N, position, depth, screenco); + fragColor = vec4(col, 1.0); } diff --git a/source/blender/draw/engines/clay/shaders/clay_fxaa.glsl b/source/blender/draw/engines/clay/shaders/clay_fxaa.glsl new file mode 100644 index 0000000000000000000000000000000000000000..1a34927aaa65677e99dfc931c0ad4feff558ae43 --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_fxaa.glsl @@ -0,0 +1,18 @@ + +in vec4 uvcoordsvar; +out vec4 fragColor; + +uniform vec2 invscreenres; +uniform sampler2D colortex; + +void main() +{ + fragColor = FxaaPixelShader( + uvcoordsvar.st, + colortex, + invscreenres, + 1.0, + 0.166, + 0.0833 + ); +} diff --git a/source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl new file mode 100644 index 0000000000000000000000000000000000000000..8eb22a7854c8e0a2af68218d40af4f58acf44f47 --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl @@ -0,0 +1,44 @@ +uniform int mat_id; + +#ifdef USE_FLAT_NORMAL +flat in vec3 normal; +#else +in vec3 normal; +#endif + +layout(location = 0) out vec2 outNormals; +layout(location = 1) out int outIndex; + +/* From http://aras-p.info/texts/CompactNormalStorage.html + * Using Method #4: Spheremap Transform */ +vec2 normal_encode(vec3 n) +{ + float p = sqrt(n.z * 8.0 + 8.0); + return n.xy / p + 0.5; +} + +/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */ +#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0)) +const mat4 dither_mat = mat4( + vec4( P(0.0), P(8.0), P(2.0), P(10.0)), + vec4(P(12.0), P(4.0), P(14.0), P(6.0)), + vec4( P(3.0), P(11.0), P(1.0), P(9.0)), + vec4(P(15.0), P(7.0), P(13.0), P(5.0)) +); + +void main() { + outIndex = (mat_id + 1); /* 0 is clear color */ + /** + * To fix the normal buffer precision issue for backfaces, + * we invert normals and use the sign of the index buffer + * to tag them, and re-invert in deferred pass. + **/ + vec3 N = (gl_FrontFacing) ? normal : -normal; + outIndex = (gl_FrontFacing) ? outIndex : -outIndex; + + outNormals = normal_encode(N); + + /* Dither the output to fight low quality. */ + ivec2 tx = ivec2(gl_FragCoord.xy) % 4; + outNormals += dither_mat[tx.x][tx.y]; +} diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c index 1b015a51f6a91baf2a3a6f8da6ba70f95df1a4de..c62f35a70e706a4fa43e76ece50a79688fed0e71 100644 --- a/source/blender/draw/engines/eevee/eevee_bloom.c +++ b/source/blender/draw/engines/eevee/eevee_bloom.c @@ -41,7 +41,7 @@ static struct { struct GPUShader *bloom_downsample_sh[2]; struct GPUShader *bloom_upsample_sh[2]; struct GPUShader *bloom_resolve_sh[2]; -} e_data = {NULL}; /* Engine data */ +} e_data = {{NULL}}; /* Engine data */ extern char datatoc_effect_bloom_frag_glsl[]; diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index b1bfc45037d1ef631c0e50f25a2d682894d4a57c..6cfecd0a226fe06660ebae0276516b5603747250 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -334,10 +334,6 @@ static void eevee_draw_background(void *vedata) EEVEE_volumes_free_smoke_textures(); - if (DRW_state_is_image_render()) { - MULTISAMPLE_SYNC_ENABLE(dfbl); - } - stl->g_data->view_updated = false; } diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index f1124436838b9470abf60e9b3a8395295589e847..6215445e11371f7996a77eab405fb5d5596293a0 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -858,6 +858,8 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get( vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state); DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); + /* XXX / WATCH: This creates non persistent binds for the ubos and textures. + * But it's currently OK because the following shgroups does not add any bind. */ add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false); } diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 4ae18b24bdc49a9078ca1a6c19b2c38f21eb5ff2..96d560688f342ac9257b7522b70f3773ccd13ce9 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -48,7 +48,7 @@ static struct { /* Theses are just references, not actually allocated */ struct GPUTexture *depth_src; struct GPUTexture *color_src; -} e_data = {NULL}; /* Engine data */ +} e_data = {{NULL}}; /* Engine data */ extern char datatoc_ambient_occlusion_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index be62a4076154400887b3a3dd393c2d0a9cf47236..12a70cc2fe746e58710df557c410996efcf1a562 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -34,7 +34,7 @@ static struct { struct GPUShader *sss_sh[4]; -} e_data = {NULL}; /* Engine data */ +} e_data = {{NULL}}; /* Engine data */ extern char datatoc_common_view_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 26ac449807377a540d4c30d94b2b8c5c6a19b466..0c0ffa391463a5663e617682209f2b1cb3f6c75a 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -472,17 +472,20 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, sldata->common_data.vol_tex_size[2]); + /* If shader failed to compile or is currently compiling. */ + if (grp == NULL) { + return; + } + /* Making sure it's updated. */ invert_m4_m4(ob->imat, ob->obmat); BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize); - if (grp) { - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", (float *)ob->imat); - DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); - DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); - } + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", (float *)ob->imat); + DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); + DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); /* Smoke Simulation */ if (((ob->base_flag & BASE_FROMDUPLI) == 0) && diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 937e88051c2d164c3341a2db05ab1e3eebe2792f..791d38ff62f721f2d53e8bf5855d1a1b800b1148 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -182,6 +182,7 @@ typedef enum { DRW_TEX_RG_32, DRW_TEX_R_8, DRW_TEX_R_16, + DRW_TEX_R_16I, DRW_TEX_R_32, DRW_TEX_DEPTH_16, DRW_TEX_DEPTH_24, @@ -381,7 +382,9 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask); void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); +void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo); +void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo); void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex); void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); @@ -428,6 +431,7 @@ void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type); void DRW_viewport_matrix_override_unset_all(void); const float *DRW_viewport_size_get(void); +const float *DRW_viewport_invert_size_get(void); const float *DRW_viewport_screenvecs_get(void); const float *DRW_viewport_pixelsize_get(void); bool DRW_viewport_is_persp_get(void); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index b44c5b8a20b856a512b0ed65b60d8abb13df3cd3..f7a82c6d0c53c4890dae5ff43492c62f26828db6 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -1665,6 +1665,46 @@ void DRW_mesh_batch_cache_dirty(Mesh *me, int mode) } } +/** + * This only clear the batches associated to the given vertex buffer. + **/ +static void mesh_batch_cache_clear_selective(Mesh *me, Gwn_VertBuf *vert) +{ + MeshBatchCache *cache = me->batch_cache; + if (!cache) { + return; + } + + BLI_assert(vert != NULL); + + if (cache->pos_with_normals == vert) { + GWN_BATCH_DISCARD_SAFE(cache->triangles_with_normals); + GWN_BATCH_DISCARD_SAFE(cache->triangles_with_weights); + GWN_BATCH_DISCARD_SAFE(cache->triangles_with_vert_colors); + GWN_BATCH_DISCARD_SAFE(cache->triangles_with_select_id); + GWN_BATCH_DISCARD_SAFE(cache->triangles_with_select_mask); + GWN_BATCH_DISCARD_SAFE(cache->points_with_normals); + if (cache->shaded_triangles) { + for (int i = 0; i < cache->mat_len; ++i) { + GWN_BATCH_DISCARD_SAFE(cache->shaded_triangles[i]); + } + } + MEM_SAFE_FREE(cache->shaded_triangles); + if (cache->texpaint_triangles) { + for (int i = 0; i < cache->mat_len; ++i) { + GWN_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]); + } + } + MEM_SAFE_FREE(cache->texpaint_triangles); + GWN_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single); + } + /* TODO: add the other ones if needed. */ + else { + /* Does not match any vertbuf in the batch cache! */ + BLI_assert(0); + } +} + static void mesh_batch_cache_clear(Mesh *me) { MeshBatchCache *cache = me->batch_cache; @@ -3878,21 +3918,10 @@ void DRW_mesh_cache_sculpt_coords_ensure(Mesh *me) if (me->batch_cache) { MeshBatchCache *cache = mesh_batch_cache_get(me); if (cache && cache->pos_with_normals && cache->is_sculpt_points_tag) { - - const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY; - MeshRenderData *rdata = mesh_render_data_create(me, datatype); - - Gwn_VertBuf *pos_with_normals = cache->pos_with_normals; - cache->pos_with_normals = NULL; - GWN_vertbuf_clear(pos_with_normals); - Gwn_VertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); - *pos_with_normals = *vbo; - GWN_vertformat_copy(&pos_with_normals->format, &vbo->format); - - free(vbo); - cache->pos_with_normals = pos_with_normals; - - mesh_render_data_free(rdata); + /* XXX Force update of all the batches that contains the pos_with_normals buffer. + * TODO(fclem): Ideally, Gawain should provide a way to update a buffer without destroying it. */ + mesh_batch_cache_clear_selective(me, cache->pos_with_normals); + GWN_VERTBUF_DISCARD_SAFE(cache->pos_with_normals); } cache->is_sculpt_points_tag = false; } diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index 86b2af5080c40825c713aed570ff8d4e60941cc7..ee73a2ba2c63ba42e1fe2fd12603f61f9be18d1e 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -156,7 +156,7 @@ void DRW_batching_buffer_request( } /* Create the batch. */ bbuf = chunk->bbufs + new_id; - bbuf->vert = *r_vert = GWN_vertbuf_create_dynamic_with_format(format); + bbuf->vert = *r_vert = GWN_vertbuf_create_with_format_ex(format, GWN_USAGE_DYNAMIC); bbuf->batch = *r_batch = GWN_batch_create_ex(type, bbuf->vert, NULL, 0); bbuf->format = format; bbuf->shgroup = shgroup; @@ -197,7 +197,7 @@ void DRW_instancing_buffer_request( } /* Create the batch. */ ibuf = chunk->ibufs + new_id; - ibuf->vert = *r_vert = GWN_vertbuf_create_dynamic_with_format(format); + ibuf->vert = *r_vert = GWN_vertbuf_create_with_format_ex(format, GWN_USAGE_DYNAMIC); ibuf->batch = *r_batch = GWN_batch_duplicate(instance); ibuf->format = format; ibuf->shgroup = shgroup; diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 2f8cf04f476e748191ae2be055444f660365ea6c..dbcfa02c555713346f0f44285e19a30a0c223c99 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -297,7 +297,12 @@ void DRW_engine_viewport_data_size_get( const float *DRW_viewport_size_get(void) { - return &DST.size[0]; + return DST.size; +} + +const float *DRW_viewport_invert_size_get(void) +{ + return DST.inv_size; } const float *DRW_viewport_screenvecs_get(void) @@ -364,6 +369,8 @@ static void drw_viewport_var_init(void) GPU_viewport_size_get(DST.viewport, size); DST.size[0] = size[0]; DST.size[1] = size[1]; + DST.inv_size[0] = 1.0f / size[0]; + DST.inv_size[1] = 1.0f / size[1]; DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get(DST.viewport); DST.default_framebuffer = fbl->default_fb; @@ -393,6 +400,9 @@ static void drw_viewport_var_init(void) DST.size[0] = 0; DST.size[1] = 0; + DST.inv_size[0] = 0; + DST.inv_size[1] = 0; + DST.default_framebuffer = NULL; DST.vmempool = NULL; } @@ -436,13 +446,13 @@ static void drw_viewport_var_init(void) DST.RST.bound_texs = MEM_callocN(sizeof(GPUTexture *) * GPU_max_textures(), "Bound GPUTexture refs"); } if (DST.RST.bound_tex_slots == NULL) { - DST.RST.bound_tex_slots = MEM_callocN(sizeof(bool) * GPU_max_textures(), "Bound Texture Slots"); + DST.RST.bound_tex_slots = MEM_callocN(sizeof(char) * GPU_max_textures(), "Bound Texture Slots"); } if (DST.RST.bound_ubos == NULL) { DST.RST.bound_ubos = MEM_callocN(sizeof(GPUUniformBuffer *) * GPU_max_ubo_binds(), "Bound GPUUniformBuffer refs"); } if (DST.RST.bound_ubo_slots == NULL) { - DST.RST.bound_ubo_slots = MEM_callocN(sizeof(bool) * GPU_max_textures(), "Bound Ubo Slots"); + DST.RST.bound_ubo_slots = MEM_callocN(sizeof(char) * GPU_max_textures(), "Bound Ubo Slots"); } if (view_ubo == NULL) { @@ -1133,7 +1143,11 @@ void DRW_draw_render_loop_ex( drw_engines_cache_finish(); DRW_render_instance_buffer_finish(); - PROFILE_END_ACCUM(DST.cache_time, stime); + +#ifdef USE_PROFILE + double *cache_time = GPU_viewport_cache_time_get(DST.viewport); + PROFILE_END_UPDATE(*cache_time, stime); +#endif } DRW_stats_begin(); diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h index bde6a4ab24d64f22d8c09d6c8099c87bcfe50c72..c7e9b3dc08de3bd1f69197fee1ae21960d338538 100644 --- a/source/blender/draw/intern/draw_manager.h +++ b/source/blender/draw/intern/draw_manager.h @@ -52,7 +52,7 @@ #ifdef USE_PROFILE # include "PIL_time.h" -# define PROFILE_TIMER_FALLOFF 0.1 +# define PROFILE_TIMER_FALLOFF 0.04 # define PROFILE_START(time_start) \ double time_start = PIL_check_seconds_timer(); @@ -159,8 +159,10 @@ typedef enum { DRW_UNIFORM_INT, DRW_UNIFORM_FLOAT, DRW_UNIFORM_TEXTURE, + DRW_UNIFORM_TEXTURE_PERSIST, DRW_UNIFORM_BUFFER, - DRW_UNIFORM_BLOCK + DRW_UNIFORM_BLOCK, + DRW_UNIFORM_BLOCK_PERSIST } DRWUniformType; struct DRWUniform { @@ -278,6 +280,7 @@ typedef struct DRWManager { GPUViewport *viewport; struct GPUFrameBuffer *default_framebuffer; float size[2]; + float inv_size[2]; float screenvecs[2][3]; float pixsize; @@ -301,9 +304,6 @@ typedef struct DRWManager { bool buffer_finish_called; /* Avoid bad usage of DRW_render_instance_buffer_finish */ - /* Profiling */ - double cache_time; - /* View dependant uniforms. */ DRWMatrixState original_mat; /* Original rv3d matrices. */ int override_mat; /* Bitflag of which matrices are overriden. */ @@ -334,10 +334,10 @@ typedef struct DRWManager { /** GPU Resource State: Memory storage between drawing. */ struct { GPUTexture **bound_texs; - bool *bound_tex_slots; + char *bound_tex_slots; int bind_tex_inc; GPUUniformBuffer **bound_ubos; - bool *bound_ubo_slots; + char *bound_ubo_slots; int bind_ubo_inc; } RST; } DRWManager; diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 4648c321f2652c520b47b5e33016853e5854402b..b1db3b63777a0ca00a1a0ef202c5536f71816d9b 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -99,7 +99,7 @@ static void drw_interface_uniform(DRWShadingGroup *shgroup, const char *name, DRWUniformType type, const void *value, int length, int arraysize) { int location; - if (type == DRW_UNIFORM_BLOCK) { + if (ELEM(type, DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_PERSIST)) { location = GPU_shader_get_uniform_block(shgroup->shader, name); } else { @@ -126,12 +126,26 @@ void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, con drw_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1); } +/* Same as DRW_shgroup_uniform_texture but is garanteed to be bound if shader does not change between shgrp. */ +void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex) +{ + BLI_assert(tex != NULL); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_PERSIST, tex, 0, 1); +} + void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo) { BLI_assert(ubo != NULL); drw_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1); } +/* Same as DRW_shgroup_uniform_block but is garanteed to be bound if shader does not change between shgrp. */ +void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo) +{ + BLI_assert(ubo != NULL); + drw_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK_PERSIST, ubo, 0, 1); +} + void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) { drw_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1); @@ -461,7 +475,7 @@ static void drw_interface_init(DRWShadingGroup *shgroup, GPUShader *shader) int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock"); if (view_ubo_location != -1) { - drw_interface_uniform_create_ex(shgroup, view_ubo_location, DRW_UNIFORM_BLOCK, view_ubo, 0, 1); + drw_interface_uniform_create_ex(shgroup, view_ubo_location, DRW_UNIFORM_BLOCK_PERSIST, view_ubo, 0, 1); } else { /* Only here to support builtin shaders. This should not be used by engines. */ diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 19b55190e6c9e06aaad67b862a3e20aca808a992..e90c1f63ecd280575b84eaa70eea1a7343300400 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -704,63 +704,87 @@ static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom) draw_geometry_execute_ex(shgroup, geom, 0, 0, false); } -static void bind_texture(GPUTexture *tex) +enum { + BIND_NONE = 0, + BIND_TEMP = 1, /* Release slot after this shading group. */ + BIND_PERSIST = 2, /* Release slot only after the next shader change. */ +}; + +static void bind_texture(GPUTexture *tex, char bind_type) { + int index; + char *slot_flags = DST.RST.bound_tex_slots; int bind_num = GPU_texture_bound_number(tex); if (bind_num == -1) { for (int i = 0; i < GPU_max_textures(); ++i) { - DST.RST.bind_tex_inc = (DST.RST.bind_tex_inc + 1) % GPU_max_textures(); - if (DST.RST.bound_tex_slots[DST.RST.bind_tex_inc] == false) { - if (DST.RST.bound_texs[DST.RST.bind_tex_inc] != NULL) { - GPU_texture_unbind(DST.RST.bound_texs[DST.RST.bind_tex_inc]); + index = DST.RST.bind_tex_inc = (DST.RST.bind_tex_inc + 1) % GPU_max_textures(); + if (slot_flags[index] == BIND_NONE) { + if (DST.RST.bound_texs[index] != NULL) { + GPU_texture_unbind(DST.RST.bound_texs[index]); } - GPU_texture_bind(tex, DST.RST.bind_tex_inc); - DST.RST.bound_texs[DST.RST.bind_tex_inc] = tex; - DST.RST.bound_tex_slots[DST.RST.bind_tex_inc] = true; + GPU_texture_bind(tex, index); + DST.RST.bound_texs[index] = tex; + slot_flags[index] = bind_type; // printf("Binds Texture %d %p\n", DST.RST.bind_tex_inc, tex); return; } } - printf("Not enough texture slots! Reduce number of textures used by your shader.\n"); } - DST.RST.bound_tex_slots[bind_num] = true; + slot_flags[bind_num] = bind_type; } -static void bind_ubo(GPUUniformBuffer *ubo) +static void bind_ubo(GPUUniformBuffer *ubo, char bind_type) { + int index; + char *slot_flags = DST.RST.bound_ubo_slots; int bind_num = GPU_uniformbuffer_bindpoint(ubo); if (bind_num == -1) { for (int i = 0; i < GPU_max_ubo_binds(); ++i) { - DST.RST.bind_ubo_inc = (DST.RST.bind_ubo_inc + 1) % GPU_max_ubo_binds(); - if (DST.RST.bound_ubo_slots[DST.RST.bind_ubo_inc] == false) { - if (DST.RST.bound_ubos[DST.RST.bind_ubo_inc] != NULL) { - GPU_uniformbuffer_unbind(DST.RST.bound_ubos[DST.RST.bind_ubo_inc]); + index = DST.RST.bind_ubo_inc = (DST.RST.bind_ubo_inc + 1) % GPU_max_ubo_binds(); + if (slot_flags[index] == BIND_NONE) { + if (DST.RST.bound_ubos[index] != NULL) { + GPU_uniformbuffer_unbind(DST.RST.bound_ubos[index]); } - GPU_uniformbuffer_bind(ubo, DST.RST.bind_ubo_inc); - DST.RST.bound_ubos[DST.RST.bind_ubo_inc] = ubo; - DST.RST.bound_ubo_slots[DST.RST.bind_ubo_inc] = true; + GPU_uniformbuffer_bind(ubo, index); + DST.RST.bound_ubos[index] = ubo; + slot_flags[bind_num] = bind_type; return; } } - /* This is not depending on user input. - * It is our responsability to make sure there enough slots. */ - BLI_assert(0 && "Not enough ubo slots! This should not happen!\n"); - /* printf so user can report bad behaviour */ printf("Not enough ubo slots! This should not happen!\n"); + /* This is not depending on user input. + * It is our responsability to make sure there is enough slots. */ + BLI_assert(0); } - DST.RST.bound_ubo_slots[bind_num] = true; + slot_flags[bind_num] = bind_type; } -static void release_texture_slots(void) +static void release_texture_slots(bool with_persist) { - memset(DST.RST.bound_tex_slots, 0x0, sizeof(bool) * GPU_max_textures()); + if (with_persist) { + memset(DST.RST.bound_tex_slots, 0x0, sizeof(*DST.RST.bound_tex_slots) * GPU_max_textures()); + } + else { + for (int i = 0; i < GPU_max_textures(); ++i) { + if (DST.RST.bound_tex_slots[i] != BIND_PERSIST) + DST.RST.bound_tex_slots[i] = BIND_NONE; + } + } } -static void release_ubo_slots(void) +static void release_ubo_slots(bool with_persist) { - memset(DST.RST.bound_ubo_slots, 0x0, sizeof(bool) * GPU_max_textures()); + if (with_persist) { + memset(DST.RST.bound_ubo_slots, 0x0, sizeof(*DST.RST.bound_ubo_slots) * GPU_max_ubo_binds()); + } + else { + for (int i = 0; i < GPU_max_ubo_binds(); ++i) { + if (DST.RST.bound_ubo_slots[i] != BIND_PERSIST) + DST.RST.bound_ubo_slots[i] = BIND_NONE; + } + } } static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) @@ -771,16 +795,17 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) GPUUniformBuffer *ubo; int val; float fval; + const bool shader_changed = (DST.shader != shgroup->shader); - if (DST.shader != shgroup->shader) { + if (shader_changed) { if (DST.shader) GPU_shader_unbind(); GPU_shader_bind(shgroup->shader); DST.shader = shgroup->shader; - - release_texture_slots(); - release_ubo_slots(); } + release_ubo_slots(shader_changed); + release_texture_slots(shader_changed); + drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra); drw_stencil_set(shgroup->stencil_mask); @@ -810,7 +835,13 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) case DRW_UNIFORM_TEXTURE: tex = (GPUTexture *)uni->value; BLI_assert(tex); - bind_texture(tex); + bind_texture(tex, BIND_TEMP); + GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); + break; + case DRW_UNIFORM_TEXTURE_PERSIST: + tex = (GPUTexture *)uni->value; + BLI_assert(tex); + bind_texture(tex, BIND_PERSIST); GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); break; case DRW_UNIFORM_BUFFER: @@ -819,12 +850,17 @@ static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) } tex = *((GPUTexture **)uni->value); BLI_assert(tex); - bind_texture(tex); + bind_texture(tex, BIND_TEMP); GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); break; case DRW_UNIFORM_BLOCK: ubo = (GPUUniformBuffer *)uni->value; - bind_ubo(ubo); + bind_ubo(ubo, BIND_TEMP); + GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + break; + case DRW_UNIFORM_BLOCK_PERSIST: + ubo = (GPUUniformBuffer *)uni->value; + bind_ubo(ubo, BIND_PERSIST); GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); break; } diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c index 8e5f98b5a49a7f70e3d4d947a85a158d01e3ae25..47769b1fb18382ccfaa4bb654e5cbbd76b12349e 100644 --- a/source/blender/draw/intern/draw_manager_profiling.c +++ b/source/blender/draw/intern/draw_manager_profiling.c @@ -286,9 +286,10 @@ void DRW_stats_draw(rcti *rect) v += 2; u = 0; + double *cache_time = GPU_viewport_cache_time_get(DST.viewport); sprintf(col_label, "Cache Time"); draw_stat_5row(rect, u++, v, col_label, sizeof(col_label)); - sprintf(time_to_txt, "%.2fms", DST.cache_time); + sprintf(time_to_txt, "%.2fms", *cache_time); draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt)); v += 2; diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index bbef680e77a87b0d7fe6ac4d0f7d9e9049d68faf..e033a0c506eda6932f8c06f56a7bb16c86d93292 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -35,6 +35,7 @@ void drw_texture_get_format( /* Only add formats that are COMPATIBLE with FB. * Generally they are multiple of 16bit. */ case DRW_TEX_R_16: + case DRW_TEX_R_16I: case DRW_TEX_R_32: case DRW_TEX_RG_8: case DRW_TEX_RG_16: @@ -70,6 +71,7 @@ void drw_texture_get_format( case DRW_TEX_RG_32: *r_data_type = GPU_RG32F; break; case DRW_TEX_R_8: *r_data_type = GPU_R8; break; case DRW_TEX_R_16: *r_data_type = GPU_R16F; break; + case DRW_TEX_R_16I: *r_data_type = GPU_R16I; break; case DRW_TEX_R_32: *r_data_type = GPU_R32F; break; #if 0 case DRW_TEX_RGB_8: *r_data_type = GPU_RGB8; break; diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index d137e5f1c74c4b5496aab4b68921bbf5ce4512fe..2f9d32eadb6ab0a0e080e3dd921e58896fb386e5 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -3090,7 +3090,7 @@ static bool select_anim_channel_keys(bAnimContext *ac, int channel_index, bool e for (ale = anim_data.first; ale; ale = ale->next) { FCurve *fcu_inner = (FCurve *)ale->key_data; - if (fcu_inner) { + if (fcu_inner != NULL && fcu_inner->bezt != NULL) { for (i = 0, bezt = fcu_inner->bezt; i < fcu_inner->totvert; i++, bezt++) { bezt->f2 = bezt->f1 = bezt->f3 = 0; } diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index a4eaf800801b352f6df03844027c22ac21382bd7..d6385276b1a75ad26133947ad1d20e3ca0549e64 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1221,11 +1221,9 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) void ui_but_override_flag(uiBut *but) { - bool is_overridden; + const int override_status = RNA_property_override_status(&but->rnapoin, but->rnaprop, but->rnaindex); - RNA_property_override_status(&but->rnapoin, but->rnaprop, but->rnaindex, NULL, &is_overridden, NULL, NULL); - - if (is_overridden) { + if (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN) { but->flag |= UI_BUT_OVERRIDEN; } else { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 3a01ff16297d361448c466db2738aecd3529ef76..b1dc30945c4c1a3d9589e9e4c25ab0ee7b5d9c99 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -6819,11 +6819,11 @@ static bool ui_but_menu(bContext *C, uiBut *but) 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_overridable; /*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */ bool is_set = RNA_property_is_set(ptr, prop); - RNA_property_override_status(ptr, prop, -1, &is_overridable, NULL, NULL, NULL); + const int override_status = RNA_property_override_status(ptr, prop, -1); + const bool is_overridable = (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE) != 0; /* second slower test, saved people finding keyframe items in menus when its not possible */ if (is_anim) diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 16525dfbc9eb0817c82b2ad376c31e15c9730036..ad4aaf599989a0e6bff6ad5fd2978d9f34019752 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -482,13 +482,12 @@ static int override_type_set_button_poll(bContext *C) PointerRNA ptr; PropertyRNA *prop; int index; - bool is_overridable; UI_context_active_but_prop_get(C, &ptr, &prop, &index); - RNA_property_override_status(&ptr, prop, index, &is_overridable, NULL, NULL, NULL); + const int override_status = RNA_property_override_status(&ptr, prop, index); - return (ptr.data && prop && is_overridable); + return (ptr.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDABLE)); } static int override_type_set_button_exec(bContext *C, wmOperator *op) @@ -572,13 +571,12 @@ static int override_remove_button_poll(bContext *C) PointerRNA ptr; PropertyRNA *prop; int index; - bool is_overridden; UI_context_active_but_prop_get(C, &ptr, &prop, &index); - RNA_property_override_status(&ptr, prop, index, NULL, &is_overridden, NULL, NULL); + const int override_status = RNA_property_override_status(&ptr, prop, index); - return (ptr.data && ptr.id.data && prop && is_overridden); + return (ptr.data && ptr.id.data && prop && (override_status & RNA_OVERRIDE_STATUS_OVERRIDDEN)); } static int override_remove_button_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index ca4ab30a08d74791d656575a9820109123439261..b584782e183d1fa0869fa7386cb8c41609aff274 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -59,6 +59,8 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "ED_object.h" + #include "UI_interface.h" #include "UI_resources.h" @@ -543,6 +545,12 @@ static int wm_alembic_import_exec(bContext *C, wmOperator *op) } } + /* Switch out of edit mode to avoid being stuck in it (T54326). */ + Object *obedit = CTX_data_edit_object(C); + if (obedit) { + ED_object_mode_toggle(C, OB_MODE_EDIT); + } + bool ok = ABC_import(C, filename, scale, is_sequence, set_frame_range, sequence_len, offset, validate_meshes, as_background_job); diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt index 80e1187609c2168bb8f9d2e11fea441ea8d3e7f5..3877838ec54cc5718f0973f82b89b9159d938252 100644 --- a/source/blender/editors/mesh/CMakeLists.txt +++ b/source/blender/editors/mesh/CMakeLists.txt @@ -60,6 +60,7 @@ set(SRC editmesh_undo.c editmesh_utils.c mesh_data.c + mesh_mirror.c mesh_ops.c meshtools.c diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 113173c1c03448393af9e790be4adfeeb0b469d2..1b9ee70ccf5f5c517af89fe47666e99dbed4db00 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -24,7 +24,6 @@ * \ingroup edmesh */ - #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" @@ -41,7 +40,6 @@ #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_context.h" -#include "BKE_editmesh.h" #include "BIF_gl.h" @@ -609,261 +607,3 @@ void paintvert_select_ungrouped(Object *ob, bool extend, bool flush_flags) paintvert_flush_flags(ob); } } - -/* ********************* MESH VERTEX MIRR TOPO LOOKUP *************** */ -/* note, this is not the best place for the function to be but moved - * here for the purpose of syncing with bmesh */ - -typedef unsigned int MirrTopoHash_t; - -typedef struct MirrTopoVert_t { - MirrTopoHash_t hash; - int v_index; -} MirrTopoVert_t; - -static int mirrtopo_hash_sort(const void *l1, const void *l2) -{ - if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1; - else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1; - return 0; -} - -static int mirrtopo_vert_sort(const void *v1, const void *v2) -{ - if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1; - else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1; - return 0; -} - -bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store) -{ - const bool is_editmode = (me->edit_btmesh != NULL); - int totvert; - int totedge; - - if (dm) { - totvert = dm->getNumVerts(dm); - totedge = dm->getNumEdges(dm); - } - else if (me->edit_btmesh) { - totvert = me->edit_btmesh->bm->totvert; - totedge = me->edit_btmesh->bm->totedge; - } - else { - totvert = me->totvert; - totedge = me->totedge; - } - - if ((mesh_topo_store->index_lookup == NULL) || - (mesh_topo_store->prev_is_editmode != is_editmode) || - (totvert != mesh_topo_store->prev_vert_tot) || - (totedge != mesh_topo_store->prev_edge_tot)) - { - return true; - } - else { - return false; - } - -} - -void ED_mesh_mirrtopo_init( - Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store, - const bool skip_em_vert_array_init) -{ - const bool is_editmode = (me->edit_btmesh != NULL); - MEdge *medge = NULL, *med; - BMEditMesh *em = dm ? NULL : me->edit_btmesh; - - /* editmode*/ - BMEdge *eed; - BMIter iter; - - int a, last; - int totvert, totedge; - int tot_unique = -1, tot_unique_prev = -1; - int tot_unique_edges = 0, tot_unique_edges_prev; - - MirrTopoHash_t *topo_hash = NULL; - MirrTopoHash_t *topo_hash_prev = NULL; - MirrTopoVert_t *topo_pairs; - MirrTopoHash_t topo_pass = 1; - - intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */ - - /* reallocate if needed */ - ED_mesh_mirrtopo_free(mesh_topo_store); - - mesh_topo_store->prev_is_editmode = is_editmode; - - if (em) { - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - totvert = em->bm->totvert; - } - else { - totvert = dm ? dm->getNumVerts(dm) : me->totvert; - } - - topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr"); - - /* Initialize the vert-edge-user counts used to detect unique topology */ - if (em) { - totedge = me->edit_btmesh->bm->totedge; - - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); - topo_hash[i1]++; - topo_hash[i2]++; - } - } - else { - totedge = dm ? dm->getNumEdges(dm) : me->totedge; - medge = dm ? dm->getEdgeArray(dm) : me->medge; - - for (a = 0, med = medge; a < totedge; a++, med++) { - const unsigned int i1 = med->v1, i2 = med->v2; - topo_hash[i1]++; - topo_hash[i2]++; - } - } - - topo_hash_prev = MEM_dupallocN(topo_hash); - - tot_unique_prev = -1; - tot_unique_edges_prev = -1; - while (1) { - /* use the number of edges per vert to give verts unique topology IDs */ - - tot_unique_edges = 0; - - /* This can make really big numbers, wrapping around here is fine */ - if (em) { - BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { - const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); - topo_hash[i1] += topo_hash_prev[i2] * topo_pass; - topo_hash[i2] += topo_hash_prev[i1] * topo_pass; - tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); - } - } - else { - for (a = 0, med = medge; a < totedge; a++, med++) { - const unsigned int i1 = med->v1, i2 = med->v2; - topo_hash[i1] += topo_hash_prev[i2] * topo_pass; - topo_hash[i2] += topo_hash_prev[i1] * topo_pass; - tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); - } - } - memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); - - /* sort so we can count unique values */ - qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort); - - tot_unique = 1; /* account for skiping the first value */ - for (a = 1; a < totvert; a++) { - if (topo_hash_prev[a - 1] != topo_hash_prev[a]) { - tot_unique++; - } - } - - if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) { - /* Finish searching for unique values when 1 loop dosnt give a - * higher number of unique values compared to the previous loop */ - break; - } - else { - tot_unique_prev = tot_unique; - tot_unique_edges_prev = tot_unique_edges; - } - /* Copy the hash calculated this iter, so we can use them next time */ - memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); - - topo_pass++; - } - - /* Hash/Index pairs are needed for sorting to find index pairs */ - topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs"); - - /* since we are looping through verts, initialize these values here too */ - index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup"); - - if (em) { - if (skip_em_vert_array_init == false) { - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - } - } - - for (a = 0; a < totvert; a++) { - topo_pairs[a].hash = topo_hash[a]; - topo_pairs[a].v_index = a; - - /* initialize lookup */ - index_lookup[a] = -1; - } - - qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort); - - last = 0; - - /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, - * but you cant ever access the last 'a' index of MirrTopoPairs */ - if (em) { - BMVert **vtable = em->bm->vtable; - for (a = 1; a <= totvert; a++) { - /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */ - if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { - const int match_count = a - last; - if (match_count == 2) { - const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; - index_lookup[j] = (intptr_t)vtable[k]; - index_lookup[k] = (intptr_t)vtable[j]; - } - else if (match_count == 1) { - /* Center vertex. */ - const int j = topo_pairs[a - 1].v_index; - index_lookup[j] = (intptr_t)vtable[j]; - } - last = a; - } - } - } - else { - /* same as above, for mesh */ - for (a = 1; a <= totvert; a++) { - if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { - const int match_count = a - last; - if (match_count == 2) { - const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; - index_lookup[j] = k; - index_lookup[k] = j; - } - else if (match_count == 1) { - /* Center vertex. */ - const int j = topo_pairs[a - 1].v_index; - index_lookup[j] = j; - } - last = a; - } - } - } - - MEM_freeN(topo_pairs); - topo_pairs = NULL; - - MEM_freeN(topo_hash); - MEM_freeN(topo_hash_prev); - - mesh_topo_store->index_lookup = index_lookup; - mesh_topo_store->prev_vert_tot = totvert; - mesh_topo_store->prev_edge_tot = totedge; -} - -void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store) -{ - if (mesh_topo_store->index_lookup) { - MEM_freeN(mesh_topo_store->index_lookup); - } - mesh_topo_store->index_lookup = NULL; - mesh_topo_store->prev_vert_tot = -1; - mesh_topo_store->prev_edge_tot = -1; -} diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index a21fc2fffdefb67dc52bcea58fa9f93ee3d6ac1d..292b28c772caf3e5461186c90f6fc5be8fb4bb40 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -65,9 +65,10 @@ typedef struct MakePrimitiveData { bool was_editmode; } MakePrimitiveData; -static Object *make_prim_init(bContext *C, const char *idname, - const float loc[3], const float rot[3], const unsigned int layer, - MakePrimitiveData *r_creation_data) +static Object *make_prim_init( + bContext *C, const char *idname, + const float loc[3], const float rot[3], const unsigned int layer, + MakePrimitiveData *r_creation_data) { Object *obedit = CTX_data_edit_object(C); diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 18320ec65f575e2e95c5d445cc3d99b761b64106..aee9785ea83bdfcd76d47623803d03fd6691bd72 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -66,6 +66,10 @@ #include "ED_util.h" #endif +/* -------------------------------------------------------------------- */ +/** \name Extrude Internal Utilities + * \{ */ + static void edbm_extrude_edge_exclude_mirror( Object *obedit, BMEditMesh *em, const char hflag, @@ -154,7 +158,7 @@ static bool edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const ch EDBM_flag_disable_all(em, BM_ELEM_SELECT); BMO_op_exec(em->bm, &bmop); - + BMO_ITER (f, &siter, bmop.slots_out, "faces.out", BM_FACE) { BM_face_select_set(em->bm, f, true); @@ -254,7 +258,7 @@ static bool edbm_extrude_ex( BMOIter siter; BMOperator extop; BMElem *ele; - + /* needed to remove the faces left behind */ if (htype & BM_FACE) { htype |= BM_EDGE; @@ -276,7 +280,7 @@ static bool edbm_extrude_ex( BM_SELECT_HISTORY_RESTORE(bm); BMO_op_exec(bm, &extop); - + BMO_ITER (ele, &siter, extop.slots_out, "geom.out", BM_ALL_NOLOOP) { BM_elem_select_set(bm, ele, true); } @@ -286,14 +290,20 @@ static bool edbm_extrude_ex( return true; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Repeat Operator + * \{ */ + static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); RegionView3D *rv3d = CTX_wm_region_view3d(C); - + const int steps = RNA_int_get(op->ptr, "steps"); - + const float offs = RNA_float_get(op->ptr, "offset"); float dvec[3], tmat[3][3], bmat[3][3]; short a; @@ -314,7 +324,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) "translate vec=%v verts=%hv", dvec, BM_ELEM_SELECT); } - + EDBM_mesh_normals_update(em); EDBM_update_generic(em, true, true); @@ -328,19 +338,25 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) ot->name = "Extrude Repeat Mesh"; ot->description = "Extrude selected vertices, edges or faces repeatedly"; ot->idname = "MESH_OT_extrude_repeat"; - + /* api callbacks */ ot->exec = edbm_extrude_repeat_exec; ot->poll = ED_operator_editmesh_view3d; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - + /* props */ RNA_def_float_distance(ot->srna, "offset", 2.0f, 0.0f, 1e12f, "Offset", "", 0.0f, 100.0f); RNA_def_int(ot->srna, "steps", 10, 0, 1000000, "Steps", "", 0, 180); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Operator + * \{ */ + /* generic extern called extruder */ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) { @@ -377,7 +393,7 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) changed = edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT); break; } - + if (changed) { return true; } @@ -392,7 +408,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); - + edbm_extrude_mesh(obedit, em, op); /* This normally happens when pushing undo but modal operators @@ -401,7 +417,7 @@ static int edbm_extrude_region_exec(bContext *C, wmOperator *op) EDBM_mesh_normals_update(em); EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -411,27 +427,33 @@ void MESH_OT_extrude_region(wmOperatorType *ot) ot->name = "Extrude Region"; ot->idname = "MESH_OT_extrude_region"; ot->description = "Extrude region of faces"; - + /* api callbacks */ //ot->invoke = mesh_extrude_region_invoke; ot->exec = edbm_extrude_region_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Verts Operator + * \{ */ + static int edbm_extrude_verts_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); - + EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -441,11 +463,11 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot) ot->name = "Extrude Only Vertices"; ot->idname = "MESH_OT_extrude_verts_indiv"; ot->description = "Extrude individual vertices only"; - + /* api callbacks */ ot->exec = edbm_extrude_verts_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -453,15 +475,21 @@ void MESH_OT_extrude_verts_indiv(wmOperatorType *ot) Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Edges Operator + * \{ */ + static int edbm_extrude_edges_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); edbm_extrude_edges_indiv(em, op, BM_ELEM_SELECT); - + EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -471,11 +499,11 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot) ot->name = "Extrude Only Edges"; ot->idname = "MESH_OT_extrude_edges_indiv"; ot->description = "Extrude individual edges only"; - + /* api callbacks */ ot->exec = edbm_extrude_edges_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -483,15 +511,21 @@ void MESH_OT_extrude_edges_indiv(wmOperatorType *ot) Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Faces Operator + * \{ */ + static int edbm_extrude_faces_exec(bContext *C, wmOperator *op) { Object *obedit = CTX_data_edit_object(C); BMEditMesh *em = BKE_editmesh_from_object(obedit); edbm_extrude_discrete_faces(em, op, BM_ELEM_SELECT); - + EDBM_update_generic(em, true, true); - + return OPERATOR_FINISHED; } @@ -501,18 +535,25 @@ void MESH_OT_extrude_faces_indiv(wmOperatorType *ot) ot->name = "Extrude Individual Faces"; ot->idname = "MESH_OT_extrude_faces_indiv"; ot->description = "Extrude individual faces only"; - + /* api callbacks */ ot->exec = edbm_extrude_faces_exec; ot->poll = ED_operator_editmesh; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } -/* *************** add-click-mesh (extrude) operator ************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Dupli-Extrude Operator + * + * Add-click-mesh (extrude) operator. + * \{ */ + static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ViewContext vc; @@ -533,7 +574,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w zero_v3(center); verts_len = 0; - + BM_ITER_MESH (v1, &iter, vc.em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v1, BM_ELEM_SELECT)) { add_v3_v3(center, v1->co); @@ -596,7 +637,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w cross_v3_v3v3(nor, view_vec, cross); normalize_v3(nor); } - + /* center */ copy_v3_v3(ofs, center); @@ -605,7 +646,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w mul_m4_v3(vc.obedit->imat, ofs); // back in object space sub_v3_v3(ofs, center); - + /* calculate rotation */ unit_m3(mat); if (done) { @@ -628,7 +669,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w axis_angle_to_mat3(mat, axis, angle); } } - + if (rot_src) { EDBM_op_callf(vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, center, mat); @@ -653,7 +694,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w ED_view3d_win_to_3d_int(vc.v3d, vc.ar, center, event->mval, center); mul_m4_v3(vc.obedit->imat, center); // back in object space - + EDBM_op_init(vc.em, &bmop, op, "create_vert co=%v", center); BMO_op_exec(vc.em->bm, &bmop); @@ -685,17 +726,22 @@ void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot) ot->name = "Duplicate or Extrude to Cursor"; ot->idname = "MESH_OT_dupli_extrude_cursor"; ot->description = "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor"; - + /* api callbacks */ ot->invoke = edbm_dupli_extrude_cursor_invoke; ot->poll = ED_operator_editmesh_region_view3d; - + /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "rotate_source", true, "Rotate Source", "Rotate initial selection giving better shape"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Spin Operator + * \{ */ static int edbm_spin_exec(bContext *C, wmOperator *op) { @@ -815,8 +861,7 @@ void MESH_OT_spin(wmOperatorType *ot) #ifdef USE_MANIPULATOR /* -------------------------------------------------------------------- */ - -/** \name Spin Manipulator +/** \name Screw Operator * \{ */ typedef struct ManipulatorSpinGroup { @@ -1315,3 +1360,5 @@ void MESH_OT_screw(wmOperatorType *ot) RNA_def_float_vector(ot->srna, "axis", 3, NULL, -1.0f, 1.0f, "Axis", "Axis in global view space", -1.0f, 1.0f); } + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index d9bbec7082db8d434ae0a75bfbdd1277654bba47..cd894502bc4fc9a031b1fa549d367ac301c8f10c 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -1782,7 +1782,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) } kcd->linehits = linehits; - kcd->totlinehit = BLI_array_count(linehits); + kcd->totlinehit = BLI_array_len(linehits); /* find position along screen line, used for sorting */ for (i = 0; i < kcd->totlinehit; i++) { diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index 795c7b6aa530b1bae943364c5393d3e121dbd5f7..2ae48bee09592dbc9a0a373f091687bb89868bad 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -63,6 +63,10 @@ #include "mesh_intern.h" /* own include */ +/* -------------------------------------------------------------------- */ +/** \name Path Select Struct & Properties + * \{ */ + struct PathSelectParams { bool track_active; /* ensure the active element is the last selected item (handy for picking) */ bool use_topology_distance; @@ -102,8 +106,11 @@ struct UserData { const struct PathSelectParams *op_params; }; +/** \} */ + /* -------------------------------------------------------------------- */ -/* Vert Path */ +/** \name Vert Path + * \{ */ /* callbacks */ static bool verttag_filter_cb(BMVert *v, void *UNUSED(user_data_v)) @@ -205,10 +212,11 @@ static void mouse_mesh_shortest_path_vert( EDBM_update_generic(em, false, false); } - +/** \} */ /* -------------------------------------------------------------------- */ -/* Edge Path */ +/** \name Edge Path + * \{ */ /* callbacks */ static bool edgetag_filter_cb(BMEdge *e, void *UNUSED(user_data_v)) @@ -427,10 +435,11 @@ static void mouse_mesh_shortest_path_edge( EDBM_update_generic(em, false, false); } - +/** \} */ /* -------------------------------------------------------------------- */ -/* Face Path */ +/** \name Face Path + * \{ */ /* callbacks */ static bool facetag_filter_cb(BMFace *f, void *UNUSED(user_data_v)) @@ -477,7 +486,6 @@ static void mouse_mesh_shortest_path_face( facetag_filter_cb, &user_data); } - if (f_act != f_dst) { if (path) { if (op_params->track_active) { @@ -538,10 +546,11 @@ static void mouse_mesh_shortest_path_face( EDBM_update_generic(em, false, false); } - +/** \} */ /* -------------------------------------------------------------------- */ -/* Main Operator for vert/edge/face tag */ +/** \name Main Operator for vert/edge/face tag + * \{ */ static bool edbm_shortest_path_pick_ex( Scene *scene, Object *obedit, const struct PathSelectParams *op_params, @@ -710,9 +719,11 @@ void MESH_OT_shortest_path_pick(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +/** \} */ /* -------------------------------------------------------------------- */ -/* Select path between existing selection */ +/** \name Select Path Between Existing Selection + * \{ */ static int edbm_shortest_path_select_exec(bContext *C, wmOperator *op) { @@ -797,3 +808,5 @@ void MESH_OT_shortest_path_select(wmOperatorType *ot) /* properties */ path_select_properties(ot); } + +/** \} */ diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index ce44eaaaa0e42dc4deb8a9deaf190a1e778fa460..5d33f1d57c5021f4ff699a0318ea8bdce69f3e63 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -4244,7 +4244,7 @@ static int loop_find_region( BLI_array_append(stack, l->f); BLI_gset_insert(visit_face_set, l->f); - while (BLI_array_count(stack) > 0) { + while (BLI_array_len(stack) > 0) { BMIter liter1, liter2; BMLoop *l1, *l2; @@ -4272,7 +4272,7 @@ static int loop_find_region( BLI_array_free(stack); *region_out = region; - return BLI_array_count(region); + return BLI_array_len(region); } static int verg_radial(const void *va, const void *vb) diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 70ee162753778c027328c380c44cd202cc84f640..312dc000a2b58adcaa2c5c380beeabd90e55ffd1 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -64,8 +64,14 @@ #include "mesh_intern.h" /* own include */ -/* mesh backup implementation. This would greatly benefit from some sort of binary diffing - * just as the undo stack would. So leaving this as an interface for further work */ +/* -------------------------------------------------------------------- */ +/** \name Redo API + * \{ */ + +/* Mesh backup implementation. + * This would greatly benefit from some sort of binary diffing + * just as the undo stack would. + * So leaving this as an interface for further work */ BMBackup EDBM_redo_state_store(BMEditMesh *em) { @@ -77,8 +83,9 @@ BMBackup EDBM_redo_state_store(BMEditMesh *em) void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess) { BMesh *tmpbm; - if (!em || !backup.bmcopy) + if (!em || !backup.bmcopy) { return; + } BM_mesh_data_free(em->bm); tmpbm = BM_mesh_copy(backup.bmcopy); @@ -86,8 +93,9 @@ void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess) MEM_freeN(tmpbm); tmpbm = NULL; - if (recalctess) + if (recalctess) { BKE_editmesh_tessface_calc(em); + } } void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess) @@ -100,68 +108,21 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess) BM_mesh_data_free(backup->bmcopy); } - if (backup->bmcopy) + if (backup->bmcopy) { MEM_freeN(backup->bmcopy); + } backup->bmcopy = NULL; - if (recalctess && em) + if (recalctess && em) { BKE_editmesh_tessface_calc(em); -} - -void EDBM_mesh_normals_update(BMEditMesh *em) -{ - BM_mesh_normals_update(em->bm); -} - -void EDBM_mesh_clear(BMEditMesh *em) -{ - /* clear bmesh */ - BM_mesh_clear(em->bm); - - /* free derived meshes */ - BKE_editmesh_free_derivedmesh(em); - - /* free tessellation data */ - em->tottri = 0; - if (em->looptris) { - MEM_freeN(em->looptris); - em->looptris = NULL; } } -void EDBM_stats_update(BMEditMesh *em) -{ - const char iter_types[3] = {BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH}; - - BMIter iter; - BMElem *ele; - int *tots[3]; - int i; +/** \} */ - tots[0] = &em->bm->totvertsel; - tots[1] = &em->bm->totedgesel; - tots[2] = &em->bm->totfacesel; - - em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0; - - for (i = 0; i < 3; i++) { - ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL); - for ( ; ele; ele = BM_iter_step(&iter)) { - if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { - (*tots[i])++; - } - } - } -} - -DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em) -{ - return ((em->derivedFinal != NULL) && - (em->derivedFinal->type == DM_TYPE_EDITBMESH) && - (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL; -} +/* -------------------------------------------------------------------- */ +/** \name BMesh Operator (BMO) API Wrapper + * \{ */ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...) { @@ -175,9 +136,10 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char * va_end(list); return false; } - - if (!em->emcopy) + + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; va_end(list); @@ -185,12 +147,11 @@ bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char * return true; } - /* returns 0 on error, 1 on success. executes and finishes a bmesh operator */ bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report) { const char *errmsg; - + BMO_op_finish(em->bm, bmop); if (BMO_error_get(em->bm, &errmsg, NULL)) { @@ -245,8 +206,9 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...) return false; } - if (!em->emcopy) + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; BMO_op_exec(bm, &bmop); @@ -255,9 +217,10 @@ bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...) return EDBM_op_finish(em, &bmop, op, true); } -bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op, - const char *select_slot_out, const bool select_extend, - const char *fmt, ...) +bool EDBM_op_call_and_selectf( + BMEditMesh *em, wmOperator *op, + const char *select_slot_out, const bool select_extend, + const char *fmt, ...) { BMOpSlot *slot_select_out; BMesh *bm = em->bm; @@ -273,8 +236,9 @@ bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op, return false; } - if (!em->emcopy) + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; BMO_op_exec(bm, &bmop); @@ -306,8 +270,9 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...) return false; } - if (!em->emcopy) + if (!em->emcopy) { em->emcopy = BKE_editmesh_copy(em); + } em->emcopyusers++; BMO_op_exec(bm, &bmop); @@ -316,20 +281,13 @@ bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...) return EDBM_op_finish(em, &bmop, NULL, false); } -void EDBM_selectmode_to_scene(bContext *C) -{ - Scene *scene = CTX_data_scene(C); - Object *obedit = CTX_data_edit_object(C); - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - if (!em) - return; +/** \} */ - scene->toolsettings->selectmode = em->selectmode; - - /* Request redraw of header buttons (to show new select mode) */ - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene); -} +/* -------------------------------------------------------------------- */ +/** \name Edit BMesh API + * + * Make/Clear/Free functions. + * \{ */ void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index) { @@ -413,6 +371,22 @@ void EDBM_mesh_load(Object *ob) #endif } +void EDBM_mesh_clear(BMEditMesh *em) +{ + /* clear bmesh */ + BM_mesh_clear(em->bm); + + /* free derived meshes */ + BKE_editmesh_free_derivedmesh(em); + + /* free tessellation data */ + em->tottri = 0; + if (em->looptris) { + MEM_freeN(em->looptris); + em->looptris = NULL; + } +} + /** * Should only be called on the active editmesh, otherwise call #BKE_editmesh_free */ @@ -427,6 +401,28 @@ void EDBM_mesh_free(BMEditMesh *em) BKE_editmesh_free(em); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Selection Utilities + * \{ */ + +void EDBM_selectmode_to_scene(bContext *C) +{ + Scene *scene = CTX_data_scene(C); + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + if (!em) { + return; + } + + scene->toolsettings->selectmode = em->selectmode; + + /* Request redraw of header buttons (to show new select mode) */ + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, scene); +} + void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode) { BM_mesh_select_mode_flush_ex(em->bm, selectmode); @@ -444,7 +440,6 @@ void EDBM_deselect_flush(BMEditMesh *em) BM_mesh_deselect_flush(em->bm); } - void EDBM_select_flush(BMEditMesh *em) { /* function below doesnt use. just do this to keep the values in sync */ @@ -457,9 +452,10 @@ void EDBM_select_more(BMEditMesh *em, const bool use_face_step) BMOperator bmop; const bool use_faces = (em->selectmode == SCE_SELECT_FACE); - BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS, - "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", - BM_ELEM_SELECT, false, use_faces, use_face_step); + BMO_op_initf( + em->bm, &bmop, BMO_FLAG_DEFAULTS, + "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", + BM_ELEM_SELECT, false, use_faces, use_face_step); BMO_op_exec(em->bm, &bmop); /* don't flush selection in edge/vertex mode */ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false); @@ -473,9 +469,10 @@ void EDBM_select_less(BMEditMesh *em, const bool use_face_step) BMOperator bmop; const bool use_faces = (em->selectmode == SCE_SELECT_FACE); - BMO_op_initf(em->bm, &bmop, BMO_FLAG_DEFAULTS, - "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", - BM_ELEM_SELECT, true, use_faces, use_face_step); + BMO_op_initf( + em->bm, &bmop, BMO_FLAG_DEFAULTS, + "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b", + BM_ELEM_SELECT, true, use_faces, use_face_step); BMO_op_exec(em->bm, &bmop); /* don't flush selection in edge/vertex mode */ BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false); @@ -497,6 +494,12 @@ void EDBM_flag_enable_all(BMEditMesh *em, const char hflag) BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name UV Vertex Map API + * \{ */ + /** * Return a new UVVertMap from the editmesh */ @@ -519,7 +522,7 @@ UvVertMap *BM_uv_vert_map_create( BLI_buffer_declare_static(vec2f, tf_uv_buf, BLI_BUFFER_NOP, BM_DEFAULT_NGON_STACK_SIZE); BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE); - + totfaces = bm->totface; totverts = bm->totvert; totuv = 0; @@ -549,7 +552,7 @@ UvVertMap *BM_uv_vert_map_create( BKE_mesh_uv_vert_map_free(vmap); return NULL; } - + BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) { if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) { float (*tf_uv)[2]; @@ -562,7 +565,7 @@ UvVertMap *BM_uv_vert_map_create( buf->tfindex = i; buf->f = a; buf->separate = 0; - + buf->next = vmap->vert[BM_elem_index_get(l->v)]; vmap->vert[BM_elem_index_get(l->v)] = buf; buf++; @@ -578,7 +581,7 @@ UvVertMap *BM_uv_vert_map_create( } } } - + /* sort individual uvs for each vert */ BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) { UvMapVert *newvlist = NULL, *vlist = vmap->vert[a]; @@ -592,22 +595,21 @@ UvVertMap *BM_uv_vert_map_create( newvlist = v; efa = BM_face_at_index(bm, v->f); - + l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->tfindex); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv = luv->uv; - + lastv = NULL; iterv = vlist; while (iterv) { next = iterv->next; efa = BM_face_at_index(bm, iterv->f); - l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex); luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); uv2 = luv->uv; - + sub_v2_v2v2(uvdiff, uv2, uv); if (fabsf(uvdiff[0]) < limit[0] && fabsf(uvdiff[1]) < limit[1] && @@ -640,13 +642,11 @@ UvVertMap *BM_uv_vert_map_create( return vmap; } - UvMapVert *BM_uv_vert_map_at_index(UvVertMap *vmap, unsigned int v) { return vmap->vert[v]; } - /* A specialized vert map used by stitch operator */ UvElementMap *BM_uv_element_map_create( BMesh *bm, @@ -904,23 +904,30 @@ void BM_uv_element_map_free(UvElementMap *element_map) UvElement *BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l) { - UvElement *element; - - element = map->vert[BM_elem_index_get(l->v)]; - - for (; element; element = element->next) - if (element->l->f == efa) + for (UvElement *element = map->vert[BM_elem_index_get(l->v)]; + element; + element = element->next) + { + if (element->l->f == efa) { return element; + } + } return NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Data Layer Checks + * \{ */ + /* last_sel, use em->act_face otherwise get the last selected face in the editselections * at the moment, last_sel is mainly useful for making sure the space image dosnt flicker */ BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected) { BMFace *efa = NULL; - + if (!EDBM_uv_check(em)) { return NULL; } @@ -948,6 +955,12 @@ bool EDBM_vert_color_check(BMEditMesh *em) return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mirror Cache API + * \{ */ + static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index) { intptr_t eve_i = index_lookup[index]; @@ -982,9 +995,10 @@ static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index) * \param maxdist Distance for close point test. * \param r_index Optional array to write into, as an alternative to a customdata layer (length of total verts). */ -void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool use_self, const bool use_select, - /* extra args */ - const bool use_topology, float maxdist, int *r_index) +void EDBM_verts_mirror_cache_begin_ex( + BMEditMesh *em, const int axis, const bool use_self, const bool use_select, + /* extra args */ + const bool use_topology, float maxdist, int *r_index) { Mesh *me = (Mesh *)em->ob->data; BMesh *bm = em->bm; @@ -1008,8 +1022,9 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool em->mirror_cdlayer = CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, layer_id); } - cd_vmirr_offset = CustomData_get_n_offset(&bm->vdata, CD_PROP_INT, - em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT)); + cd_vmirr_offset = CustomData_get_n_offset( + &bm->vdata, CD_PROP_INT, + em->mirror_cdlayer - CustomData_get_layer_index(&bm->vdata, CD_PROP_INT)); bm->vdata.layers[em->mirror_cdlayer].flag |= CD_FLAG_TEMPORARY; } @@ -1082,14 +1097,16 @@ void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool } } -void EDBM_verts_mirror_cache_begin(BMEditMesh *em, const int axis, - const bool use_self, const bool use_select, - const bool use_topology) +void EDBM_verts_mirror_cache_begin( + BMEditMesh *em, const int axis, + const bool use_self, const bool use_select, + const bool use_topology) { - EDBM_verts_mirror_cache_begin_ex(em, axis, - use_self, use_select, - /* extra args */ - use_topology, BM_SEARCH_MAXDIST_MIRR, NULL); + EDBM_verts_mirror_cache_begin_ex( + em, axis, + use_self, use_select, + /* extra args */ + use_topology, BM_SEARCH_MAXDIST_MIRR, NULL); } BMVert *EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v) @@ -1177,6 +1194,11 @@ void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_t } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hide/Reveal API + * \{ */ /* swap is 0 or 1, if 1 it hides not selected */ void EDBM_mesh_hide(BMEditMesh *em, bool swap) @@ -1211,17 +1233,18 @@ void EDBM_mesh_hide(BMEditMesh *em, bool swap) */ } - void EDBM_mesh_reveal(BMEditMesh *em, bool select) { - const char iter_types[3] = {BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH}; + const char iter_types[3] = { + BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH, + }; const bool sels[3] = { - (em->selectmode & SCE_SELECT_VERTEX) != 0, - (em->selectmode & SCE_SELECT_EDGE) != 0, - (em->selectmode & SCE_SELECT_FACE) != 0, + (em->selectmode & SCE_SELECT_VERTEX) != 0, + (em->selectmode & SCE_SELECT_EDGE) != 0, + (em->selectmode & SCE_SELECT_FACE) != 0, }; int i; @@ -1261,6 +1284,46 @@ void EDBM_mesh_reveal(BMEditMesh *em, bool select) EDBM_mesh_normals_update(em); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Update API + * \{ */ + +void EDBM_mesh_normals_update(BMEditMesh *em) +{ + BM_mesh_normals_update(em->bm); +} + +void EDBM_stats_update(BMEditMesh *em) +{ + const char iter_types[3] = { + BM_VERTS_OF_MESH, + BM_EDGES_OF_MESH, + BM_FACES_OF_MESH, + }; + + BMIter iter; + BMElem *ele; + int *tots[3]; + int i; + + tots[0] = &em->bm->totvertsel; + tots[1] = &em->bm->totedgesel; + tots[2] = &em->bm->totfacesel; + + em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0; + + for (i = 0; i < 3; i++) { + ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL); + for ( ; ele; ele = BM_iter_step(&iter)) { + if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) { + (*tots[i])++; + } + } + } +} + /* so many tools call these that we better make it a generic function. */ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_destructive) @@ -1296,15 +1359,41 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d #endif } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Data Access + * \{ */ + +DerivedMesh *EDBM_mesh_deform_dm_get(BMEditMesh *em) +{ + return ((em->derivedFinal != NULL) && + (em->derivedFinal->type == DM_TYPE_EDITBMESH) && + (em->derivedFinal->deformedOnly != false)) ? em->derivedFinal : NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Helpers + * \{ */ + /* poll call for mesh operators requiring a view3d context */ int EDBM_view3d_poll(bContext *C) { - if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) + if (ED_operator_editmesh(C) && ED_operator_view3d_active(C)) { return 1; + } return 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name BMesh Element API + * \{ */ + BMElem *EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa) { BMElem *ele = NULL; @@ -1369,22 +1458,19 @@ BMElem *EDBM_elem_from_index_any(BMEditMesh *em, int index) return NULL; } -/* -------------------------------------------------------------------- */ -/* BMBVH functions */ -// XXX -#if 0 //BMESH_TODO: not implemented yet -int BMBVH_VertVisible(BMBVHTree *tree, BMEdge *e, RegionView3D *r3d) -{ +/** \} */ -} -#endif +/* -------------------------------------------------------------------- */ +/** \name BMesh BVH API + * \{ */ static BMFace *edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e) { BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL); - if (f && BM_edge_in_face(e, f)) + if (f && BM_edge_in_face(e, f)) { return NULL; + } return f; } @@ -1405,8 +1491,10 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, float origin[3], invmat[4][4]; float epsilon = 0.01f; float end[3]; - const float mval_f[2] = {ar->winx / 2.0f, - ar->winy / 2.0f}; + const float mval_f[2] = { + ar->winx / 2.0f, + ar->winy / 2.0f, + }; ED_view3d_win_to_segment(depsgraph, ar, v3d, mval_f, origin, end, false); @@ -1442,12 +1530,17 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, /* do three samplings: left, middle, right */ f = edge_ray_cast(tree, co1, dir1, NULL, e); - if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) + if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) { return true; - else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) + } + else if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) { return true; - else if (!f) + } + else if (!f) { return true; + } return false; } + +/** \} */ diff --git a/source/blender/editors/mesh/mesh_mirror.c b/source/blender/editors/mesh/mesh_mirror.c new file mode 100644 index 0000000000000000000000000000000000000000..22bfd8eedeaafc29c976958c6b2d5b1bde2f22bf --- /dev/null +++ b/source/blender/editors/mesh/mesh_mirror.c @@ -0,0 +1,377 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor(s): Blender Foundation, Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/mesh/mesh_mirror.c + * \ingroup edmesh + * + * Mirror calculation for edit-mode and object mode. + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_math.h" +#include "BLI_bitmap.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" + +#include "BKE_DerivedMesh.h" +#include "BLI_kdtree.h" +#include "BKE_editmesh.h" + +#include "ED_mesh.h" + +/* -------------------------------------------------------------------- */ +/** \name Mesh Spatial Mirror API + * \{ */ + +#define KD_THRESH 0.00002f + +static struct { void *tree; } MirrKdStore = {NULL}; + +/* mode is 's' start, or 'e' end, or 'u' use */ +/* if end, ob can be NULL */ +int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode) +{ + if (mode == 'u') { /* use table */ + if (MirrKdStore.tree == NULL) + ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's'); + + if (MirrKdStore.tree) { + KDTreeNearest nearest; + const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest); + + if (i != -1) { + if (nearest.dist < KD_THRESH) { + return i; + } + } + } + return -1; + } + else if (mode == 's') { /* start table */ + Mesh *me = ob->data; + const bool use_em = (!dm && em && me->edit_btmesh == em); + const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert; + + if (MirrKdStore.tree) /* happens when entering this call without ending it */ + ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e'); + + MirrKdStore.tree = BLI_kdtree_new(totvert); + + if (use_em) { + BMVert *eve; + BMIter iter; + int i; + + /* this needs to be valid for index lookups later (callers need) */ + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + BLI_kdtree_insert(MirrKdStore.tree, i, eve->co); + } + } + else { + MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert; + int i; + + for (i = 0; i < totvert; i++, mvert++) { + BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co); + } + } + + BLI_kdtree_balance(MirrKdStore.tree); + } + else if (mode == 'e') { /* end table */ + if (MirrKdStore.tree) { + BLI_kdtree_free(MirrKdStore.tree); + MirrKdStore.tree = NULL; + } + } + else { + BLI_assert(0); + } + + return 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mesh Topology Mirror API + * \{ */ + +typedef unsigned int MirrTopoHash_t; + +typedef struct MirrTopoVert_t { + MirrTopoHash_t hash; + int v_index; +} MirrTopoVert_t; + +static int mirrtopo_hash_sort(const void *l1, const void *l2) +{ + if ((MirrTopoHash_t)(intptr_t)l1 > (MirrTopoHash_t)(intptr_t)l2) return 1; + else if ((MirrTopoHash_t)(intptr_t)l1 < (MirrTopoHash_t)(intptr_t)l2) return -1; + return 0; +} + +static int mirrtopo_vert_sort(const void *v1, const void *v2) +{ + if (((MirrTopoVert_t *)v1)->hash > ((MirrTopoVert_t *)v2)->hash) return 1; + else if (((MirrTopoVert_t *)v1)->hash < ((MirrTopoVert_t *)v2)->hash) return -1; + return 0; +} + +bool ED_mesh_mirrtopo_recalc_check(Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store) +{ + const bool is_editmode = (me->edit_btmesh != NULL); + int totvert; + int totedge; + + if (dm) { + totvert = dm->getNumVerts(dm); + totedge = dm->getNumEdges(dm); + } + else if (me->edit_btmesh) { + totvert = me->edit_btmesh->bm->totvert; + totedge = me->edit_btmesh->bm->totedge; + } + else { + totvert = me->totvert; + totedge = me->totedge; + } + + if ((mesh_topo_store->index_lookup == NULL) || + (mesh_topo_store->prev_is_editmode != is_editmode) || + (totvert != mesh_topo_store->prev_vert_tot) || + (totedge != mesh_topo_store->prev_edge_tot)) + { + return true; + } + else { + return false; + } + +} + +void ED_mesh_mirrtopo_init( + Mesh *me, DerivedMesh *dm, MirrTopoStore_t *mesh_topo_store, + const bool skip_em_vert_array_init) +{ + const bool is_editmode = (me->edit_btmesh != NULL); + MEdge *medge = NULL, *med; + BMEditMesh *em = dm ? NULL : me->edit_btmesh; + + /* editmode*/ + BMEdge *eed; + BMIter iter; + + int a, last; + int totvert, totedge; + int tot_unique = -1, tot_unique_prev = -1; + int tot_unique_edges = 0, tot_unique_edges_prev; + + MirrTopoHash_t *topo_hash = NULL; + MirrTopoHash_t *topo_hash_prev = NULL; + MirrTopoVert_t *topo_pairs; + MirrTopoHash_t topo_pass = 1; + + intptr_t *index_lookup; /* direct access to mesh_topo_store->index_lookup */ + + /* reallocate if needed */ + ED_mesh_mirrtopo_free(mesh_topo_store); + + mesh_topo_store->prev_is_editmode = is_editmode; + + if (em) { + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + totvert = em->bm->totvert; + } + else { + totvert = dm ? dm->getNumVerts(dm) : me->totvert; + } + + topo_hash = MEM_callocN(totvert * sizeof(MirrTopoHash_t), "TopoMirr"); + + /* Initialize the vert-edge-user counts used to detect unique topology */ + if (em) { + totedge = me->edit_btmesh->bm->totedge; + + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); + topo_hash[i1]++; + topo_hash[i2]++; + } + } + else { + totedge = dm ? dm->getNumEdges(dm) : me->totedge; + medge = dm ? dm->getEdgeArray(dm) : me->medge; + + for (a = 0, med = medge; a < totedge; a++, med++) { + const unsigned int i1 = med->v1, i2 = med->v2; + topo_hash[i1]++; + topo_hash[i2]++; + } + } + + topo_hash_prev = MEM_dupallocN(topo_hash); + + tot_unique_prev = -1; + tot_unique_edges_prev = -1; + while (1) { + /* use the number of edges per vert to give verts unique topology IDs */ + + tot_unique_edges = 0; + + /* This can make really big numbers, wrapping around here is fine */ + if (em) { + BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { + const int i1 = BM_elem_index_get(eed->v1), i2 = BM_elem_index_get(eed->v2); + topo_hash[i1] += topo_hash_prev[i2] * topo_pass; + topo_hash[i2] += topo_hash_prev[i1] * topo_pass; + tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); + } + } + else { + for (a = 0, med = medge; a < totedge; a++, med++) { + const unsigned int i1 = med->v1, i2 = med->v2; + topo_hash[i1] += topo_hash_prev[i2] * topo_pass; + topo_hash[i2] += topo_hash_prev[i1] * topo_pass; + tot_unique_edges += (topo_hash[i1] != topo_hash[i2]); + } + } + memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); + + /* sort so we can count unique values */ + qsort(topo_hash_prev, totvert, sizeof(MirrTopoHash_t), mirrtopo_hash_sort); + + tot_unique = 1; /* account for skiping the first value */ + for (a = 1; a < totvert; a++) { + if (topo_hash_prev[a - 1] != topo_hash_prev[a]) { + tot_unique++; + } + } + + if ((tot_unique <= tot_unique_prev) && (tot_unique_edges <= tot_unique_edges_prev)) { + /* Finish searching for unique values when 1 loop dosnt give a + * higher number of unique values compared to the previous loop */ + break; + } + else { + tot_unique_prev = tot_unique; + tot_unique_edges_prev = tot_unique_edges; + } + /* Copy the hash calculated this iter, so we can use them next time */ + memcpy(topo_hash_prev, topo_hash, sizeof(MirrTopoHash_t) * totvert); + + topo_pass++; + } + + /* Hash/Index pairs are needed for sorting to find index pairs */ + topo_pairs = MEM_callocN(sizeof(MirrTopoVert_t) * totvert, "MirrTopoPairs"); + + /* since we are looping through verts, initialize these values here too */ + index_lookup = MEM_mallocN(totvert * sizeof(*index_lookup), "mesh_topo_lookup"); + + if (em) { + if (skip_em_vert_array_init == false) { + BM_mesh_elem_table_ensure(em->bm, BM_VERT); + } + } + + for (a = 0; a < totvert; a++) { + topo_pairs[a].hash = topo_hash[a]; + topo_pairs[a].v_index = a; + + /* initialize lookup */ + index_lookup[a] = -1; + } + + qsort(topo_pairs, totvert, sizeof(MirrTopoVert_t), mirrtopo_vert_sort); + + last = 0; + + /* Get the pairs out of the sorted hashes, note, totvert+1 means we can use the previous 2, + * but you cant ever access the last 'a' index of MirrTopoPairs */ + if (em) { + BMVert **vtable = em->bm->vtable; + for (a = 1; a <= totvert; a++) { + /* printf("I %d %ld %d\n", (a - last), MirrTopoPairs[a].hash, MirrTopoPairs[a].v_indexs); */ + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = (intptr_t)vtable[k]; + index_lookup[k] = (intptr_t)vtable[j]; + } + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = (intptr_t)vtable[j]; + } + last = a; + } + } + } + else { + /* same as above, for mesh */ + for (a = 1; a <= totvert; a++) { + if ((a == totvert) || (topo_pairs[a - 1].hash != topo_pairs[a].hash)) { + const int match_count = a - last; + if (match_count == 2) { + const int j = topo_pairs[a - 1].v_index, k = topo_pairs[a - 2].v_index; + index_lookup[j] = k; + index_lookup[k] = j; + } + else if (match_count == 1) { + /* Center vertex. */ + const int j = topo_pairs[a - 1].v_index; + index_lookup[j] = j; + } + last = a; + } + } + } + + MEM_freeN(topo_pairs); + topo_pairs = NULL; + + MEM_freeN(topo_hash); + MEM_freeN(topo_hash_prev); + + mesh_topo_store->index_lookup = index_lookup; + mesh_topo_store->prev_vert_tot = totvert; + mesh_topo_store->prev_edge_tot = totedge; +} + +void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store) +{ + if (mesh_topo_store->index_lookup) { + MEM_freeN(mesh_topo_store->index_lookup); + } + mesh_topo_store->index_lookup = NULL; + mesh_topo_store->prev_vert_tot = -1; + mesh_topo_store->prev_edge_tot = -1; +} + +/** \} */ diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index da73d7205c3743d9f75d0fa973d285675c6786eb..3cf0f43fe39bd9299b968fca02a2a9f7770225df 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -47,8 +47,6 @@ #include "BLI_math.h" #include "BLI_blenlib.h" - -#include "BLI_kdtree.h" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_DerivedMesh.h" @@ -563,12 +561,10 @@ int join_mesh_exec(bContext *C, wmOperator *op) if (ma) id_us_min(&ma->id); } - if (ob->mat) MEM_freeN(ob->mat); - if (ob->matbits) MEM_freeN(ob->matbits); - if (me->mat) MEM_freeN(me->mat); - ob->mat = me->mat = NULL; - ob->matbits = NULL; - + MEM_SAFE_FREE(ob->mat); + MEM_SAFE_FREE(ob->matbits); + MEM_SAFE_FREE(me->mat); + if (totcol) { me->mat = matar; ob->mat = MEM_callocN(sizeof(*ob->mat) * totcol, "join obmatar"); @@ -683,84 +679,6 @@ int join_mesh_shapes_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/* -------------------------------------------------------------------- */ -/* Mesh Mirror (Spatial) */ - -/** \name Mesh Spatial Mirror API - * \{ */ - -#define KD_THRESH 0.00002f - -static struct { void *tree; } MirrKdStore = {NULL}; - -/* mode is 's' start, or 'e' end, or 'u' use */ -/* if end, ob can be NULL */ -int ED_mesh_mirror_spatial_table(Object *ob, BMEditMesh *em, DerivedMesh *dm, const float co[3], char mode) -{ - if (mode == 'u') { /* use table */ - if (MirrKdStore.tree == NULL) - ED_mesh_mirror_spatial_table(ob, em, dm, NULL, 's'); - - if (MirrKdStore.tree) { - KDTreeNearest nearest; - const int i = BLI_kdtree_find_nearest(MirrKdStore.tree, co, &nearest); - - if (i != -1) { - if (nearest.dist < KD_THRESH) { - return i; - } - } - } - return -1; - } - else if (mode == 's') { /* start table */ - Mesh *me = ob->data; - const bool use_em = (!dm && em && me->edit_btmesh == em); - const int totvert = use_em ? em->bm->totvert : dm ? dm->getNumVerts(dm) : me->totvert; - - if (MirrKdStore.tree) /* happens when entering this call without ending it */ - ED_mesh_mirror_spatial_table(ob, em, dm, co, 'e'); - - MirrKdStore.tree = BLI_kdtree_new(totvert); - - if (use_em) { - BMVert *eve; - BMIter iter; - int i; - - /* this needs to be valid for index lookups later (callers need) */ - BM_mesh_elem_table_ensure(em->bm, BM_VERT); - - BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { - BLI_kdtree_insert(MirrKdStore.tree, i, eve->co); - } - } - else { - MVert *mvert = dm ? dm->getVertArray(dm) : me->mvert; - int i; - - for (i = 0; i < totvert; i++, mvert++) { - BLI_kdtree_insert(MirrKdStore.tree, i, mvert->co); - } - } - - BLI_kdtree_balance(MirrKdStore.tree); - } - else if (mode == 'e') { /* end table */ - if (MirrKdStore.tree) { - BLI_kdtree_free(MirrKdStore.tree); - MirrKdStore.tree = NULL; - } - } - else { - BLI_assert(0); - } - - return 0; -} - -/** \} */ - /* -------------------------------------------------------------------- */ /* Mesh Mirror (Topology) */ diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 5e7e0fb68a3f5e7beafa78a1d7e22610285aa56b..00c5fdf3cc728ea302b0979bc0199995a0e1bad4 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1632,33 +1632,30 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) static Object *single_object_users_object(Main *bmain, Scene *scene, Object *ob, const bool copy_groups) { - if (!ID_IS_LINKED(ob) && ob->id.us > 1) { - /* base gets copy of object */ - Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); + /* base gets copy of object */ + Object *obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); - if (copy_groups) { - if (ob->flag & OB_FROMGROUP) { - obn->flag |= OB_FROMGROUP; - } - } - else { - /* copy already clears */ + if (copy_groups) { + if (ob->flag & OB_FROMGROUP) { + obn->flag |= OB_FROMGROUP; } - /* remap gpencil parenting */ + } + else { + /* copy already clears */ + } + /* remap gpencil parenting */ - if (scene->gpd) { - bGPdata *gpd = scene->gpd; - for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { - if (gpl->parent == ob) { - gpl->parent = obn; - } + if (scene->gpd) { + bGPdata *gpd = scene->gpd; + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->parent == ob) { + gpl->parent = obn; } } - - id_us_min(&ob->id); - return obn; } - return NULL; + + id_us_min(&ob->id); + return obn; } static void libblock_relink_scene_collection(SceneCollection *sc) @@ -1678,7 +1675,9 @@ static void single_object_users_scene_collection(Main *bmain, Scene *scene, Scen Object *ob = link->data; /* an object may be in more than one collection */ if ((ob->id.newid == NULL) && ((ob->flag & flag) == flag)) { - link->data = single_object_users_object(bmain, scene, link->data, copy_groups); + if (!ID_IS_LINKED(ob) && ob->id.us > 1) { + link->data = single_object_users_object(bmain, scene, link->data, copy_groups); + } } } diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 033f9d190b7f6b2365db5042d297fb3e2b71f12a..7ea1a04f31f271e33668ad40c6de5379194872ce 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -1343,9 +1343,9 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons CTX_DATA_END; xfd->object_data = object_data; - xfd->object_data_len = BLI_array_count(object_data); + xfd->object_data_len = BLI_array_len(object_data); - if (xfd->object_data_len != BLI_array_count(object_data)) { + if (xfd->object_data_len != BLI_array_len(object_data)) { xfd->object_data = MEM_reallocN(xfd->object_data, xfd->object_data_len * sizeof(*xfd->object_data)); } } diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 00a24e7fe7257de67e6cf00898733394629afe4a..eb04de5feb271695f495fb6065528ea897bf86ce 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -1192,7 +1192,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count) } /* Append a and b verts to array, if not yet present. */ - k = BLI_array_count(verts); + k = BLI_array_len(verts); /* XXX Maybe a == b is enough? */ while (k-- && !(a == b && a == -1)) { if (verts[k] == a) @@ -1214,7 +1214,7 @@ static int *getSurroundingVerts(Mesh *me, int vert, int *count) } /* Do not free the array! */ - *count = BLI_array_count(verts); + *count = BLI_array_len(verts); return verts; } diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index aba4b7788f86c49792451c3022afa8396606b088..33ca6ea74954500f886f78a4a5b968cf6c24b12d 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -536,10 +536,8 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, int layer = BLI_findstringindex(&main_rr->layers, (char *)rr->renlay->name, offsetof(RenderLayer, name)); - if (layer != rj->last_layer) { - sima->iuser.layer = layer; - rj->last_layer = layer; - } + sima->iuser.layer = layer; + rj->last_layer = layer; } iuser->pass = sima->iuser.pass; @@ -637,7 +635,21 @@ static void render_image_restore_layer(RenderJob *rj) if (sa == rj->sa) { if (sa->spacetype == SPACE_IMAGE) { SpaceImage *sima = sa->spacedata.first; - sima->iuser.layer = rj->orig_layer; + + if (RE_HasSingleLayer(rj->re)) { + /* For single layer renders keep the active layer + * visible, or show the compositing result. */ + RenderResult *rr = RE_AcquireResultRead(rj->re); + if(RE_HasCombinedLayer(rr)) { + sima->iuser.layer = 0; + } + RE_ReleaseResult(rj->re); + } + else { + /* For multiple layer render, set back the layer + * that was set at the start of rendering. */ + sima->iuser.layer = rj->orig_layer; + } } return; } diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index c791b9f6eae40d2c69b61b09849bc4db8b35c2de..1047c498e4d975c8afc0d8118cae360759870690 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -482,10 +482,10 @@ static void ui_node_menu_column(NodeLinkArg *arg, int nclass, const char *cname) } NODE_TYPES_END - qsort(sorted_ntypes, BLI_array_count(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare); + qsort(sorted_ntypes, BLI_array_len(sorted_ntypes), sizeof(bNodeType *), ui_node_item_name_compare); /* generate UI */ - for (int j = 0; j < BLI_array_count(sorted_ntypes); j++) { + for (int j = 0; j < BLI_array_len(sorted_ntypes); j++) { bNodeType *ntype = sorted_ntypes[j]; NodeLinkItem *items; int totitems; diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 9d02c8589b29052b4624a0ad7a754883c36bda82..b22cbf6d1552af6e3a14361d678bd12382089c34 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -60,6 +60,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" +#include "GPU_batch.h" #include "GPU_immediate.h" #include "GPU_immediate_util.h" #include "GPU_matrix.h" @@ -74,7 +75,7 @@ #include "uvedit_intern.h" -static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset, const uint shdr_pos); +static void draw_uvs_lineloop_bmfaces(BMesh *bm, const int cd_loop_uv_offset, const uint shdr_pos); void ED_image_draw_cursor(ARegion *ar, const float cursor[2]) { @@ -161,8 +162,6 @@ static void draw_uvs_shadow(Object *obedit) { BMEditMesh *em = BKE_editmesh_from_object(obedit); BMesh *bm = em->bm; - BMFace *efa; - BMIter iter; const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); @@ -173,9 +172,7 @@ static void draw_uvs_shadow(Object *obedit) /* draws the mesh when painting */ immUniformThemeColor(TH_UV_SHADOW); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); - } + draw_uvs_lineloop_bmfaces(bm, cd_loop_uv_offset, pos); immUnbindProgram(); } @@ -385,18 +382,43 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, Object *obedit, BME BLI_buffer_free(&tf_uvorig_buf); } -static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset, const uint shdr_pos) +static void draw_uvs_lineloop_bmfaces(BMesh *bm, const int cd_loop_uv_offset, const uint shdr_pos) { - BMIter liter; + BMIter iter, liter; + BMFace *efa; BMLoop *l; MLoopUV *luv; - immBegin(GWN_PRIM_LINE_LOOP, efa->len); + /* For more efficiency first transfer the entire buffer to vram. */ + Gwn_Batch *uv_batch = immBeginBatchAtMost(GWN_PRIM_LINE_LOOP, bm->totloop); + + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + immVertex2fv(shdr_pos, luv->uv); + } + } + immEnd(); - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - immVertex2fv(shdr_pos, luv->uv); + /* Then draw each face contour separately. */ + GWN_batch_program_use_begin(uv_batch); + unsigned int index = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + GWN_batch_draw_range_ex(uv_batch, index, efa->len, false); + index += efa->len; } + GWN_batch_program_use_end(uv_batch); + + GWN_vertbuf_discard(uv_batch->verts[0]); + GWN_batch_discard(uv_batch); + + immUnbindProgram(); immEnd(); } @@ -616,7 +638,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje BMLoop *l; BMIter iter, liter; MLoopUV *luv; - unsigned char col1[4], col2[4]; + float col1[4], col2[4]; float pointsize; int drawfaces, interpedges; Image *ima = sima->image; @@ -686,14 +708,14 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (tri_count && !(sima->flag & SI_NO_DRAWFACES)) { /* draw transparent faces */ - UI_GetThemeColor4ubv(TH_FACE, col1); - UI_GetThemeColor4ubv(TH_FACE_SELECT, col2); + UI_GetThemeColor4fv(TH_FACE, col1); + UI_GetThemeColor4fv(TH_FACE_SELECT, col2); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); Gwn_VertFormat *format = immVertexFormat(); pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); @@ -705,12 +727,12 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (efa == efa_act) { /* only once */ - unsigned char tmp_col[4]; - UI_GetThemeColor4ubv(TH_EDITMESH_ACTIVE, tmp_col); - immAttrib4ubv(color, tmp_col); + float tmp_col[4]; + UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, tmp_col); + immAttrib4fv(color, tmp_col); } else { - immAttrib4ubv(color, is_select ? col2 : col1); + immAttrib4fv(color, is_select ? col2 : col1); } draw_uvs_looptri(em, &i, cd_loop_uv_offset, pos); @@ -740,13 +762,11 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } - glLineWidth(1); + pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); switch (sima->dt_uv) { case SI_UVDT_DASH: { - const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR); float viewport_size[4]; @@ -756,141 +776,160 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje immUniform1i("num_colors", 2); /* "advanced" mode */ immUniformArray4fv("colors", (float *)(float[][4]){{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}}, 2); immUniform1f("dash_width", 4.0f); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, shdr_pos); - } - - immUnbindProgram(); + glLineWidth(1.0f); break; } case SI_UVDT_BLACK: /* black/white */ case SI_UVDT_WHITE: - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - if (sima->dt_uv == SI_UVDT_WHITE) { immUniformColor3f(1.0f, 1.0f, 1.0f); } else { immUniformColor3f(0.0f, 0.0f, 0.0f); } - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); - } - - immUnbindProgram(); + glLineWidth(1.0f); break; case SI_UVDT_OUTLINE: - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - glLineWidth(3); imm_cpack(0x0); + glLineWidth(3.0f); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; + break; + } - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); - } + /* For more efficiency first transfer the entire buffer to vram. */ + Gwn_Batch *uv_batch = immBeginBatchAtMost(GWN_PRIM_LINE_LOOP, bm->totloop); + Gwn_VertBuf* uv_vbo = uv_batch->verts[0]; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; - immUnbindProgram(); + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + immVertex2fv(pos, luv->uv); + } + } + immEnd(); - glLineWidth(1); - UI_GetThemeColor4ubv(TH_WIRE_EDIT, col2); + /* Then draw each face contour separately. */ + GWN_batch_program_use_begin(uv_batch); + unsigned int index = 0, vbo_len_used; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; - if (me->drawflag & ME_DRAWEDGES) { - int sel; - UI_GetThemeColor4ubv(TH_EDGE_SELECT, col1); + GWN_batch_draw_range_ex(uv_batch, index, efa->len, false); + index += efa->len; + } + vbo_len_used = index; + GWN_batch_program_use_end(uv_batch); + immUnbindProgram(); - Gwn_VertFormat *format = immVertexFormat(); - pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 4, GWN_FETCH_INT_TO_FLOAT_UNIT); - if (interpedges) { - immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR); + if (sima->dt_uv == SI_UVDT_OUTLINE) { + glLineWidth(1.0f); + UI_GetThemeColor4fv(TH_WIRE_EDIT, col2); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; + if (me->drawflag & ME_DRAWEDGES) { + int sel; + UI_GetThemeColor4fv(TH_EDGE_SELECT, col1); - immBegin(GWN_PRIM_LINE_LOOP, efa->len); + if (interpedges) { + /* Create a color buffer. */ + static Gwn_VertFormat format = {0}; + static uint shdr_col; + if (format.attrib_ct == 0) { + shdr_col = GWN_vertformat_attr_add(&format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); + } - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); - immAttrib4ubv(color, sel ? (GLubyte *)col1 : (GLubyte *)col2); + Gwn_VertBuf *vbo_col = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo_col, vbo_len_used); - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); - } + index = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; - immEnd(); + BM_ITER_ELEM(l, &liter, efa, BM_LOOPS_OF_FACE) { + sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + GWN_vertbuf_attr_set(vbo_col, shdr_col, index++, sel ? col1 : col2); } - - immUnbindProgram(); } - else { - immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + /* Reuse the UV buffer and add the color buffer. */ + GWN_batch_vertbuf_add_ex(uv_batch, vbo_col, true); - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - int lastsel = -1; + /* Now draw each face contour separately with another builtin program. */ + GWN_batch_program_set_builtin(uv_batch, GPU_SHADER_2D_SMOOTH_COLOR); + gpuBindMatrices(uv_batch->interface); - if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) - continue; - - immBegin(GWN_PRIM_LINES, efa->len * 2); - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - sel = uvedit_edge_select_test(scene, l, cd_loop_uv_offset); - if (sel != lastsel) { - immAttrib4ubv(color, sel ? (GLubyte *)col1 : (GLubyte *)col2); - lastsel = sel; - } - - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); - luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - immVertex2fv(pos, luv->uv); - } - - immEnd(); - } + GWN_batch_program_use_begin(uv_batch); + index = 0; + BM_ITER_MESH(efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; - immUnbindProgram(); + GWN_batch_draw_range_ex(uv_batch, index, efa->len, false); + index += efa->len; } + GWN_batch_program_use_end(uv_batch); } else { - pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + Gwn_VertFormat *format = immVertexFormat(); + pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4ubv(col2); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); - /* no nice edges */ + /* Use batch here to avoid problems with `IMM_BUFFER_SIZE`. */ + Gwn_Batch *flat_edges_batch = immBeginBatchAtMost(GWN_PRIM_LINES, vbo_len_used * 2); BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) continue; - - draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset, pos); + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + sel = uvedit_edge_select_test(scene, l, cd_loop_uv_offset); + immAttrib4fv(color, sel ? col1 : col2); + + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + immVertex2fv(pos, luv->uv); + luv = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + immVertex2fv(pos, luv->uv); + } } + immEnd(); + + GWN_batch_draw(flat_edges_batch); + GWN_vertbuf_discard(flat_edges_batch->verts[0]); + GWN_batch_discard(flat_edges_batch); immUnbindProgram(); } + } + else { + GWN_batch_uniform_4fv(uv_batch, "color", col2); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - break; + /* no nice edges */ + GWN_batch_program_use_begin(uv_batch); + index = 0; + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG)) + continue; + + GWN_batch_draw_range_ex(uv_batch, index, efa->len, false); + index += efa->len; + } + GWN_batch_program_use_end(uv_batch); + immUnbindProgram(); + } } + GWN_vertbuf_discard(uv_vbo); + GWN_batch_discard(uv_batch); + if (sima->flag & SI_SMOOTH_UV) { glDisable(GL_LINE_SMOOTH); glDisable(GL_BLEND); @@ -904,7 +943,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje Gwn_VertFormat *format = immVertexFormat(); pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + color = GWN_vertformat_attr_add(format, "color", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); @@ -922,8 +961,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { /* Only set color for the first face */ if (!col_set) { - UI_GetThemeColor3ubv(TH_WIRE, col1); - immAttrib3ubv(color, col1); + UI_GetThemeColor3fv(TH_WIRE, col1); + immAttrib3fv(color, col1); col_set = true; } @@ -944,8 +983,8 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, Obje if (uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { /* Only set color for the first face */ if (!col_set) { - UI_GetThemeColor3ubv(TH_FACE_DOT, col1); - immAttrib3ubv(color, col1); + UI_GetThemeColor3fv(TH_FACE_DOT, col1); + immAttrib3fv(color, col1); col_set = true; } diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 8f051327265c94962b81d8b0700282d72b2ed9dc..8ec9fe355120b90d06157ead1ee7c3637a976526 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -1723,13 +1723,13 @@ static void uv_weld_align(bContext *C, int tool) } /* now we have all verts, make into a line */ - if (BLI_array_count(eve_line) > 2) { + if (BLI_array_len(eve_line) > 2) { /* we know the returns from these must be valid */ const float *uv_start = uv_sel_co_from_eve( scene, obedit, ima, em, eve_line[0]); const float *uv_end = uv_sel_co_from_eve( - scene, obedit, ima, em, eve_line[BLI_array_count(eve_line) - 1]); + scene, obedit, ima, em, eve_line[BLI_array_len(eve_line) - 1]); /* For t & u modes */ float a = 0.0f; @@ -1747,7 +1747,7 @@ static void uv_weld_align(bContext *C, int tool) } /* go over all verts except for endpoints */ - for (i = 0; i < BLI_array_count(eve_line); i++) { + for (i = 0; i < BLI_array_len(eve_line); i++) { BM_ITER_ELEM (l, &liter, eve_line[i], BM_LOOPS_OF_VERT) { if (!uvedit_face_visible_test(scene, obedit, ima, l->f)) continue; @@ -1878,7 +1878,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) } } - for (uv_a_index = 0; uv_a_index < BLI_array_count(vert_arr); uv_a_index++) { + for (uv_a_index = 0; uv_a_index < BLI_array_len(vert_arr); uv_a_index++) { if (vert_arr[uv_a_index].weld == false) { float uv_min[2]; float uv_max[2]; @@ -1892,7 +1892,7 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) copy_v2_v2(uv_min, uv_a); vert_arr[uv_a_index].weld = true; - for (uv_b_index = uv_a_index + 1; uv_b_index < BLI_array_count(vert_arr); uv_b_index++) { + for (uv_b_index = uv_a_index + 1; uv_b_index < BLI_array_len(vert_arr); uv_b_index++) { uv_b = vert_arr[uv_b_index].uv_loop->uv; if ((vert_arr[uv_b_index].weld == false) && (len_manhattan_v2v2(uv_a, uv_b) < threshold)) @@ -1902,10 +1902,10 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) vert_arr[uv_b_index].weld = true; } } - if (BLI_array_count(loop_arr)) { + if (BLI_array_len(loop_arr)) { float uv_mid[2]; mid_v2_v2v2(uv_mid, uv_min, uv_max); - for (uv_b_index = 0; uv_b_index < BLI_array_count(loop_arr); uv_b_index++) { + for (uv_b_index = 0; uv_b_index < BLI_array_len(loop_arr); uv_b_index++) { copy_v2_v2(loop_arr[uv_b_index]->uv, uv_mid); } } @@ -1939,12 +1939,12 @@ static int uv_remove_doubles_exec(bContext *C, wmOperator *op) } } - for (uv_a_index = 0; uv_a_index < BLI_array_count(loop_arr); uv_a_index++) { + for (uv_a_index = 0; uv_a_index < BLI_array_len(loop_arr); uv_a_index++) { float dist_best = FLT_MAX, dist; const float *uv_best = NULL; uv_a = loop_arr[uv_a_index]->uv; - for (uv_b_index = 0; uv_b_index < BLI_array_count(loop_arr_unselected); uv_b_index++) { + for (uv_b_index = 0; uv_b_index < BLI_array_len(loop_arr_unselected); uv_b_index++) { uv_b = loop_arr_unselected[uv_b_index]->uv; dist = len_manhattan_v2v2(uv_a, uv_b); if ((dist < threshold) && (dist < dist_best)) { diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 486af0a8a74c0351b31c69e0afc92c024ff35bc4..0fde0edcf2bce6fe49a9b22dda2db3d51ea881ec 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -70,6 +70,7 @@ typedef enum GPUTextureFormat { GPU_RG16I, GPU_R32F, GPU_R16F, + GPU_R16I, GPU_RG8, GPU_R8, #if 0 @@ -88,7 +89,6 @@ typedef enum GPUTextureFormat { GPU_RG8UI, GPU_R32I, GPU_R32UI, - GPU_R16I, GPU_R16UI, GPU_R16, GPU_R8I, diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index b733027b0f33e73dee26703d838930746739c7c9..20d468459e6e4d277229eb058076a88f192ae587 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -83,7 +83,6 @@ typedef struct ViewportEngineData { /* Profiling data */ double init_time; - double cache_time; double render_time; double background_time; } ViewportEngineData; @@ -114,6 +113,9 @@ void *GPU_viewport_texture_list_get(GPUViewport *viewport); void GPU_viewport_size_get(const GPUViewport *viewport, int size[2]); void GPU_viewport_size_set(GPUViewport *viewport, const int size[2]); +/* Profiling */ +double *GPU_viewport_cache_time_get(GPUViewport *viewport); + void GPU_viewport_tag_update(GPUViewport *viewport); bool GPU_viewport_do_update(GPUViewport *viewport); diff --git a/source/blender/gpu/intern/gpu_batch_presets.c b/source/blender/gpu/intern/gpu_batch_presets.c index 950f1a2dab3c81678e48ab94f4583f6a11320263..696143a385787c79e93b077f626fecc529435220 100644 --- a/source/blender/gpu/intern/gpu_batch_presets.c +++ b/source/blender/gpu/intern/gpu_batch_presets.c @@ -51,7 +51,7 @@ static struct { struct { uint pos, nor; } attr_id; -} g_presets_3d = {0}; +} g_presets_3d = {{0}}; /* We may want 2D presets later. */ diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 651cbda00e82d05483dbdce46fa6a23d16c41a22..bd25dd03f133b888349a7e33ba3cc5470a52700b 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -136,7 +136,7 @@ static GLenum gpu_texture_get_format( *is_stencil = false; /* Integer formats */ - if (ELEM(data_type, GPU_RG16I)) { + if (ELEM(data_type, GPU_RG16I, GPU_R16I)) { *data_format = GL_INT; switch (components) { @@ -185,6 +185,7 @@ static GLenum gpu_texture_get_format( break; case GPU_DEPTH_COMPONENT16: case GPU_R16F: + case GPU_R16I: case GPU_RG8: *bytesize = 2; break; @@ -209,6 +210,7 @@ static GLenum gpu_texture_get_format( case GPU_RGBA8: return GL_RGBA8; case GPU_R32F: return GL_R32F; case GPU_R16F: return GL_R16F; + case GPU_R16I: return GL_R16I; case GPU_RG8: return GL_RG8; case GPU_R8: return GL_R8; /* Special formats texture & renderbuffer */ diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index 42dfe59389d6ab4e9a6f22646861653969973e7a..2ad89bd1345d5527c7caed916c9c1d7d194be987 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -87,6 +87,9 @@ struct GPUViewport { struct DRWInstanceDataList *idatalist; /* Used for rendering data structure. */ ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */ + + /* Profiling data */ + double cache_time; }; enum { @@ -153,15 +156,22 @@ GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs) */ void GPU_viewport_clear_from_offscreen(GPUViewport *viewport) { - if (viewport->fbl->multisample_fb) { - viewport->fbl->multisample_fb = NULL; - viewport->txl->multisample_color = NULL; - viewport->txl->multisample_depth = NULL; + DefaultFramebufferList *dfbl = viewport->fbl; + DefaultTextureList *dtxl = viewport->txl; + + if (dfbl->multisample_fb) { + /* GPUViewport expect the final result to be in default_fb but + * GPUOffscreen wants it in its multisample_fb, so we sync it back. */ + GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, false, false); + GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, true, false); + dfbl->multisample_fb = NULL; + dtxl->multisample_color = NULL; + dtxl->multisample_depth = NULL; } else { viewport->fbl->default_fb = NULL; - viewport->txl->color = NULL; - viewport->txl->depth = NULL; + dtxl->color = NULL; + dtxl->depth = NULL; } } @@ -268,6 +278,11 @@ void GPU_viewport_size_set(GPUViewport *viewport, const int size[2]) viewport->size[1] = size[1]; } +double *GPU_viewport_cache_time_get(GPUViewport *viewport) +{ + return &viewport->cache_time; +} + /** * Try to find a texture coresponding to params into the texture pool. * If no texture was found, create one and add it to the pool. diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index 5e3cbeaa0571441bfdbef1fd5867fcfaf2371e27..1058099e9ef7fb9c970b1ca4a4c14279279ebaa4 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -1278,6 +1278,13 @@ typedef enum eRNAOverrideMatchResult { RNA_OVERRIDE_MATCH_RESULT_RESTORED = 1 << 1, } eRNAOverrideMatchResult; +typedef enum eRNAOverrideStatus { + RNA_OVERRIDE_STATUS_OVERRIDABLE = 1 << 0, /* The property is overridable. */ + RNA_OVERRIDE_STATUS_OVERRIDDEN = 1 << 1, /* The property is overridden. */ + RNA_OVERRIDE_STATUS_MANDATORY = 1 << 2, /* Overriding this property is mandatory when creating an override. */ + RNA_OVERRIDE_STATUS_LOCKED = 1 << 3, /* The override status of this property is locked. */ +} eRNAOverrideStatus; + bool RNA_struct_override_matches( struct PointerRNA *ptr_local, struct PointerRNA *ptr_reference, const char *root_path, struct IDOverrideStatic *override, const eRNAOverrideMatch flags, @@ -1300,9 +1307,7 @@ struct IDOverrideStaticPropertyOperation *RNA_property_override_property_operati PointerRNA *ptr, PropertyRNA *prop, const short operation, const int index, const bool strict, bool *r_strict, bool *r_created); -void RNA_property_override_status( - PointerRNA *ptr, PropertyRNA *prop, const int index, - bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked); +eRNAOverrideStatus RNA_property_override_status(PointerRNA *ptr, PropertyRNA *prop, const int index); void RNA_struct_state_owner_set(const char *name); const char *RNA_struct_state_owner_get(void); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 0f47a461cdaff40974fb728fbfc2f03bd6cc6c8b..b63cebbdde247ae69a60557bf00422fed2b1894f 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -451,8 +451,9 @@ static void *rna_idproperty_check_ex(PropertyRNA **prop, PointerRNA *ptr, const return idprop; } - else + else { return return_rnaprop ? *prop : NULL; + } } { @@ -7149,10 +7150,13 @@ bool RNA_struct_equals(PointerRNA *ptr_a, PointerRNA *ptr_b, eRNACompareMode mod * When \a prop is given, \a prop_a and \a prop_b should always be NULL, and vice-versa. * This is necessary, because we cannot perform 'set/unset' checks on resolved properties * (unset IDProps would merely be NULL then). + * + * \note When there is no equality, but we cannot determine an order (greater than/lesser than), we return 1. */ static int rna_property_override_diff( - PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, PropertyRNA *prop_a, PropertyRNA *prop_b, const char *rna_path, - eRNACompareMode mode, IDOverrideStatic *override, const int flags, eRNAOverrideMatchResult *r_report_flags) + PointerRNA *ptr_a, PointerRNA *ptr_b, PropertyRNA *prop, PropertyRNA *prop_a, PropertyRNA *prop_b, + const char *rna_path, eRNACompareMode mode, + IDOverrideStatic *override, const int flags, eRNAOverrideMatchResult *r_report_flags) { if (prop != NULL) { BLI_assert(prop_a == NULL && prop_b == NULL); @@ -7678,29 +7682,30 @@ IDOverrideStaticPropertyOperation *RNA_property_override_property_operation_get( return BKE_override_static_property_operation_get(op, operation, NULL, NULL, index, index, strict, r_strict, r_created); } -void RNA_property_override_status( - PointerRNA *ptr, PropertyRNA *prop, const int index, - bool *r_overridable, bool *r_overridden, bool *r_mandatory, bool *r_locked) +eRNAOverrideStatus RNA_property_override_status(PointerRNA *ptr, PropertyRNA *prop, const int index) { -#define SET_RET(_name, _val) if (_name != NULL) *_name = (_val) - - SET_RET(r_overridable, false); - SET_RET(r_overridden, false); - SET_RET(r_mandatory, false); - SET_RET(r_locked, false); + int override_status = 0; if (!ptr || !prop || !ptr->id.data || !((ID *)ptr->id.data)->override_static) { - return; + return override_status; } - SET_RET(r_overridable, (prop->flag & PROP_OVERRIDABLE_STATIC) && (prop->flag & PROP_EDITABLE)); + if ((prop->flag & PROP_OVERRIDABLE_STATIC) && (prop->flag & PROP_EDITABLE)) { + override_status |= RNA_OVERRIDE_STATUS_OVERRIDABLE; + } - if (r_overridden || r_mandatory || r_locked) { - IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_find(ptr, prop, index, false, NULL); - SET_RET(r_overridden, opop != NULL); - SET_RET(r_mandatory, (opop->flag & IDOVERRIDESTATIC_FLAG_MANDATORY) != 0); - SET_RET(r_locked, (opop->flag & IDOVERRIDESTATIC_FLAG_LOCKED) != 0); + IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_find(ptr, prop, index, false, NULL); + if (opop != NULL) { + override_status |= RNA_OVERRIDE_STATUS_OVERRIDDEN; + if (opop->flag & IDOVERRIDESTATIC_FLAG_MANDATORY) { + override_status |= RNA_OVERRIDE_STATUS_MANDATORY; + } + if (opop->flag & IDOVERRIDESTATIC_FLAG_LOCKED) { + override_status |= RNA_OVERRIDE_STATUS_LOCKED; + } } + + return override_status; } diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index aa37c9ffa88c4e0e7a96db49494a718a51cbd3f3..ca8abdc8b48bbca80c3a49bcb87f230e13209cdd 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -441,7 +441,6 @@ static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi br->id.icon_id = 0; if (br->flag & BRUSH_CUSTOM_ICON) { - BKE_previewimg_id_ensure(&br->id); BKE_icon_changed(BKE_icon_id_ensure(&br->id)); } diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c index b973e0f27ee6f3fadab1007765a69c4b5b4ed578..466a01a72712e2818da109b2ab423c85e851c51c 100644 --- a/source/blender/makesrna/intern/rna_dynamicpaint.c +++ b/source/blender/makesrna/intern/rna_dynamicpaint.c @@ -723,11 +723,11 @@ static void rna_def_canvas_surface(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flags", MOD_DPAINT_WAVE_OPEN_BORDERS); RNA_def_property_ui_text(prop, "Open Borders", "Pass waves through mesh edges"); - /* cache */ prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "pointcache"); + RNA_def_property_struct_type(prop, "PointCache"); RNA_def_property_ui_text(prop, "Point Cache", ""); /* is cache used */ diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 4a89ca001ac0bfc1ebb0c45100234f7ebdc8985c..649cb523e92bde94ae79c1ee4258f3f94d745b29 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -772,31 +772,8 @@ static const EnumPropertyItem *rna_Effector_shape_itemf(bContext *UNUSED(C), Poi #else -/* ptcache.point_caches */ -static void rna_def_ptcache_point_caches(BlenderRNA *brna, PropertyRNA *cprop) +static void rna_def_pointcache_common(StructRNA *srna) { - StructRNA *srna; - PropertyRNA *prop; - - /* FunctionRNA *func; */ - /* PropertyRNA *parm; */ - - RNA_def_property_srna(cprop, "PointCaches"); - srna = RNA_def_struct(brna, "PointCaches", NULL); - RNA_def_struct_sdna(srna, "PointCache"); - RNA_def_struct_ui_text(srna, "Point Caches", "Collection of point caches"); - - prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_funcs(prop, "rna_Cache_active_point_cache_index_get", - "rna_Cache_active_point_cache_index_set", - "rna_Cache_active_point_cache_index_range"); - RNA_def_property_ui_text(prop, "Active Point Cache Index", ""); - RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_change"); -} - -static void rna_def_pointcache(BlenderRNA *brna) -{ - StructRNA *srna; PropertyRNA *prop; static const EnumPropertyItem point_cache_compress_items[] = { @@ -806,16 +783,12 @@ static void rna_def_pointcache(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; - srna = RNA_def_struct(brna, "PointCache", NULL); - RNA_def_struct_ui_text(srna, "Point Cache", "Point cache for physics simulations"); - RNA_def_struct_ui_icon(srna, ICON_PHYSICS); - prop = RNA_def_property(srna, "frame_start", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "startframe"); RNA_def_property_range(prop, -MAXFRAME, MAXFRAME); RNA_def_property_ui_range(prop, 1, MAXFRAME, 1, 1); RNA_def_property_ui_text(prop, "Start", "Frame on which the simulation starts"); - + prop = RNA_def_property(srna, "frame_end", PROP_INT, PROP_TIME); RNA_def_property_int_sdna(prop, NULL, "endframe"); RNA_def_property_range(prop, 1, MAXFRAME); @@ -896,13 +869,59 @@ static void rna_def_pointcache(BlenderRNA *brna) "Use this file's path for the disk cache when library linked into another file " "(for local bakes per scene file, disable this option)"); RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_idname_change"); +} + +static void rna_def_ptcache_point_caches(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* FunctionRNA *func; */ + /* PropertyRNA *parm; */ + + RNA_def_property_srna(cprop, "PointCaches"); + srna = RNA_def_struct(brna, "PointCaches", NULL); + RNA_def_struct_sdna(srna, "PointCache"); + RNA_def_struct_ui_text(srna, "Point Caches", "Collection of point caches"); + + prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED); + RNA_def_property_int_funcs(prop, "rna_Cache_active_point_cache_index_get", + "rna_Cache_active_point_cache_index_set", + "rna_Cache_active_point_cache_index_range"); + RNA_def_property_ui_text(prop, "Active Point Cache Index", ""); + RNA_def_property_update(prop, NC_OBJECT, "rna_Cache_change"); + + /* And define another RNA type for those collection items. */ + srna = RNA_def_struct(brna, "PointCacheItem", NULL); + RNA_def_struct_sdna(srna, "PointCache"); + RNA_def_struct_ui_text(srna, "Point Cache", "point cache for physics simulations"); + RNA_def_struct_ui_icon(srna, ICON_PHYSICS); + + rna_def_pointcache_common(srna); +} + +static void rna_def_pointcache_active(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "PointCache", NULL); + RNA_def_struct_ui_text(srna, "Active Point Cache", "Active point cache for physics simulations"); + RNA_def_struct_ui_icon(srna, ICON_PHYSICS); + + rna_def_pointcache_common(srna); + /* This first-level RNA pointer also has list of all caches from owning ID. + * Those caches items have exact same content as 'active' one, except for that collection, + * to prevent ugly recursive layout pattern. + * Note: This shall probably be redone from scratch in a proper way at some poitn, but for now that will do, + * and shall not break anything in the API. */ prop = RNA_def_property(srna, "point_caches", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_funcs(prop, "rna_Cache_list_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", NULL, NULL, NULL, NULL); - RNA_def_property_struct_type(prop, "PointCache"); - RNA_def_property_ui_text(prop, "Point Cache List", "Point cache list"); + RNA_def_property_struct_type(prop, "PointCacheItem"); + RNA_def_property_ui_text(prop, "Point Cache List", ""); rna_def_ptcache_point_caches(brna, prop); } @@ -1882,7 +1901,7 @@ static void rna_def_softbody(BlenderRNA *brna) void RNA_def_object_force(BlenderRNA *brna) { - rna_def_pointcache(brna); + rna_def_pointcache_active(brna); rna_def_collision(brna); rna_def_effector_weight(brna); rna_def_field(brna); diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index bc85e9c650311efd071abf8c085fb212879e919c..ae325651a318c2ddf78b056aca3d70bf61580dbc 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -802,6 +802,7 @@ static void rna_def_rigidbody_world(BlenderRNA *brna) prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "pointcache"); + RNA_def_property_struct_type(prop, "PointCache"); RNA_def_property_ui_text(prop, "Point Cache", ""); /* effector weights */ diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 8cf9bc7d39c49d6ef00acb73b0d0f80e0bd7abc5..9c043c3563a75574cee9be64f98be78ac680b64c 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -1458,6 +1458,10 @@ int rna_property_override_diff_default(PointerRNA *ptr_a, PointerRNA *ptr_b, if (propname != NULL) { propname_a = RNA_property_string_get_alloc(&iter_a.ptr, propname, propname_buff_a, sizeof(propname_buff_a), NULL); propname_b = RNA_property_string_get_alloc(&iter_b.ptr, propname, propname_buff_b, sizeof(propname_buff_b), NULL); + } + /* There may be a propname defined in some cases, while no actual name set + * (e.g. happens with point cache), in that case too we want to fall back to index. */ + if ((propname_a != NULL && propname_a[0] != '\0') || (propname_b != NULL && propname_b[0] != '\0')) { if (!STREQ(propname_a, propname_b)) { /* Same as above, not same structs. */ equals = false; diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c index a49c71fc54b8c9f33d848893dd7dec9f93a2cd0b..8fe97885f497f17066dcfd1e778505030e137166 100644 --- a/source/blender/makesrna/intern/rna_smoke.c +++ b/source/blender/makesrna/intern/rna_smoke.c @@ -624,6 +624,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); RNA_def_property_pointer_sdna(prop, NULL, "point_cache[0]"); + RNA_def_property_struct_type(prop, "PointCache"); RNA_def_property_ui_text(prop, "Point Cache", ""); prop = RNA_def_property(srna, "point_cache_compress_type", PROP_ENUM, PROP_NONE); diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index d2d8da289b745ac84292cf3e5668189ddc6c228f..4afe6ca33e235a7d81972742672c54010e5bbaa6 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -1304,9 +1304,9 @@ static void skin_fix_hole_no_good_verts(BMesh *bm, Frame *frame, BMFace *split_f else if (split_face->len > 4) { /* Maintain a dynamic vert array containing the split_face's * vertices, avoids frequent allocs in collapse_face_corners() */ - if (BLI_array_count(vert_buf) < split_face->len) { + if (BLI_array_len(vert_buf) < split_face->len) { BLI_array_grow_items(vert_buf, (split_face->len - - BLI_array_count(vert_buf))); + BLI_array_len(vert_buf))); } /* Get split face's verts */ diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index ec77dc07ba701d8d48400d8d68b212554a853491..1e2ce3727272f68561781e45d3567466982d6aba 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -361,6 +361,7 @@ static PyGetSetDef bpy_app_getsets[] = { {(char *)"debug_depsgraph_eval", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_EVAL}, {(char *)"debug_depsgraph_tag", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_TAG}, {(char *)"debug_depsgraph_time", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_TIME}, + {(char *)"debug_depsgraph_pretty", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_DEPSGRAPH_PRETTY}, {(char *)"debug_simdata", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_SIMDATA}, {(char *)"debug_gpumem", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_GPU_MEM}, diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c index 924e46a8c000410bbc5a377cc0906b3924f83c1c..cc6a536789569d1aabadeedb8a87561ad040c9f8 100644 --- a/source/blender/python/mathutils/mathutils_Matrix.c +++ b/source/blender/python/mathutils/mathutils_Matrix.c @@ -1710,10 +1710,18 @@ static PyObject *Matrix_lerp(MatrixObject *self, PyObject *args) /* TODO, different sized matrix */ if (self->num_col == 4 && self->num_row == 4) { +#ifdef MATH_STANDALONE + blend_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac); +#else interp_m4_m4m4((float (*)[4])mat, (float (*)[4])self->matrix, (float (*)[4])mat2->matrix, fac); +#endif } else if (self->num_col == 3 && self->num_row == 3) { +#ifdef MATH_STANDALONE + blend_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac); +#else interp_m3_m3m3((float (*)[3])mat, (float (*)[3])self->matrix, (float (*)[3])mat2->matrix, fac); +#endif } else { PyErr_SetString(PyExc_ValueError, diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index 822993a2372dd4af55b782d5fa7b1aa74ebec69f..93ac53cdfcc676a3c77a4219c9c26bdf81f129ad 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -238,6 +238,8 @@ void RE_render_result_rect_from_ibuf( struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name); float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, const char *name, const char *viewname); +bool RE_HasSingleLayer(struct Render *re); + /* add passes for grease pencil */ struct RenderPass *RE_create_gp_pass(struct RenderResult *rr, const char *layername, const char *viewname); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index 33c633c76bc40328dd7a0f20c811b2bf1466dc3d..170cd0ad41997984561bb9d947752e10135d83e9 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -261,6 +261,11 @@ RenderLayer *RE_GetRenderLayer(RenderResult *rr, const char *name) } } +bool RE_HasSingleLayer(Render *re) +{ + return (re->r.scemode & R_SINGLE_LAYER); +} + RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty) { return render_result_new_from_exr(exrhandle, colorspace, predivide, rectx, recty); @@ -268,12 +273,19 @@ RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool RenderLayer *render_get_active_layer(Render *re, RenderResult *rr) { - RenderLayer *rl = BLI_findlink(&rr->layers, re->active_view_layer); - - if (rl) - return rl; - else - return rr->layers.first; + ViewLayer *view_layer = BLI_findlink(&re->view_layers, re->active_view_layer); + + if (view_layer) { + RenderLayer *rl = BLI_findstring(&rr->layers, + view_layer->name, + offsetof(RenderLayer, name)); + + if (rl) { + return rl; + } + } + + return rr->layers.first; } static int UNUSED_FUNCTION(render_scene_needs_vector)(Render *re) diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index b6317a1f0e2cfd2599c13dc77d7aec38a01d98ee..2ecbad81a94305fee3d652367190c4dc04feb871 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1814,7 +1814,7 @@ static int wm_operator_tool_set_exec(bContext *C, wmOperator *op) { ScrArea *sa = CTX_wm_area(C); - bToolDef tool_def = {0}; + bToolDef tool_def = {{0}}; tool_def.index = RNA_int_get(op->ptr, "index"); tool_def.spacetype = sa->spacetype; diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 5ca3488074316429359b85aa689156e933fbba5c..f34b5bf9c9500ffbd209e683ddad231bcec960e7 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -69,8 +69,6 @@ void wmPartialViewport(rcti *drawrct, const rcti *winrct, const rcti *partialrct scissor_pad = false; } - int x = drawrct->xmin; - int y = drawrct->ymin; int width = BLI_rcti_size_x(winrct) + 1; int height = BLI_rcti_size_y(winrct) + 1; @@ -85,8 +83,8 @@ void wmPartialViewport(rcti *drawrct, const rcti *winrct, const rcti *partialrct scissor_height += 1; } - glViewport(x, y, width, height); - glScissor(x, y, scissor_width, scissor_height); + glViewport(winrct->xmin, winrct->ymin, width, height); + glScissor(drawrct->xmin, drawrct->ymin, scissor_width, scissor_height); wmOrtho2_pixelspace(width, height); gpuLoadIdentity(); diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c index dba38dc8c8cb09512b8301eed261d687893f9413..06a9c2de69b122fc2f17d65b0a8b223222f5f5df 100644 --- a/source/blender/windowmanager/message_bus/intern/wm_message_bus.c +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus.c @@ -40,7 +40,7 @@ /** \name Public API * \{ */ -static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM] = {NULL}; +static wmMsgTypeInfo wm_msg_types[WM_MSG_TYPE_NUM] = {{{NULL}}}; typedef void (*wmMsgTypeInitFn)(wmMsgTypeInfo *); diff --git a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c index 03177d9ac6a418fb177ee30a534a9895d385a77d..c9b43cc2a91d504e1c39d92ad57b2b49e5a647d4 100644 --- a/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c +++ b/source/blender/windowmanager/message_bus/intern/wm_message_bus_rna.c @@ -300,14 +300,14 @@ void WM_msg_subscribe_ID( struct wmMsgBus *mbus, ID *id, const wmMsgSubscribeValue *msg_val_params, const char *id_repr) { - wmMsgParams_RNA msg_key_params = {NULL}; + wmMsgParams_RNA msg_key_params = {{{NULL}}}; RNA_id_pointer_create(id, &msg_key_params.ptr); WM_msg_subscribe_rna_params(mbus, &msg_key_params, msg_val_params, id_repr); } void WM_msg_publish_ID(struct wmMsgBus *mbus, ID *id) { - wmMsgParams_RNA msg_key_params = {NULL}; + wmMsgParams_RNA msg_key_params = {{{NULL}}}; RNA_id_pointer_create(id, &msg_key_params.ptr); WM_msg_publish_rna_params(mbus, &msg_key_params); } diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index f5ec13fc0dfe077f37349647fc0a85a952adff0e..df4946a817576dc5164ffcdeaa1e13d74a24ffe0 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -759,6 +759,8 @@ static const char arg_handle_debug_mode_generic_set_doc_depsgraph_eval[] = "\n\tEnable debug messages from dependency graph related on evaluation."; static const char arg_handle_debug_mode_generic_set_doc_depsgraph_no_threads[] = "\n\tSwitch dependency graph to a single threaded evaluation."; +static const char arg_handle_debug_mode_generic_set_doc_depsgraph_pretty[] = +"\n\tEnable colors for dependency graph debug messages."; static const char arg_handle_debug_mode_generic_set_doc_gpumem[] = "\n\tEnable GPU memory stats in status bar."; @@ -1854,6 +1856,8 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle) CB_EX(arg_handle_debug_mode_generic_set, depsgraph_time), (void *)G_DEBUG_DEPSGRAPH_TIME); BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-no-threads", CB_EX(arg_handle_debug_mode_generic_set, depsgraph_no_threads), (void *)G_DEBUG_DEPSGRAPH_NO_THREADS); + BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph-pretty", + CB_EX(arg_handle_debug_mode_generic_set, depsgraph_pretty), (void *)G_DEBUG_DEPSGRAPH_PRETTY); BLI_argsAdd(ba, 1, NULL, "--debug-gpumem", CB_EX(arg_handle_debug_mode_generic_set, gpumem), (void *)G_DEBUG_GPU_MEM); BLI_argsAdd(ba, 1, NULL, "--debug-gpu-shaders", diff --git a/tests/python/view_layer/CMakeLists.txt b/tests/python/view_layer/CMakeLists.txt index 77a56fb47f9f95308068ffe44a69099a3833375c..9cb33420ac51b3e7874c5f3916fd4750932069b6 100644 --- a/tests/python/view_layer/CMakeLists.txt +++ b/tests/python/view_layer/CMakeLists.txt @@ -108,6 +108,7 @@ VIEW_LAYER_TEST(object_link_a) VIEW_LAYER_TEST(object_link_b) VIEW_LAYER_TEST(object_link_c) VIEW_LAYER_TEST(operator_context) +VIEW_LAYER_TEST(make_single_user) VIEW_LAYER_TEST(move_above_below_scene_collection_a) VIEW_LAYER_TEST(move_above_below_scene_collection_b) VIEW_LAYER_TEST(move_above_below_scene_collection_c) diff --git a/tests/python/view_layer/test_make_single_user.py b/tests/python/view_layer/test_make_single_user.py new file mode 100644 index 0000000000000000000000000000000000000000..2a8a479bab26371b8a644b3c04d8ababe3d811ba --- /dev/null +++ b/tests/python/view_layer/test_make_single_user.py @@ -0,0 +1,54 @@ +# ############################################################ +# Importing - Same For All Render Layer Tests +# ############################################################ + +import unittest +import os +import sys + +from view_layer_common import * + + +# ############################################################ +# Testing +# ############################################################ + +class UnitTesting(ViewLayerTesting): + def test_make_single_user(self): + """ + Really basic test, just to check for crashes on basic files. + """ + import bpy + scene = bpy.context.scene + master_collection = scene.master_collection + view_layer = bpy.context.view_layer + ob = bpy.context.object + + # clean up the scene a bit + for o in (o for o in view_layer.objects if o != ob): + view_layer.collections[0].collection.objects.unlink(o) + + for v in (v for v in scene.view_layers if v != view_layer): + scene.view_layers.remove(v) + + while master_collection.collections: + master_collection.collections.remove( + master_collection.collections[0]) + + view_layer.collections.link(master_collection) + ob.select_set('SELECT') + + # update depsgraph + scene.update() + + # test itself + bpy.ops.object.make_single_user(object=True) + + +# ############################################################ +# Main - Same For All Render Layer Tests +# ############################################################ + +if __name__ == '__main__': + UnitTesting._extra_arguments = setup_extra_arguments(__file__) + unittest.main()